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 (&current->sigmask_lock);	flush_signals (current);	spin_unlock (&current->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 + -
显示快捷键?