usbd-bi.c

来自「Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码」· C语言 代码 · 共 1,414 行 · 第 1/3 页

C
1,414
字号
/* * linux/drivers/usbd/usbd-bi.c - USB Bus Interface Driver * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * Copyright (c) 2003 MontaVista Software Inc. * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>#if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE)#include <linux/pm.h>#endif#ifdef CONFIG_DPM	/* MVL-CEE */#include <linux/device.h>#endif#include "../usbd.h"#include "../usbd-debug.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"//#define DEBUG 1#if DEBUGstatic unsigned int usbd_bi_dbg = 1;#else#define usbd_bi_dbg 0#endif/* Module Parameters ************************************************************************* */static char *dbg = NULL;MODULE_PARM (dbg, "s");/* Debug switches (module parameter "dbg=...") *********************************************** */extern int dbgflg_usbdbi_init;int dbgflg_usbdbi_intr;int dbgflg_usbdbi_tick;int dbgflg_usbdbi_usbe;int dbgflg_usbdbi_rx;int dbgflg_usbdbi_tx;int dbgflg_usbdbi_dma_flg;int dbgflg_usbdbi_setup;int dbgflg_usbdbi_ep0;int dbgflg_usbdbi_udc;int dbgflg_usbdbi_stall;int dbgflg_usbdbi_pm;int dbgflg_usbdbi_pur;static debug_option dbg_table[] = {	{&dbgflg_usbdbi_init, NULL, "init", "initialization and termination"},	{&dbgflg_usbdbi_intr, NULL, "intr", "interrupt handling"},	{&dbgflg_usbdbi_tick, NULL, "tick", "interrupt status monitoring on clock tick"},	{&dbgflg_usbdbi_usbe, NULL, "usbe", "USB events"},	{&dbgflg_usbdbi_rx, NULL, "rx", "USB RX (host->device) handling"},	{&dbgflg_usbdbi_tx, NULL, "tx", "USB TX (device->host) handling"},	{&dbgflg_usbdbi_dma_flg, NULL, "dma", "DMA handling"},	{&dbgflg_usbdbi_setup, NULL, "setup", "Setup packet handling"},	{&dbgflg_usbdbi_ep0, NULL, "ep0", "End Point 0 packet handling"},	{&dbgflg_usbdbi_udc, NULL, "udc", "USB Device"},	{&dbgflg_usbdbi_stall, NULL, "stall", "Testing"},	{&dbgflg_usbdbi_pm, NULL, "pm", "Power Management"},	{&dbgflg_usbdbi_pur, NULL, "pur", "USB cable Pullup Resistor"},	{NULL, NULL, NULL, NULL}};/* XXXstatic __initdata unsigned char default_dev_addr[ETH_ALEN] = {        0x40, 0x00, 0x00, 0x00, 0x00, 0x01};*//* globals */int have_cable_irq;/* ticker */int ticker_terminating;int ticker_timer_set;/** * kickoff_thread - start management thread */void ticker_kickoff (void);/** * killoff_thread - stop management thread */void ticker_killoff (void);#if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE)struct pm_dev *pm_dev;		// power management#endif/* Bus Interface Callback Functions ********************************************************** *//** * bi_cancel_urb - cancel sending an urb * @urb: data urb to cancel * * Used by the USB Device Core to cancel an urb. */int bi_cancel_urb (struct urb *urb){	dbgENTER (dbgflg_usbdbi_tx, 1);	//ep2_reset();	return 0;}/** * bi_find_endpoint - find endpoint * @device: device * @endpoint_address: endpoint address * * The endpoint_address MUST have the IN/OUT bit (0x80) set appropriately to  * distinguish IN endpoints from OUT endpoints. */struct usb_endpoint_instance *bi_find_endpoint(struct usb_device_instance *device, int endpoint_address){	if (device && device->bus && device->bus->endpoint_array) {                int i;		for (i = 0; i < udc_max_endpoints (); i++) {			struct usb_endpoint_instance *endpoint;			if ((endpoint = device->bus->endpoint_array + i)) {				if (endpoint->endpoint_address == endpoint_address) {                                        return endpoint;                                }			}		}	}        return NULL;}/** * bi_endpoint_halted - check if endpoint halted * @device: device * @endpoint: endpoint to check * * Used by the USB Device Core to check endpoint halt status. */int bi_endpoint_halted (struct usb_device_instance *device, int endpoint_address){        struct usb_endpoint_instance *endpoint;        if ((endpoint = bi_find_endpoint(device, endpoint_address))) {                dbg_ep0 (1, "endpoint: %d status: %d", endpoint_address, endpoint->status);                return endpoint->status;        }        dbg_ep0 (0, "endpoint: %02x NOT FOUND", endpoint_address);	return 0;}/** * bi_device_feature - handle set/clear feature requests * @device: device * @endpoint: endpoint to check * @flag: set or clear * * Used by the USB Device Core to check endpoint halt status. */int bi_device_feature (struct usb_device_instance *device, int endpoint_address, int flag){	int ep = 0;        struct usb_endpoint_instance *endpoint = NULL;        dbg_ep0 (0, "endpoint: %d flag: %d", endpoint_address, flag);        if (device && device->bus && device->bus->endpoint_array) {                endpoint = device->bus->endpoint_array;                for (ep = 0; ep < udc_max_endpoints (); ep++) {                        if (endpoint->endpoint_address == endpoint_address)                                break;                        endpoint++;                }                if (ep == udc_max_endpoints ())                        endpoint = NULL;        }        if (endpoint) {                dbg_ep0 (1, "endpoint: %d status: %d", ep, endpoint->status);                if (flag && !endpoint->status) {                        dbg_ep0 (1, "stalling endpoint");                        udc_stall_ep (ep);                        endpoint->status = 1;                }                else if (!flag && endpoint->status){                        dbg_ep0 (1, "reseting endpoint %d", ep);                        udc_reset_ep (ep);                        endpoint->status = 0;                }                return 0;        }        dbg_ep0 (0, "endpoint: %d NOT FOUND", endpoint_address);        return -EINVAL;}/*  * bi_disable_endpoints - disable udc and all endpoints */static void bi_disable_endpoints (struct usb_device_instance *device){	int i;	if (device && device->bus && device->bus->endpoint_array) {		for (i = 0; i < udc_max_endpoints (); i++) {			struct usb_endpoint_instance *endpoint;			if ((endpoint = device->bus->endpoint_array + i)) {				usbd_flush_ep (endpoint);			}		}	}}/* bi_config - commission bus interface driver */static int bi_config (struct usb_device_instance *device){	int i;	struct usb_interface_descriptor *interface;	struct usb_endpoint_descriptor *endpoint_descriptor;	int found_tx = 0;	int found_rx = 0;	dbg_init (1, "checking config: config: %d interface: %d alternate: %d",		  device->configuration, device->interface, device->alternate);	bi_disable_endpoints (device);	// audit configuration for compatibility	if (!(interface = usbd_device_interface_descriptor (device,                        0, device->configuration, device->interface, device->alternate)))         {		dbg_init (0, "cannot fetch interface descriptor c:%d i:%d a:%d",			  device->configuration, device->interface, device->alternate);		return -EINVAL;	}	dbg_init (2, "---> endpoints: %d", interface->bNumEndpoints);	// iterate across all endpoints for this configuration and verify they are valid 	for (i = 0; i < interface->bNumEndpoints; i++) {		int transfersize;		int physical_endpoint;		int logical_endpoint;		//dbg_init(0, "fetching endpoint %d", i);                if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, 0,                                device-> configuration, device-> interface, device-> alternate, i)))                 {			dbg_init (0, "cannot fetch endpoint descriptor: %d", i);			continue;		}		// XXX check this                transfersize = usbd_device_endpoint_transfersize (device, 0,                        device->configuration, device->interface, device->alternate, i);                 logical_endpoint = endpoint_descriptor->bEndpointAddress;		if (!		    (physical_endpoint =		     udc_check_ep (logical_endpoint, 		     le16_to_cpu(endpoint_descriptor->wMaxPacketSize)))) {			dbg_init (2,				  "endpoint[%d]: l: %02x p: %02x transferSize: %d packetSize: %02x INVALID",				  i, logical_endpoint, physical_endpoint, transfersize,				  le16_to_cpu(endpoint_descriptor->wMaxPacketSize));			dbg_init (0, "invalid endpoint: %d %d", logical_endpoint, physical_endpoint);			return -EINVAL;		}                 else {			struct usb_endpoint_instance *endpoint =			    device->bus->endpoint_array + physical_endpoint;			dbg_init (2, "endpoint[%d]: l: %02x p: %02x transferSize: %d packetSize: %02x FOUND",				  i, logical_endpoint, physical_endpoint, transfersize,				  le16_to_cpu(endpoint_descriptor->wMaxPacketSize));			dbg_init (2, "epd->bEndpointAddress=%02x", endpoint_descriptor->bEndpointAddress);                        endpoint->endpoint_address = endpoint_descriptor->bEndpointAddress;			if (le16_to_cpu(endpoint_descriptor->wMaxPacketSize) > 64) {				dbg_init (0, "incompatible with endpoint size: %x", 					le16_to_cpu(endpoint_descriptor->wMaxPacketSize));				return -EINVAL;			}			if (endpoint_descriptor->bEndpointAddress & IN) {				found_tx++;				endpoint->tx_attributes = endpoint_descriptor->bmAttributes;				endpoint->tx_transferSize = transfersize & 0xfff;				endpoint->tx_packetSize = le16_to_cpu(endpoint_descriptor->wMaxPacketSize);				endpoint->last = 0;                                if (endpoint->tx_urb) {                                        dbg_init (1, "CLEARING tx_urb: %p", endpoint->tx_urb);                                        usbd_dealloc_urb (endpoint->tx_urb);                                        endpoint->tx_urb = NULL;                                }			} else {				found_rx++;				endpoint->rcv_attributes = endpoint_descriptor->bmAttributes;				endpoint->rcv_transferSize = transfersize & 0xfff;				endpoint->rcv_packetSize = 					le16_to_cpu(endpoint_descriptor->wMaxPacketSize);                                if (endpoint->rcv_urb) {                                        dbg_init (1, "CLEARING rcv_urb: %p", endpoint->tx_urb);                                        usbd_dealloc_urb (endpoint->rcv_urb);                                        endpoint->rcv_urb = NULL;                                }			}		}	}	// iterate across all endpoints and enable them        dbg_init(1, "---> device->status: %d", device->status);	if (device->status == USBD_OK) {                dbg_init (1, "enabling endpoints");		for (i = 1; i < device->bus->driver->max_endpoints; i++) {			struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + i;			dbg_init (1, "endpoint[%d]: %p addr: %02x transferSize: %d:%d packetSize: %d:%d SETUP",				  i, endpoint, endpoint->endpoint_address,				  endpoint->rcv_transferSize, endpoint->tx_transferSize,				  endpoint->rcv_packetSize, endpoint->tx_packetSize);			//udc_setup_ep(device, i, endpoint->endpoint_address?  endpoint : NULL);			udc_setup_ep (device, i, endpoint);		}	}	return 0;}/** * bi_device_event - handle generic bus event * @device: device pointer * @event: interrupt event * * Called by usb core layer to inform bus of an event. */int bi_device_event (struct usb_device_instance *device, usb_device_event_t event, int data){	//printk(KERN_DEBUG "bi_device_event: event: %d\n", event);	if (!device) {		return 0;	}        dbg_usbe (1,"%s", USBD_DEVICE_EVENTS(event));	switch (event) {	case DEVICE_UNKNOWN:		break;	case DEVICE_INIT:		break;	case DEVICE_CREATE:	// XXX should this stuff be in DEVICE_INIT?		// enable upstream port		//ep0_enable(device);		// for net_create		bi_config (device);		// enable udc, enable interrupts, enable connect                printk(KERN_INFO"bi_device_event: call udc_enable\n");		udc_enable (device);                printk(KERN_INFO"bi_device_event: call udc_all_interrupts\n");                // XXX verify		udc_suspended_interrupts (device);		//udc_all_interrupts (device);		dbg_usbe (1, "CREATE done");		break;	case DEVICE_HUB_CONFIGURED:		udc_connect ();		break;	case DEVICE_RESET:		device->address = 0;		udc_set_address (device->address);		udc_reset_ep (0);                                // XXX verify		udc_suspended_interrupts (device);		dbg_usbe (1, "DEVICE RESET done: %d", device->address);		break;	case DEVICE_ADDRESS_ASSIGNED:		udc_set_address (device->address);		device->status = USBD_OK;                // XXX verify		udc_all_interrupts (device);	// XXX		break;	case DEVICE_CONFIGURED:		device->status = USBD_OK;		bi_config (device);		break;	case DEVICE_DE_CONFIGURED:		{			int ep;			for (ep = 1; ep < udc_max_endpoints (); ep++)				udc_reset_ep (ep);		}		break;	case DEVICE_SET_INTERFACE:		bi_config (device);		break;	case DEVICE_SET_FEATURE:		break;	case DEVICE_CLEAR_FEATURE:

⌨️ 快捷键说明

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