www.pudn.com > Linux2410_device.rar > gen.c
/* * linux/drivers/usbd/gen_bi/udc.c -- USB Device Controller driver. * * Copyright (c) 2000, 2001, 2002 Lineo * * By: * Stuart Lynne, * Tom Rushworth , * Bruce Balden * * 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 #include #include "../usbd-export.h" #include "../usbd-build.h" #include "../usbd-module.h" MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com"); MODULE_DESCRIPTION ("USB Device Prototype Bus Interface"); USBD_MODULE_INFO ("gen_bi 0.1-alpha"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../usbd.h" #include "../usbd-func.h" #include "../usbd-bus.h" #include "../usbd-inline.h" #include "usbd-bi.h" //#include "xxxx.h" #include "gen.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) static struct usb_device_instance *udc_device; // required for the interrupt handler /* * ep_endpoints - map physical endpoints to logical endpoints */ static struct usb_endpoint_instance *ep_endpoints[UDC_MAX_ENDPOINTS]; static struct urb ep0_urb; static unsigned char usb_address; extern unsigned int udc_interrupts; /* ********************************************************************************************* */ /* IO */ /* ********************************************************************************************* */ /* Control (endpoint zero) */ /* ********************************************************************************************* */ /* Bulk OUT (recv) */ /* ********************************************************************************************* */ /* Bulk IN (tx) */ /** * send_data - send packet via endpoint * @ep: logical endpoint number * @bp: pointer to data * @size: bytes to write */ static void __inline__ send_data (unsigned char ep, unsigned char *bp, unsigned char size) { if (bp && size) { // copy data from buffer to chip } // arm } /** * start_in - start transmit * @ep: */ static void __inline__ start_in (unsigned int ep, struct usb_endpoint_instance *endpoint, int restart) { if (endpoint->tx_urb) { struct urb *urb = endpoint->tx_urb; if ((urb->actual_length - endpoint->sent) > 0) { endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->tx_packetSize); send_data (ep, urb->buffer + endpoint->sent, endpoint->last); } else { // XXX ZLP endpoint->last = 0; send_data (ep, urb->buffer + endpoint->sent, 0); } } } /* ********************************************************************************************* */ /* Interrupt Handler */ #if 0 /** * int_hndlr - interrupt handler * */ static void int_hndlr (int irq, void *dev_id, struct pt_regs *regs) { udc_interrupts++; } #endif /* ********************************************************************************************* */ /* ********************************************************************************************* */ /* * Start of public functions. */ /** * udc_start_in_irq - start transmit * @eendpoint: endpoint instance * * Called by bus interface driver to see if we need to start a data transmission. */ void udc_start_in_irq (struct usb_endpoint_instance *endpoint) { } /** * udc_init - initialize * * Return non-zero if we cannot see device. **/ int udc_init (void) { // reset return 0; } /** * udc_start_in - start transmit * @eendpoint: endpoint instance * * Called by bus interface driver to see if we need to start a data transmission. */ void udc_start_in (struct usb_endpoint_instance *endpoint) { if (endpoint) { unsigned long flags; local_irq_save (flags); if (!endpoint->tx_urb) { usbd_tx_complete_irq (endpoint, 0); start_in (endpoint->endpoint_address & 0x7f, endpoint, 0); } local_irq_restore (flags); } } /** * udc_stall_ep - stall endpoint * @ep: physical endpoint * * Stall the endpoint. */ void udc_stall_ep (unsigned int ep) { if (ep < UDC_MAX_ENDPOINTS) { // stall } } /** * udc_reset_ep - reset endpoint * @ep: physical endpoint * reset the endpoint. * * returns : 0 if ok, -1 otherwise */ void udc_reset_ep (unsigned int ep) { if (ep < UDC_MAX_ENDPOINTS) { // reset } } /** * udc_endpoint_halted - is endpoint halted * @ep: * * Return non-zero if endpoint is halted */ int udc_endpoint_halted (unsigned int ep) { return 0; } /** * udc_set_address - set the USB address for this device * @address: * * Called from control endpoint function after it decodes a set address setup packet. */ void udc_set_address (unsigned char address) { // address cannot be setup until ack received usb_address = address; } #if 0 /** * udc_serial_init - set a serial number if available */ static int __init udc_serial_init (struct usb_bus_instance *bus) { return -EINVAL; } #endif /* ********************************************************************************************* */ /** * udc_max_endpoints - max physical endpoints * * Return number of physical endpoints. */ int udc_max_endpoints (void) { return UDC_MAX_ENDPOINTS; } /** * udc_check_ep - check logical endpoint * @lep: * * Return physical endpoint number to use for this logical endpoint or zero if not valid. */ int udc_check_ep (int logical_endpoint, int packetsize) { return (((logical_endpoint & 0xf) >= UDC_MAX_ENDPOINTS) || (packetsize > 64)) ? 0 : (logical_endpoint & 0xf); } /** * udc_set_ep - setup endpoint * @ep: * @endpoint: * * Associate a physical endpoint with endpoint_instance */ void udc_setup_ep (struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint) { if (ep < UDC_MAX_ENDPOINTS) { ep_endpoints[ep] = endpoint; // ep0 if (ep == 0) { } // IN else if (endpoint->endpoint_address & 0x80) { } // OUT else if (endpoint->endpoint_address) { usbd_fill_rcv (device, endpoint, 5); endpoint->rcv_urb = first_urb_detached (&endpoint->rdy); } } } /** * udc_disable_ep - disable endpoint * @ep: * * Disable specified endpoint */ void udc_disable_ep (unsigned int ep) { if (ep < UDC_MAX_ENDPOINTS) { struct usb_endpoint_instance *endpoint; if ((endpoint = ep_endpoints[ep])) { ep_endpoints[ep] = NULL; usbd_flush_ep (endpoint); } } } /* ********************************************************************************************* */ /** * udc_connected - is the USB cable connected * * Return non-zeron if cable is connected. */ int udc_connected () { return 1; } /** * udc_connect - enable pullup resistor * * Turn on the USB connection by enabling the pullup resistor. */ void udc_connect (void) { } /** * udc_disconnect - disable pullup resistor * * Turn off the USB connection by disabling the pullup resistor. */ void udc_disconnect (void) { } #if 0 /** * udc_int_hndlr_cable - interrupt handler for cable */ static void udc_int_hndlr_cable (int irq, void *dev_id, struct pt_regs *regs) { } #endif /* ********************************************************************************************* */ /** * udc_enable_interrupts - enable interrupts * * Switch on UDC interrupts. * */ void udc_all_interrupts (struct usb_device_instance *device) { printk (KERN_DEBUG "udc_enable_interrupts:\n"); // set interrupt mask } /** * udc_suspended_interrupts - enable suspended interrupts * * Switch on only UDC resume interrupt. * */ void udc_suspended_interrupts (struct usb_device_instance *device) { printk (KERN_DEBUG "udc_enable_interrupts:\n"); // set interrupt mask } /** * udc_disable_interrupts - disable interrupts. * * switch off interrupts */ void udc_disable_interrupts (struct usb_device_instance *device) { printk (KERN_DEBUG "udc_disable_interrupts:\n"); // reset interrupt mask } /* ********************************************************************************************* */ /** * udc_ep0_packetsize - return ep0 packetsize */ int udc_ep0_packetsize (void) { return EP0_PACKETSIZE; } /** * udc_enable - enable the UDC * * Switch on the UDC */ void udc_enable (struct usb_device_instance *device) { printk (KERN_DEBUG "\n"); printk (KERN_DEBUG "udc_enable: device: %p\n", device); // save the device structure pointer udc_device = device; // ep0 urb ep0_urb.device = device; usbd_alloc_urb_data (&ep0_urb, 512); // enable UDC } /** * udc_disable - disable the UDC * * Switch off the UDC */ void udc_disable (void) { printk (KERN_DEBUG "************************* udc_disable:\n"); // disable UDC // reset device pointer udc_device = NULL; // ep0 urb kfree (ep0_urb.buffer); } /** * udc_startup - allow udc code to do any additional startup */ void udc_startup_events (struct usb_device_instance *device) { usbd_device_event (device, DEVICE_INIT, 0); usbd_device_event (device, DEVICE_CREATE, 0); usbd_device_event (device, DEVICE_HUB_CONFIGURED, 0); usbd_device_event (device, DEVICE_RESET, 0); // XXX should be done from device event } /* ********************************************************************************************* */ /** * udc_name - return name of USB Device Controller */ char *udc_name (void) { return UDC_NAME; } /** * udc_request_udc_irq - request UDC interrupt * * Return non-zero if not successful. */ int udc_request_udc_irq () { #ifdef XXXX_UDC_IRQ // request IRQ and IO region if (request_irq (XXXX_UDC_IRQ, int_hndlr, SA_INTERRUPT | SA_SAMPLE_RANDOM, UDC_NAME " USBD Bus Interface", NULL) != 0) { printk (KERN_DEBUG "usb_ctl: Couldn't request USB irq\n"); return -EINVAL; } #endif return 0; } /** * udc_request_cable_irq - request Cable interrupt * * Return non-zero if not successful. */ int udc_request_cable_irq () { #ifdef XXXX_CABLE_IRQ // request IRQ and IO region if (request_irq (XXXX_CABLE_IRQ, int_hndlr, SA_INTERRUPT | SA_SAMPLE_RANDOM, UDC_NAME " Cable", NULL) != 0) { printk (KERN_DEBUG "usb_ctl: Couldn't request USB irq\n"); return -EINVAL; } #endif return 0; } /** * udc_request_udc_io - request UDC io region * * Return non-zero if not successful. */ int udc_request_io () { #if defined(XXXX_ADDR) && defined(XXXX_ADDR_SIZE) // reserve io { unsigned long flags; local_irq_save (flags); if (check_region (XXXX_ADDR, XXXX_ADDR_SIZE)) { return -EINVAL; } request_region (XXXX_ADDR, 0x04, UDC_NAME " USBD Bus Interface"); local_irq_restore (flags); } #endif return 0; } /** * udc_release_udc_irq - release UDC irq */ void udc_release_udc_irq () { #ifdef XXXX_IRQ free_irq (XXXX_UDC_IRQ, NULL); #endif } /** * udc_release_cable_irq - release Cable irq */ void udc_release_cable_irq () { #ifdef XXXX_IRQ free_irq (XXXX_CABLE_IRQ, NULL); #endif } /** * udc_release_release_io - release UDC io region */ void udc_release_io () { #if defined(XXXX_ADDR) && defined(XXXX_ADDR_SIZE) release_region (XXXX_ADDR, XXXX_ADDR_SIZE); #endif } /** * udc_regs - dump registers * * Dump registers with printk */ void udc_regs (void) { printk ("\n"); }