usbd-bi.c
来自「Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码」· C语言 代码 · 共 1,414 行 · 第 1/3 页
C
1,414 行
len += sprintf ((char *) page + len, "Cable: %s\n", udc_connected ()? "Plugged" : "Unplugged"); break; case 2: if ((device = device_array[0])) { struct usb_function_instance * function_instance; struct usb_bus_instance * bus; len += sprintf ((char *) page + len, "Device status: %s\n", USBD_DEVICE_STATUS(device->status)); len += sprintf ((char *) page + len, "Device state: %s\n", USBD_DEVICE_STATE(device->device_state)); if ((function_instance = device->function_instance_array+0)) { len += sprintf ((char *) page + len, "Function: %s\n", function_instance->function_driver->name); } if ((bus= device->bus)) { len += sprintf ((char *) page + len, "Bus interface: %s\n", bus->driver->name); } } break; default: break; } if (len > count) { len = -EINVAL; } else if (len > 0 && copy_to_user (buf, (char *) page, len)) { len = -EFAULT; } free_page (page); MOD_DEC_USE_COUNT; return len;}/* * * usbd_proc_write - implement proc file system write. * @file * @buf * @count * @pos * * Proc file system write function, used to signal monitor actions complete. * (Hotplug script (or whatever) writes to the file to signal the completion * of the script.) An ugly hack. */static ssize_t usbd_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos){ struct usb_device_instance *device; size_t n = count; char command[64]; char *cp = command; int i = 0; MOD_INC_USE_COUNT; //printk(KERN_DEBUG "%s: count=%u\n",__FUNCTION__,count); while ((n > 0) && (i < 64)) { // Not too efficient, but it shouldn't matter if (copy_from_user (cp++, buf + (count - n), 1)) { count = -EFAULT; break; } *cp = '\0'; i++; n -= 1; //printk(KERN_DEBUG "%s: %u/%u %02x\n",__FUNCTION__,count-n,count,c); } if (!strncmp (command, "plug", 4)) { udc_connect (); } else if (!strncmp (command, "unplug", 6)) { udc_disconnect (); if ((device = device_array[0])) { usbd_device_event (device, DEVICE_RESET, 0); } } MOD_DEC_USE_COUNT; return (count);}static struct file_operations usbd_proc_operations_functions = { read:usbd_proc_read, write:usbd_proc_write,};#endif/* Module Init - module loading init and exit routines *************************************** *//* We must be able to use the real bi_init() and bi_exit() functions * from here and the power management event function. * * We handle power management registration issues from here. * *//* bi_modinit - commission bus interface driver */static int __init bi_modinit (void){ struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; printk (KERN_INFO "usbd-bi: (dbg=\"%s\")\n", dbg ? dbg : ""); // process debug options if (0 != scan_debug_options ("usbd-bi", dbg_table, dbg)) { return -EINVAL; } // check if we can see the UDC if (bi_udc_init ()) { return -EINVAL; } // allocate a bi private data structure if ((data = kmalloc (sizeof (struct bi_data), GFP_KERNEL)) == NULL) { bi_udc_exit (); return -EINVAL; } memset (data, 0, sizeof (struct bi_data)); // register this bus interface driver and create the device driver instance if ((bus = usbd_register_bus (&bi_driver)) == NULL) { kfree (data); bi_udc_exit (); return -EINVAL; } bus->privdata = data; // 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\n", bus->serial_number_str, bus->serial_number); } if ((device = usbd_register_device (NULL, bus, 8)) == NULL) { usbd_deregister_bus (bus); kfree (data); bi_udc_exit (); return -EINVAL; }#if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE) // register with power management pm_dev = pm_register (PM_USB_DEV, PM_SYS_UNKNOWN, bi_pm_event); pm_dev->data = device;#endif#ifdef CONFIG_DPM /* MVL-CEE */ bi_udc_ldm_driver_register(); bi_udc_ldm_device_register();#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 printk(KERN_INFO"bi_modinit: call udc_startup_events\n"); udc_startup_events (device);#if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE) 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 (); }#ifdef CONFIG_USBD_PROCFS { struct proc_dir_entry *p; // create proc filesystem entries if ((p = create_proc_entry ("usbd", 0, 0)) == NULL) { return -ENOMEM; } p->proc_fops = &usbd_proc_operations_functions; }#endif dbgLEAVE (dbgflg_usbdbi_init, 1); return 0;}/* bi_modexit - decommission bus interface driver */static void __exit bi_modexit (void){ struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; dbgENTER (dbgflg_usbdbi_init, 1);#ifdef CONFIG_USBD_PROCFS remove_proc_entry ("usbd", NULL);#endif udc_disconnect (); udc_disable (); if ((device = device_array[0])) { // XXX moved to usbd_deregister_device() //device->status = USBD_CLOSING; // 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; // XXX moved to usbd-bus.c usbd_deregister_device()#if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE) dbg_init (1, "PM_UNREGISTER(pm_dev#%p)", pm_dev); if (pm_dev) { pm_unregister_all(bi_pm_event); }#endif#ifdef CONFIG_DPM /* MVL-CEE */ bi_udc_ldm_device_unregister(); bi_udc_ldm_driver_unregister();#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 (3, "--------------"); } // do some work memset (buf, 0, sizeof (buf)); cp = buf; if (dbgflg_usbdbi_tick) { unsigned long flags; local_irq_save (flags); dbg_tick (2, "[%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 (); } 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 + =
减小字号Ctrl + -
显示快捷键?