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 + -
显示快捷键?