cy7c67200_300_hcd_simple.c
来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 2,186 行 · 第 1/5 页
C
2,186 行
/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------* * simple generic USB HCD frontend Version 0.9.5 (10/28/2001) * for embedded HCs (CY7C67200/300) * * USB URB handling, hci_ hcs_ * URB queueing, qu_ * Transfer scheduling, sh_ * * *-------------------------------------------------------------------------* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *-------------------------------------------------------------------------*/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/list.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/arch/irq.h>#include <linux/usb.h>#include "67300.h"#include "cy7c67200_300_common.h"#include "cy7c67200_300_lcd.h"#include "lcp_cmd.h"#include "lcp_data.h"#include "cy7c67200_300_otg.h"#include "cy7c67200_300_hcd.h"#include "cy7c67200_300_hcd_simple.h"#include "cy7c67200_300_debug.h"/* maximum bandwidth in the one millisecond frame in terms of bits ?bytes? *///#define MAX_FRAME_BW 700//#define MAX_FRAME_BW 2048//#define MAX_FRAME_BW 6144//#define MAX_FRAME_BW 5600#define MAX_FRAME_BW 4096#define MAX_PERIODIC_BW 630//#define MAX_PERIODIC_BW 1260#define SETUP_STAGE 0#define DATA_STAGE 1#define STATUS_STAGE 2/* main lock for urb access */static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED; /* lock for clear the urb frame list *//* static spinlock_t urb_frame_lock = SPIN_LOCK_UNLOCKED; */static int iso_urb_cnt=0;static const int usb_bandwidth_option = 1;/* forward declarations */int sie_check_bandwidth (hci_t *hci, int sie_num, struct usb_device *dev, struct urb *urb);void sie_claim_bandwidth (hci_t * hci, int sie_num, struct usb_device *dev, struct urb *urb, int bustime, int isoc);void sie_release_bandwidth(hci_t *hci, int sie_num, struct usb_device *dev, struct urb *urb, int isoc);static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount);/* External */extern int fillTd(hci_t * hci, td_t * td, __u16 * td_addr, __u16 * buf_addr, __u8 devaddr, __u8 epaddr, int pid, int len, int toggle, int slow, int tt, int port_num);extern int urb_debug;extern int hc_otg_offer_hnp(struct usb_device * dev);extern int hc_otg_end_session (struct usb_device * dev);/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /* URB HCD API function layer * * * */int get_port_num_from_urb(cy_priv_t * cy_priv, urb_t * urb){ hci_t * hci = cy_priv->hci; int i; if (hci == NULL) { cy_err("get_port_num_from_urb: hci == NULL\n"); return ERROR; } for (i = 0; i < MAX_NUM_PORT; i++) { /* Find the right bus port device number */ if (hci->valid_host_port[i] == 1) { if (urb->dev->bus->busnum == hci->port[i].bus->busnum) { return (i); } } } cy_err("get_port_num_from_urb: can't find valid port num\n"); return ERROR;}static int get_port_num_from_dev(cy_priv_t * cy_priv, struct usb_device * usb_dev){ hci_t * hci = cy_priv->hci; int i; if (hci == NULL) return ERROR; for (i = 0; i < MAX_NUM_PORT; i++) { /* Find the right bus port device number */ if (hci->valid_host_port[i] == 1) { if (usb_dev->bus->busnum == hci->port[i].bus->busnum) { return (i); } } } return ERROR;}/*************************************************************************** * Function Name : hcs_urb_queue * * This function initializes the urb status and length before queueing the * urb. * * Input: hci = data structure for the host controller * urb = USB request block data structure * * Return: 0 **************************************************************************/static inline int hcs_urb_queue (cy_priv_t * cy_priv, urb_t * urb, int port){ int i; hci_t * hci = cy_priv->hci; int bustime = 0; cy_dbg("enter hcs_urb_queue\n"); if (usb_pipeisoc (urb->pipe)) { cy_dbg("hcs_urb_queue: isoc pipe\n"); for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; } /* urb->next hack : 1 .. resub, 0 .. single shot */ urb->interval = urb->next ? 1 : 0; } /* allocate and claim bandwidth if needed; ISO * needs start frame index if it was't provided. */ switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: case PIPE_INTERRUPT: if (urb->bandwidth == 0) { bustime = usb_check_bandwidth (urb->dev, urb); } if (bustime < 0) { usb_dec_dev_use (urb->dev); return bustime; } usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); } urb->status = USB_ST_URB_PENDING; urb->actual_length = 0; urb->error_count = 0; if (usb_pipecontrol (urb->pipe)) { urb->interval = 0; hc_flush_data_cache (hci, urb->setup_packet, 8); } if (usb_pipeout (urb->pipe)) { hc_flush_data_cache (hci, urb->transfer_buffer, urb->transfer_buffer_length); } qu_queue_urb (cy_priv, urb, port); return 0;}/*************************************************************************** * Function Name : hcs_return_urb * * This function the return path of URB back to the USB core. It calls the * the urb complete function if exist, and also handles the resubmition of * interrupt URBs. * * Input: hci = data structure for the host controller * urb = USB request block data structure * resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit * * Return: 0 **************************************************************************/static int hcs_return_urb (cy_priv_t * cy_priv, urb_t * urb, int port_num, int resub_ok){ struct usb_device * dev = urb->dev; int resubmit = 0; HWTrace(0x70); if (urb == NULL) { cy_err("hcs_return_urb: urb == NULL\n"); HWTrace(0x71); } cy_dbg("enter hcs_return_urb, urb pointer = 0x%x, " "transferbuffer point = 0x%x, next pointer = 0x%x," " setup packet pointer = 0x%x, context pointer = 0x%x \n", (__u32 *) urb, (__u32 *) urb->transfer_buffer, (__u32 *) urb->next, (__u32 *) urb->setup_packet, (__u32 *) urb->context); if (urb_debug) urb_print (urb, "RET", usb_pipeout (urb->pipe)); resubmit = urb->interval && resub_ok; switch (usb_pipetype (urb->pipe)) { case PIPE_INTERRUPT: HWTrace(0x72); /* Release int bandwidth */ if (urb->bandwidth) { usb_release_bandwidth (urb->dev, urb, 0); } urb->dev = urb->hcpriv = NULL; if (urb->complete) { urb->complete (urb); } if (resubmit) { /* requeue the URB */ urb->dev = dev; hcs_urb_queue (cy_priv, urb, port_num); } break; case PIPE_ISOCHRONOUS: case PIPE_BULK: case PIPE_CONTROL: /* unlink URB, call complete */ HWTrace(0x73); /* Release iso bandwidth */ if ((urb->bandwidth) && (usb_pipetype (urb->pipe) == PIPE_ISOCHRONOUS)) { usb_release_bandwidth (urb->dev, urb, 1); } if (urb->complete) { urb->complete (urb); /* call complete */ if (usb_pipeisoc(urb->pipe)) { HWTrace(0x8); iso_urb_cnt--; } } break; } return 0;}/*************************************************************************** * Function Name : hci_submit_urb * * This function is called by the USB core API when an URB is available to * process. This function does the following * * 1) Check the validity of the URB * 2) Parse the device number from the URB * 3) Pass the URB to the root hub routine if its intended for the hub, else * queue the urb for the attached device. * * Input: urb = USB request block data structure * * Return: 0 if success or error code **************************************************************************/static int hci_submit_urb (urb_t * urb){ hci_t * hci; cy_priv_t * cy_priv; unsigned int pipe = urb->pipe; unsigned long int_flags; int ret = -1; int i; HWTrace (0x4000); cy_dbg("enter hci_submit_urb, pipe = 0x%x, dev = 0x%x, bus = 0x%x\n", urb->pipe, urb->dev, urb->dev->bus); if (!urb->dev || !urb->dev->bus || urb->hcpriv) { cy_err("hci_submit_urb: urb->dev = 0x%x, urb->dev->bus = 0x%x, urb->hcpriv = 0x%x\n", (int) urb->dev, (int) urb->dev->bus, (int) urb->hcpriv); return -EINVAL; } if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) { cy_err("hci_submit_urb: endpoint_halted\n"); return -EPIPE; } cy_priv = (cy_priv_t *) urb->dev->bus->hcpriv; hci = cy_priv->hci; if (cy_priv == NULL || hci == NULL || urb == NULL) { HWTrace (0x4001); cy_err("hci_submit_urb: Error, cy_priv = 0x%x, hci = 0x%x, urb = 0x%x! \n", (int) cy_priv, (int) hci, (int) urb); return -EINVAL; } /* a request to the virtual root hub */ for (i = 0; i < MAX_NUM_PORT; i++) { /* Find the right bus port device number */ if (hci->valid_host_port[i] == 1) { if (urb->dev->bus->busnum != hci->port[i].bus->busnum) { HWTrace (0x4003); cy_dbg("sumbit urb: busnum = 0x%x, port %d s/b 0x%x\n", urb->dev->bus->busnum, i, hci->port[i].bus->busnum); continue; } /* Is the bus being disable? */ if (usb_pipedevice (pipe) == hci->port[i].rh.devnum) { if (urb_debug > 1) urb_print (urb, "SUB-RH", usb_pipein (pipe)); HWTrace (0x4004); return rh_submit_urb (urb, i); } /* queue the URB to its endpoint-queue */ if (usb_pipeisoc(urb->pipe)) { iso_urb_cnt++; HWTrace (0x4005); } spin_lock_irqsave (&usb_urb_lock, int_flags); ret = hcs_urb_queue (cy_priv, urb, i); if (ret != 0) { HWTrace (0x4006); /* error on return */ cy_err("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n", ret, urb->status); } HWTrace (0x4024); spin_unlock_irqrestore (&usb_urb_lock, int_flags); } } HWTrace (0x4008); return ret;}/*************************************************************************** * Function Name : hci_unlink_urb * * This function mark the URB to unlink * * Input: urb = USB request block data structure * * Return: 0 if success or error code **************************************************************************/static int hci_unlink_urb (urb_t * urb){ unsigned long int_flags; hci_t * hci; struct hci_device * hci_dev; DECLARE_WAITQUEUE (wait, current); void * comp = NULL; int i = 0; int port_num = -1; cy_priv_t * cy_priv = NULL; epd_t * ed = NULL; cy_dbg("enter hci_unlink_urb\n"); HWTrace (0xC0); if (!urb) /* just to be sure */ return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; cy_priv = (cy_priv_t * ) urb->dev->bus->hcpriv;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?