📄 usbd-bi.c
字号:
/* * linux/drivers/usbd/usbd-bi.c - USB Bus Interface Driver * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * 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/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>#ifdef CONFIG_PM#include <linux/pm.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"#include "udc.h"#include "../../cy7c67200_300_common.h"#include "../../cy7c67200_300_otg.h"/* Module Parameters ************************************************************************* *///static char *dbg = NULL;static char *dbg = "init=0:intr=0:tick=0:usbe=0:rx=0:tx=0:dma=0:setup=0:ep0=0:udc=0:stall=0:pm=0:pur=0";MODULE_PARM(dbg, "s");/* Debug switches (module parameter "dbg=...") *********************************************** */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}};/* 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);#ifdef CONFIG_PMstruct 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 usbd_urb *urb){ return 0;}/** * 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){ 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, int flag){ if (flag) { dbg_ep0(1,"stalling endpoint"); // XXX logical to physical? udc_stall_ep(endpoint, device); return 0; } dbg_ep0(1,"reseting endpoint %d", endpoint); udc_reset_ep(endpoint, device); return 0;}/* * 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, endpoint_descriptor->wMaxPacketSize, device))) { dbg_init(2, "endpoint[%d]: l: %02x p: %02x transferSize: %d packetSize: %02x INVALID", i, logical_endpoint, physical_endpoint, transfersize, endpoint_descriptor->wMaxPacketSize); dbg_init(2, "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, endpoint_descriptor->wMaxPacketSize); dbg_init(2,"epd->bEndpointAddress=%d", endpoint_descriptor->bEndpointAddress); endpoint->endpoint_address = endpoint_descriptor->bEndpointAddress; if (endpoint_descriptor->wMaxPacketSize > 64) { dbg_init(0,"incompatible with endpoint size: %x", 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 = endpoint_descriptor->wMaxPacketSize; endpoint->last = 0; endpoint->tx_urb = NULL; } else { found_rx++; endpoint->rcv_attributes = endpoint_descriptor->bmAttributes; endpoint->rcv_transferSize = transfersize&0xfff; endpoint->rcv_packetSize = endpoint_descriptor->wMaxPacketSize; endpoint->rcv_urb = NULL; } } } if (device->status == USBD_OK) { for (i = 1; i < device->bus->driver->max_endpoints; i++) { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + i; // 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) { sie_info * sie_data; cy_priv_t * cy_priv; otg_t * otg; sie_data = (sie_info *) device->bus->privdata; cy_priv = (cy_priv_t *) sie_data->cy_priv; otg = (otg_t *) cy_priv->otg; //printk(KERN_DEBUG "bi_device_event: event: %d\n", event); if (!device) { return 0; } switch (event) { case DEVICE_UNKNOWN: break; case DEVICE_INIT: break; case DEVICE_CREATE: // XXX should this stuff be in DEVICE_INIT? bi_config(device); // enable udc, enable interrupts, enable connect udc_enable(device); udc_all_interrupts(device); udc_connect(); break; case DEVICE_HUB_CONFIGURED: break; case DEVICE_RESET: device->address = 0; udc_set_address(device->address, device); udc_reset_ep(0, device); udc_all_interrupts(device); // XXX break; case DEVICE_ADDRESS_ASSIGNED: udc_set_address(device->address, device); device->status = USBD_OK; break; case DEVICE_CONFIGURED: bi_config(device); break; case DEVICE_DE_CONFIGURED: udc_reset_ep(1, device); udc_reset_ep(2, device); udc_reset_ep(3, device); break; case DEVICE_SET_INTERFACE: bi_config(device); break; case DEVICE_SET_FEATURE: break; case DEVICE_CLEAR_FEATURE: break; case DEVICE_BUS_INACTIVE: // disable suspend interrupt udc_suspended_interrupts(device); // XXX check on linkup and sl11 // if we are no longer connected then force a reset if (!udc_connected()) { usbd_device_event_irq(device, DEVICE_RESET, 0); } break; case DEVICE_BUS_ACTIVITY: // enable suspend interrupt udc_all_interrupts(device); break; case DEVICE_POWER_INTERRUPTION: break; case DEVICE_HUB_RESET: break; case DEVICE_DESTROY: udc_disconnect(); bi_disable_endpoints(device); udc_disable_interrupts(device); udc_disable(); break; case DEVICE_BUS_REQUEST: otg->b_bus_req = TRUE; update_otg_state(otg); break; case DEVICE_BUS_RELEASE: otg->b_bus_req = FALSE; update_otg_state(otg); break; case DEVICE_RCV_URB_RECYCLED: udc_rcv_urb_recycled(); break; case DEVICE_ACCEPT_HNP: otg->b_hnp_en = TRUE; update_otg_state(otg); break; case DEVICE_REQUEST_SRP: //otg->srp_start_flag = TRUE; otg->b_bus_req = TRUE; otg->b_se0_srp = TRUE; update_otg_state(otg); break; case DEVICE_FUNCTION_PRIVATE: break; } return 0;}/** * bi_send_urb - start transmit * @urb: */int bi_send_urb(struct usbd_urb *urb){ unsigned long flags; dbg_tx(4, "urb: %p", urb); local_irq_save(flags); if (urb && urb->endpoint && !urb->endpoint->tx_urb) { dbg_tx(2, "urb: %p endpoint: %x", urb, urb->endpoint->endpoint_address); usbd_tx_complete_irq(urb->endpoint, 0); udc_start_in_irq(urb->endpoint, urb->device); } local_irq_restore(flags); // Shouldn't need to make this atomic, all we need is a change indicator urb->device->usbd_rxtx_timestamp = jiffies; return 0;}#ifdef CONFIG_PMstatic int bi_pm_event(struct pm_dev *pm_dev, pm_request_t request, void *unused);#endifstruct usb_bus_operations bi_ops = { send_urb: bi_send_urb, cancel_urb: bi_cancel_urb, endpoint_halted: bi_endpoint_halted, device_feature: bi_device_feature, device_event: bi_device_event,};struct usb_bus_driver bi_driver = { name: "", max_endpoints: 0, ops: &bi_ops, this_module: THIS_MODULE,};struct usb_bus_driver * bi_retrieve_bus_driver(){ return(&bi_driver);}/* Bus Interface Received Data *************************************************************** */struct usb_device_instance *device_array[MAX_DEVICES];/* Bus Interface Support Functions *********************************************************** *//** * udc_cable_event - called from cradle interrupt handler */void udc_cable_event(void){ struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; dbgENTER(dbgflg_usbdbi_init,1); // sanity check if (!(device = device_array[0]) || !(bus = device->bus) || !(data = bus->privdata)) { return; } { unsigned long flags; local_irq_save(flags); if (udc_connected()) { dbg_init(1, "state: %d connected: %d", device->device_state, 1);; if (device->device_state == STATE_ATTACHED) { dbg_init(1, "LOADING");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -