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