📄 usbd-bi.c
字号:
usbd_device_event_irq(device, DEVICE_HUB_CONFIGURED, 0); usbd_device_event_irq(device, DEVICE_RESET, 0); } } else { dbg_init(1, "state: %d connected: %d", device->device_state, 0);; if (device->device_state != STATE_ATTACHED) { dbg_init(1, "UNLOADING"); usbd_device_event_irq(device, DEVICE_RESET, 0); usbd_device_event_irq(device, DEVICE_POWER_INTERRUPTION, 0); usbd_device_event_irq(device, DEVICE_HUB_RESET, 0); } } local_irq_restore(flags); } dbgLEAVE(dbgflg_usbdbi_init,1);}/* Module Init - the device init and exit routines ******************************************* *//* bi_udc_init - initialize USB Device Controller This function is called for each physical bus interface that is found. Register an interrupt handler and IO region. Return non-zero for error. */int bi_udc_init(){ dbg_init(1,"Loading %s", udc_name()); bi_driver.name = udc_name(); bi_driver.max_endpoints = udc_max_endpoints(); bi_driver.maxpacketsize = udc_ep0_packetsize(); dbg_init(1,"name: %s endpoints: %d ep0: %d", bi_driver.name, bi_driver.max_endpoints, bi_driver.maxpacketsize); // request device IRQ. if (udc_request_udc_irq()) { dbg_init(0,"name: %s request udc irq failed", udc_name()); return -EINVAL; } // request device IO if (udc_request_io()) { udc_release_udc_irq(); dbg_init(0,"name: %s request udc io failed", udc_name()); return -EINVAL; } if (udc_init()) { udc_release_udc_irq(); udc_release_io(); dbg_init(1,"name: %s probe failed", udc_name()); return -EINVAL; } return 0;}/** * bi_udc_exit - Stop using the USB Device Controller * * Stop using the USB Device Controller. * * Shutdown and free dma channels, de-register the interrupt handler. */void bi_udc_exit(void){ int i; dbg_init(1, "Unloading %s", udc_name()); for (i = 0; i < udc_max_endpoints(); i++) { udc_disable_ep(i); } // free io and irq udc_disconnect(); udc_disable(); udc_release_io(); udc_release_udc_irq(); if (have_cable_irq) { udc_release_cable_irq(); }}/* bi_exit - decommission bus interface driver */static void bi_exit(void){}#ifdef CONFIG_PM/* Module Init - Power management ************************************************************ *//* The power management scheme is simple. Simply do the following: * * Event Call Equivalent * ------------------------------------------ * PM_SUSPEND bi_exit(); rmmod * PM_RESUME bi_init(); insmod * */static int pm_suspended;/* * usbd_pm_callback * @dev: * @rqst: * @unused: * * Used to signal power management events. */static int bi_pm_event(struct pm_dev *pm_dev, pm_request_t request, void *unused){ struct usb_device_instance *device; dbg_pm(0, "request: %d pm_dev: %p data: %p", request, pm_dev, pm_dev->data); if (!(device = pm_dev->data)) { dbg_pm(0, "DATA NULL, NO DEVICE"); return 0; } switch (request) {#if defined(CONFIG_IRIS) case PM_STANDBY: case PM_BLANK:#endif case PM_SUSPEND: dbg_pm(0, "PM_SUSPEND"); if (!pm_suspended) { pm_suspended = 1; dbg_init(1,"MOD_INC_USE_COUNT %d", GET_USE_COUNT(THIS_MODULE)); udc_disconnect(); // disable USB pullup if we can udc_disable_interrupts(device); // disable interupts udc_disable(); // disable UDC dbg_pm(0, "PM_SUSPEND: finished"); } break;#if defined(CONFIG_IRIS) case PM_UNBLANK:#endif case PM_RESUME: dbg_pm(0, "PM_RESUME"); if (pm_suspended) { // probe for device if (udc_init()) { dbg_init(0,"udc_init failed"); //return -EINVAL; } udc_enable(device); // enable UDC udc_all_interrupts(device); // enable interrupts udc_connect(device); // enable USB pullup if we can pm_suspended = 0; dbg_init(1,"MOD_INC_USE_COUNT %d", GET_USE_COUNT(THIS_MODULE)); dbg_pm(0, "PM_RESUME: finished"); } break; } return 0;}#endif/* bi_modinit - commission bus interface driver */int __init bi_modinit(void){ struct usb_bus_instance * bus; struct usb_device_instance * device; //extern const char __usbd_module_info[]; //printk(KERN_INFO "%s (dbg=\"%s\")\n", __usbd_module_info, dbg?dbg:""); if (0 != scan_debug_options("usb-bus",dbg_table,dbg)) { printk("Failed to scan dbg in bi_modinit\n"); } if (bi_udc_init()) { return(-EINVAL); } // register this bus interface driver and create the device driver instance if ((bus = usbd_register_bus(&bi_driver))==NULL) { bi_udc_exit(); return -EINVAL; } // see if we can scrounge up something to set a sort of unique device // address if (!udc_serial_init(bus)) { dbg_init(1,"serial: %s %04x", bus->serial_number_str, bus->serial_number); } if ((device = usbd_register_device(NULL, bus, 8))==NULL) { usbd_deregister_bus(bus); bi_udc_exit(); return -EINVAL; }#ifdef CONFIG_PM // register with power management pm_dev = pm_register(PM_USB_DEV, PM_SYS_UNKNOWN, bi_pm_event); pm_dev->data = device;#endif bus->device = device; device_array[0] = device; // initialize the device { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + 0; // setup endpoint zero endpoint->endpoint_address = 0; endpoint->tx_attributes = 0; endpoint->tx_transferSize = 255; endpoint->tx_packetSize = udc_ep0_packetsize(); endpoint->rcv_attributes = 0; endpoint->rcv_transferSize = 0x8; endpoint->rcv_packetSize = udc_ep0_packetsize(); udc_setup_ep(device, 0, endpoint); } // hopefully device enumeration will finish this process udc_startup_events(device);#ifdef CONFIG_PM dbg_pm(0,"pm_dev->callback#%p",pm_dev->callback); if (!udc_connected()) { /* Fake a call from the PM system to suspend the UDC until it is needed (cable connect, etc) */ (void) bi_pm_event(pm_dev,PM_SUSPEND,NULL); /* There appears to be no constant for this, but inspection of arch/arm/mach-l7200/apm.c:send_event() shows that the suspended state is 3 (i.e. pm_send_all(PM_SUSPEND, (void *)3)) corresponding to ACPI_D3. */ pm_dev->state = 3; }#endif if (dbgflg_usbdbi_tick > 0) { // start ticker ticker_kickoff(); } dbgLEAVE(dbgflg_usbdbi_init,1); return 0;}/* bi_modexit - decommission bus interface driver */void __exit bi_modexit(void){ struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; dbgENTER(dbgflg_usbdbi_init,1); if ((device = device_array[0])) { // XXX moved to usbd_deregister_device() //device->status = USBD_CLOSING; udc_disconnect(); udc_disable(); // XXX XXX if (dbgflg_usbdbi_tick > 0) { ticker_killoff(); } bus = device->bus; data = bus->privdata; // XXX usbd_device_event(device, DEVICE_RESET, 0); usbd_device_event(device, DEVICE_POWER_INTERRUPTION, 0); usbd_device_event(device, DEVICE_HUB_RESET, 0); dbg_init(1,"DEVICE_DESTROY"); usbd_device_event(device, DEVICE_DESTROY, 0); dbg_init(1,"DISABLE ENDPOINTS"); bi_disable_endpoints(device); dbg_init(1,"UDC_DISABLE"); //udc_disable(); dbg_init(1,"BI_UDC_EXIT"); bi_udc_exit(); device_array[0] = NULL; bus->privdata = NULL;#ifdef CONFIG_PM dbg_init(1,"PM_UNREGISTER(pm_dev#%p)",pm_dev); if (pm_dev) { pm_unregister(pm_dev); }#endif dbg_init(1,"DEREGISTER DEVICE"); usbd_deregister_device(device); bus->device = NULL; dbg_init(1,"kfree(data#%p)",data); if (data) { kfree(data); } if (bus->serial_number_str) { kfree(bus->serial_number_str); } dbg_init(1,"DEREGISTER BUS"); usbd_deregister_bus(bus); } else { dbg_init(0,"device is NULL"); } dbg_init(1,"BI_EXIT"); bi_exit(); dbgLEAVE(dbgflg_usbdbi_init,1);}/* ticker *//* Clock Tick Debug support ****************************************************************** */#define RETRYTIME 10int ticker_terminating;int ticker_timer_set;unsigned int udc_interrupts;unsigned int udc_interrupts_last;static DECLARE_MUTEX_LOCKED(ticker_sem_start);static DECLARE_MUTEX_LOCKED(ticker_sem_work);void ticker_tick(unsigned long data){ ticker_timer_set = 0; up(&ticker_sem_work);}void udc_ticker_poke(void){ up(&ticker_sem_work);}int ticker_thread(void *data) { struct timer_list ticker; // detach lock_kernel(); exit_mm(current); exit_files(current); exit_fs(current); // setsid equivalent, used at start of kernel thread, no error checks needed, or at least none made :). current->leader = 1; current->session = current->pgrp = current->pid; current->tty = NULL; current->tty_old_pgrp = 0; // Name this thread sprintf(current->comm, "usbd-bi"); // setup signal handler current->exit_signal = SIGCHLD; spin_lock(¤t->sigmask_lock); flush_signals(current); spin_unlock(¤t->sigmask_lock); // XXX Run at a high priority, ahead of sync and friends current->nice = -20; current->policy = SCHED_OTHER; unlock_kernel(); // setup timer init_timer(&ticker); ticker.data = 0; ticker.function = ticker_tick; // let startup continue up(&ticker_sem_start); // process loop for (ticker_timer_set = ticker_terminating = 0; !ticker_terminating;) { char buf[100]; char *cp; if (!ticker_timer_set) { mod_timer(&ticker, jiffies + HZ*RETRYTIME); } // wait for someone to tell us to do something down(&ticker_sem_work); if (udc_interrupts != udc_interrupts_last) { dbg_tick(1,"--------------"); } // do some work memset(buf, 0, sizeof(buf)); cp = buf; if (dbgflg_usbdbi_tick) { unsigned long flags; local_irq_save(flags); dbg_tick(1,"[%d]", udc_interrupts); udc_regs(); local_irq_restore(flags); }#if 0 // XXX#if defined(CONFIG_SA1110_CALYPSO) && defined(CONFIG_PM) && defined(CONFIG_USBD_TRAFFIC_KEEPAWAKE) /* Check for rx/tx activity, and reset the sleep timer if present */ if (device->usbd_rxtx_timestamp != device->usbd_last_rxtx_timestamp) { extern void resetSleepTimer(void); dbg_tick(7,"resetting sleep timer"); resetSleepTimer(); device->usbd_last_rxtx_timestamp = device->usbd_rxtx_timestamp; }#endif#endif#if 0 /* Check for TX endpoint stall. If the endpoint has stalled, we have probably run into the DMA/TCP window problem, and the only thing we can do is disconnect from the bus, then reconnect (and re-enumerate...). */ if (reconnect > 0 && 0 >= --reconnect) { dbg_init(0,"TX stall disconnect finished"); udc_connect(); /* TODO: needs a device pointer */ } else if (0 != USBD_STALL_TIMEOUT_SECONDS) { // Stall watchdog unleashed unsigned long now, tx_waiting; now = jiffies; tx_waiting = (now - tx_queue_head_timestamp(now)) / HZ; if (tx_waiting > USBD_STALL_TIMEOUT_SECONDS) { /* The URB at the head of the queue has waited too long */ reconnect = USBD_STALL_DISCONNECT_DURATION; dbg_init(0,"TX stalled, disconnecting for %d seconds", reconnect); udc_disconnect(); } }#endif } // remove timer del_timer(&ticker); // let the process stopping us know we are done and return up(&ticker_sem_start); return 0;}/** * kickoff_thread - start management thread */void ticker_kickoff(void){ ticker_terminating = 0; kernel_thread(&ticker_thread, NULL, 0); down(&ticker_sem_start);}/** * killoff_thread - stop management thread */void ticker_killoff(void){ if (!ticker_terminating) { ticker_terminating = 1; up(&ticker_sem_work); down(&ticker_sem_start); }}/* module *//*module_init(bi_modinit);module_exit(bi_modexit);*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -