cy7c67200_300_hcd.c

来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 2,356 行 · 第 1/4 页

C
2,356
字号
 * Input:  cy_priv = data structure for the controller * * Return value  : 0  *                 *****************************************************************/static int __devinit hc_init_port (cy_priv_t * cy_priv, int port_num){	hci_t * hci = cy_priv->hci;    hcipriv_t * hp = &hci->port[port_num];    portstat_t * ps;    struct usb_bus * bus;    	cy_dbg("port_num = 0x%x", port_num);    /* set the initial port structure to zero */	memset (hp, 0, sizeof(hcipriv_t));	/* setup root hub port status */    HWTrace(0xBEF7);    ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);    if (!ps)	{	    return ERROR;	}		ps->portStatus = PORT_STAT_DEFAULT;    ps->portChange = PORT_CHANGE_DEFAULT;	HWTrace(0x6018);    hp->RHportStatus = ps;    hp->frame_number = 0;	hp->host_disabled = 1;    INIT_LIST_HEAD (&hp->ctrl_list);    INIT_LIST_HEAD (&hp->bulk_list);    INIT_LIST_HEAD (&hp->iso_list);    INIT_LIST_HEAD (&hp->intr_list);    INIT_LIST_HEAD (&hp->del_list);    INIT_LIST_HEAD (&hp->frame_urb_list);    bus = usb_alloc_bus (&hci_device_operations);    if (!bus)     {		cy_err("unable to alloc bus");	    kfree (hci);        return ERROR;    }    hp->bus = bus;    bus->hcpriv = (void *) cy_priv;    hci->valid_host_port[port_num] = 1;	return SUCCESS;}	/***************************************************************** * * Function Name: hc_init_sie * * This function initializes the port specify by port_num.  * * Input:  cy_priv = data structure for the controller * * Return value  : 0  *                 *****************************************************************/static int __devinit hc_init_sie (cy_priv_t * cy_priv, int sie_num){	hci_t * hci = cy_priv->hci;    sie_t * sie = &hci->sie[sie_num];        cy_dbg("Enter hc_init_sie, sie_num = 0x%x", sie_num);    /* set the initial port structure to zero */	memset (sie, 0, sizeof(sie_t));	/* set TD base address and TD buffer address for this sie:	   TD list size = 256	   TD buffer size = 1k	   see cy_7c67200_300_comm.h for detail on addr 	 */	if (sie_num == 0)	{	    sie->tdBaseAddr = cy_priv->cy_buf_addr + SIE0_TD_OFFSET;	}	else if (sie_num == 1)	{	    sie->tdBaseAddr = cy_priv->cy_buf_addr + SIE1_TD_OFFSET;	}	else	{	    cy_err("unknown sie_num %d", sie_num);		return ERROR;	}	/* Initialize the buffer */	sie->td_active = FALSE;	sie->bufBaseAddr = sie->tdBaseAddr + SIE_TD_SIZE;    /* initalize the list heads */    INIT_LIST_HEAD (&sie->done_list_head);    INIT_LIST_HEAD (&sie->td_list_head);	return SUCCESS;}/***************************************************************** * * Function Name: cy67x00_release_priv * * This function De-allocate all resources   * * Input:  hci = data structure for the host controller * * Return value  : 0  *                 *****************************************************************/static void cy67x00_release_priv (cy_priv_t * cy_priv){	    int port_num;    hci_t * hci = cy_priv->hci;	hcipriv_t * hp;        cy_dbg("Enter cy67x00_release_priv");    for (port_num = 0; port_num < MAX_NUM_PORT; port_num++)	{		if (hci->valid_host_port[port_num] == 1) {	    	hp = &hci->port[port_num]; 		    /* disconnect all devices */    		    if (hp->bus->root_hub)			{				usb_disconnect (&hp->bus->root_hub);			}			usb_deregister_bus (hp->bus);	    	usb_free_bus (hp->bus);		}	}	    if (cy_priv->cy_addr > 0)     {	    release_region (cy_priv->cy_addr, CY67X00_ADDR_SIZE);	    cy_priv->cy_addr = 0;    }    if (cy_priv->cy_irq > 0)     {	    free_irq (cy_priv->cy_irq, cy_priv);	    cy_priv->cy_irq = -1;    }    list_del (&hci->hci_hcd_list);    INIT_LIST_HEAD (&hci->hci_hcd_list);    kfree (hci);	kfree (cy_priv);}int __devinit hcd_init (cy_priv_t * cy_priv, int port_num){    hci_t * hci = NULL;	int sie_num = port_num / 2;	HWTrace (0xD2D2);	if (cy_priv == NULL)	{		cy_err("cy_priv == NULL");    }    /* Initalize data structure */	if (cy_priv->hci == NULL)	{		cy_priv->hci = hc_alloc_hci (cy_priv, port_num);		if (cy_priv->hci == NULL) 	    {			cy_err("Error allocating hci");		    return -ENOMEM;	    }	}	hci = cy_priv->hci;	if ((port_num == PORT0) || (port_num == PORT2))	{	    /* initialize  the sie structure */	    if (hc_init_sie(cy_priv, sie_num) == ERROR)		{			cy_err("can't init sie %d", sie_num);	    }	}    /* Initialize the port structure*/    if (hc_init_port(cy_priv, port_num) == ERROR)    {		cy_err("can't init port %d", port_num);    }	/* register the bus */	usb_register_bus (hci->port[port_num].bus);	hcd_start(cy_priv, port_num);	return SUCCESS;}/***************************************************************** * * *	THE FOLLOWING IS CY7C67200/300 HARDWARE SPECIFIC STUFF *  IT IS COMMON TO HCD, PCD and LCD * *******************************************************************/void __devinit cy67x00_reg_init(cy_priv_t * cy_priv){    unsigned short intStat = 0;	lcd_hpi_read_mbx(cy_priv);	lcd_write_reg(HPI_SIE_IE, 0, cy_priv);}/***************************************************************** * * Function Name: cy67x00_init * * This function request IO memory regions, request IRQ, and * allocate all other resources.  * * Input: addr = first IO address *        addr2 = second IO address *        irq = interrupt number  * * Return: SUCCESS or Error *                 *****************************************************************/static int __devinit cy67x00_init (int addr, int addr2, int irq){    int hw_config;     /* for dip switch setting */	ushort data;        cy_dbg ("Enter cy67x00_init");    	/******************************************************************	 * It reads the DIP switches from the controller card and determine	 * the demo mode which can be:	 *	 * DE1 OTG demo on SIE0 -- OTG, HPI	 * DE2 slave demo  on SIE0 -- loopback using all comm ports	 * DE3 host on SIE0 and peripheral on SIE1 -- HPI 	 * DE4 slave demo on SIE0  -- act as display device	 *	 * The DIP switches also indicates the communication mode: HPI, HSS	 * or SPI	 *******************************************************************/         hw_config = cy67x00_get_hw_config() & SAB_DIP_MASK;      hw_config = DE2_HPI;	/*    switch(hw_config)    {        case DE2_HPI:            cy_err("Configuring for DE2_HPI");            return cy67x00_hw_reset();        case DE2_HSS:            cy_err("Configuring for DE2_HSS");            return cy67x00_hw_reset();        case DE2_SPI:            cy_err("Configuring for DE2_SPI");            return cy67x00_hw_reset();        case DE1_HPI:        case DE3_HPI: 		case DE4_HPI:         default:            break;    }*/    /* allocate the private data */    HWTrace(0xBEF8);    g_cy_priv = (cy_priv_t *) kmalloc(sizeof(cy_priv_t), 0);	if (!g_cy_priv)	{	    return -ENOMEM;	}    g_cy_priv->otg = NULL;	g_cy_priv->hci = NULL;	g_cy_priv->lcd_priv = NULL;	g_cy_priv->pcdi = NULL;    g_cy_priv->system_mode[SIE0] = HOST_ROLE;    g_cy_priv->system_mode[SIE1] = HOST_ROLE;    g_cy_priv->cy_buf_addr = 0x500; // Start of arena    /* allocated I/O address for CY67x00 */    if (!request_region (addr, CY67X00_ADDR_SIZE,                          "CY7C67200/300 Embedded USB controller"))     {	    cy_err("request address %d failed", addr);		kfree(g_cy_priv);	    g_cy_priv = 0;	    return -EBUSY;	    }	g_cy_priv->cy_addr = addr;	/* Initialize the IRQ to be edge trigger */    init_irq();	/* allocated interrupt for CY67x00, the standard cy67x00_int_handler is for       the HPI protocol only.  Handler resides in lcd layer. */    if (request_irq (irq, cy67x00_int_handler, 0,                     "CY7C67200/300 Embedded USB controller HPI",                      g_cy_priv) != 0)     {        cy_err("request interrupt %d failed", irq);	    release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);		kfree(g_cy_priv);	    g_cy_priv = 0;        return -EBUSY;    }    g_cy_priv->cy_irq = irq;       /* Gets re-enabled when lcd_init is done */    disable_irq(g_cy_priv->cy_irq);            	HWTrace(0x1000);    if (cy67x00_hw_reset() != SUCCESS)    {	    cy_err("no Lyberty card present in addr 0x%x", addr);	    release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);	    free_irq (g_cy_priv->cy_irq, g_cy_priv);		kfree (g_cy_priv);        g_cy_priv = 0;	    return -EBUSY;    }     /* initialze the registers */    cy67x00_reg_init(g_cy_priv);    /* Initialize Port timers */    init_timer(&PORT0_timer);    PORT0_timer.function = hc_host_usb_reset1;    init_timer(&PORT1_timer);    PORT1_timer.function = hc_host_usb_reset1;    init_timer(&PORT2_timer);    PORT2_timer.function = hc_host_usb_reset1;    init_timer(&PORT3_timer);    PORT3_timer.function = hc_host_usb_reset1;    /* Setup drivers based upon design example *///#if 1	    switch (hw_config)    {           case DE1_HPI:            {                extern void switch_role(int new_role);                otg_t * otg;                 HWTrace (0x1);                cy_err("Configuring for DE1");                /* Initialize the Low Level Controller (lcd) structures */                if (lcd_init(&de1_bios[0], sizeof(de1_bios), 0, 0, g_cy_priv)                   == ERROR)                {                    release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);                    free_irq (g_cy_priv->cy_irq, g_cy_priv);                    kfree (g_cy_priv);                    g_cy_priv = 0;                    return ERROR;                }                /* Initialize OTG */                otg_init(g_cy_priv);                otg = g_cy_priv->otg;                /* Init pcd first so remainder EZ-HOST memory is left for hcd */                pcd_init(SIE0, DE1, g_cy_priv);                hcd_init(g_cy_priv, PORT0);                switch_role(HOST_INACTIVE_ROLE);                if(otg->id == A_DEV)                 {                    otg->a_bus_req = TRUE;                    update_otg_state(otg);                }            }            break;                case DE3_HPI: 			HWTrace (0x3);            cy_err("Configuring for DE3");			g_cy_priv->otg = NULL;			/* Initialize the Low Level Controller (lcd) structures */    		if (lcd_init(&de3_bios[0], sizeof(de3_bios), 0, 0, g_cy_priv)                == ERROR)    		{                release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);                free_irq (g_cy_priv->cy_irq, g_cy_priv);                kfree (g_cy_priv);                g_cy_priv = 0;				return ERROR;    		}                        /* Init pcd first so remainder EZ-HOST memory is left for hcd */            /* Set HW SIE1 as a peripherial */            pcd_init(SIE1, DE3, g_cy_priv);            pcd_switch_role(PERIPHERAL_ROLE, g_cy_priv);			g_cy_priv->system_mode[SIE1] = PERIPHERAL_ROLE;            /* start the USB host controller */			hcd_init(g_cy_priv, PORT0);			hcd_switch_role(HOST_ROLE, g_cy_priv);			g_cy_priv->system_mode[SIE0] = HOST_ROLE; 			break;		case DE4_HPI:             cy_err("Configuring for DE4");			/* Initialize the Low Level Controller (lcd) structures */    		if (lcd_init(0, 0, 0, 0, g_cy_priv) == ERROR)    		{                release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);                free_irq (g_cy_priv->cy_irq, g_cy_priv);                kfree (g_cy_priv);                g_cy_priv = 0;				return ERROR;    		}			/* Set HW SIE1 as a peripherial */            pcd_init(SIE0, DE4, g_cy_priv);            pcd_switch_role(PERIPHERAL_ROLE, g_cy_priv);			g_cy_priv->system_mode[SIE0] = PERIPHERAL_ROLE; 			break;        default:			//            cy_err("unknown HW mode, dip = 0x%X\n", hw_config);			cy_err("Configuring for host");            /* Initialize the Low Level Controller (lcd) structures */    		if (lcd_init(0, 0, 0, 0, g_cy_priv) == ERROR)    		{                release_region (g_cy_priv->cy_addr, CY67X00_ADDR_SIZE);                free_irq (g_cy_priv->cy_irq, g_cy_priv);                kfree (g_cy_priv);                g_cy_priv = 0;				return ERROR;    		}			/* Initialize host port(s) */			hcd_init(g_cy_priv, PORT0);			hcd_init(g_cy_priv, PORT1);			hcd_init(g_cy_priv, PORT2);//			hcd_init(g_cy_priv, PORT3);			/* Initialize the SIEs */			hc_host_usb_init (g_cy_priv, SIE0);			hc_host_usb_init (g_cy_priv, SIE1);			/* Enable host ports */		   	hc_enable_port(g_cy_priv, PORT0);		   	hc_enable_port(g_cy_priv, PORT1);		   	hc_enable_port(g_cy_priv, PORT2);//		   	hc_enable_port(g_cy_priv, PORT3);            break;    }     return SUCCESS;}/***************************************************************** * * Function Name: hci_hcd_init * * This is an init function, and it is the first function being called * * Input: none  * * Return: 0 = success or error condition  *                 *****************************************************************/static int __init hci_hcd_init (void) {    int ret;	HWTrace(0xDADA);    console_verbose();    cy_dbg("Enter hci_hcd_init");    ret = cy67x00_init (base_addr, data_reg_addr, irq);       if( ret != SUCCESS )    {        cy_err("cy67x00_init returned error.");    }    return ret;}/***************************************************************** * * Function Name: hci_hcd_cleanup * * This is a cleanup function, and it is called when module is  * unloaded.  * * Input: none  * * Return: none  *                 *****************************************************************/static void __exit hci_hcd_cleanup (void) {    struct list_head *  hci_l;    hci_t * hci = g_cy_priv->hci;        cy_dbg("Enter hci_hcd_cleanup");    for (hci_l = hci->hci_hcd_list.next; hci_l != &hci_hcd_list;) 	    {		hci = list_entry (hci_l, hci_t, hci_hcd_list);		hci_l = hci_l->next;		cy67x00_release_priv(g_cy_priv);	    }	}/***************************************************************** * * Function Name: Various  * * This is a collection of handlers called at interrupt context  * from the main interrupt handler defined in lcd. * * Input: cy_priv - Private data structure maintaining certain  *                  state for hcd, pcd, lcd, otg. * * Return: none  *                 *****************************************************************/void hcd_irq_sofeop1(cy_priv_t *cy_priv){    hci_t * hci = cy_priv->hci;    HWTrace (0x2033);    if( hci == 0 )    {        return;    }    sh_schedule_trans (cy_priv, SIE0);}/******************************************************************/void hcd_irq_sofeop2(cy_priv_t *cy_priv){    hci_t * hci = cy_priv->hci;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?