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