diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2002-04-04 18:53:38 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2002-04-04 18:53:38 -0800 |
| commit | dff4eb9d31108f3028a4aaa1a19096a29932afb7 (patch) | |
| tree | ac99bc5dbe61c04fa92d5c912bcbb635eb5fca45 /drivers/usb/class | |
| parent | 03943afd2cede3e02cd89fbb3cb518692e4a77be (diff) | |
USB
moved class/storage/ back to storage/
created input/
orderd the makefiles and config.in menus better.
Diffstat (limited to 'drivers/usb/class')
39 files changed, 5 insertions, 17297 deletions
diff --git a/drivers/usb/class/Config.in b/drivers/usb/class/Config.in index 4f607b443e8e..94fedd1f9c30 100644 --- a/drivers/usb/class/Config.in +++ b/drivers/usb/class/Config.in @@ -4,44 +4,16 @@ comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL -if [ "$CONFIG_SCSI" = "n" ]; then - comment ' SCSI support is needed for USB Storage' -fi -dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI - dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE - dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE - dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE - dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE - dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB - dep_tristate ' USB CDC Ethernet support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB - -comment 'USB Human Interface Devices (HID)' -dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB -if [ "$CONFIG_INPUT" = "n" ]; then - comment ' Input core support is needed for USB HID input layer or HIDBP support' -fi -dep_mbool ' HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID -dep_mbool ' /dev/hiddev raw HID device support' CONFIG_USB_HIDDEV $CONFIG_USB_HID +dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB +dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB -if [ "$CONFIG_USB_HID" != "y" ]; then - dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT - dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT -fi # Turn on CONFIG_USB_CLASS if any of the drivers are compiled into the kernel # to make our Makefile logic a bit simpler. -if [ "$CONFIG_USB_AUDIO" = "y" -o "$CONFIG_USB_BLUETOOTH" = "y" -o "$CONFIG_USB_ACM" = "y" ]; then - define_bool CONFIG_USB_CLASS y -fi -if [ "$CONFIG_USB_CDCETHER" = "y" -o "$CONFIG_USB_PRINTER" = "y" ]; then +if [ "$CONFIG_USB_AUDIO" = "y" -o "$CONFIG_USB_BLUETOOTH" = "y" ]; then define_bool CONFIG_USB_CLASS y fi -if [ "$CONFIG_USB_HID" = "y" -o "$CONFIG_USB_KBD" = "y" -o "$CONFIG_USB_MOUSE" = "y" ]; then +if [ "$CONFIG_USB_ACM" = "y" -o "$CONFIG_USB_PRINTER" = "y" ]; then define_bool CONFIG_USB_CLASS y fi diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile index da255cfc23fd..53443b76f9ef 100644 --- a/drivers/usb/class/Makefile +++ b/drivers/usb/class/Makefile @@ -1,28 +1,13 @@ # # Makefile for USB Class drivers +# (one step up from the misc category) # O_TARGET := usb-class.o -# Multipart objects. -hid-objs := hid-core.o - -# Optional parts of multipart objects. -ifeq ($(CONFIG_USB_HIDDEV),y) - hid-objs += hiddev.o -endif -ifeq ($(CONFIG_USB_HIDINPUT),y) - hid-objs += hid-input.o -endif - - obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_AUDIO) += audio.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o -obj-$(CONFIG_USB_CDCETHER) += cdc-ether.o -obj-$(CONFIG_USB_HID) += hid.o -obj-$(CONFIG_USB_KBD) += usbkbd.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_PRINTER) += printer.o diff --git a/drivers/usb/class/cdc-ether.c b/drivers/usb/class/cdc-ether.c deleted file mode 100644 index 3b41f2a445dc..000000000000 --- a/drivers/usb/class/cdc-ether.c +++ /dev/null @@ -1,1365 +0,0 @@ -// Portions of this file taken from -// Petko Manolov - Petkan (petkan@dce.bg) -// from his driver pegasus.c - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/usb.h> -#include <linux/module.h> -#include "cdc-ether.h" - -static const char *version = __FILE__ ": v0.98.5 22 Sep 2001 Brad Hards and another"; - -/* Take any CDC device, and sort it out in probe() */ -static struct usb_device_id CDCEther_ids[] = { - { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) }, - { } /* Terminating null entry */ -}; - -/* - * module parameter that provides an alternate upper limit on the - * number of multicast filters we use, with a default to use all - * the filters available to us. Note that the actual number used - * is the lesser of this parameter and the number returned in the - * descriptor for the particular device. See Table 41 of the CDC - * spec for more info on the descriptor limit. - */ -static int multicast_filter_limit = 32767; - - -////////////////////////////////////////////////////////////////////////////// -// Callback routines from USB device ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static void read_bulk_callback( struct urb *urb ) -{ - ether_dev_t *ether_dev = urb->context; - struct net_device *net; - int count = urb->actual_length, res; - struct sk_buff *skb; - - // Sanity check - if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) { - dbg("BULK IN callback but driver is not active!"); - return; - } - - net = ether_dev->net; - if ( !netif_device_present(net) ) { - // Somebody killed our network interface... - return; - } - - if ( ether_dev->flags & CDC_ETHER_RX_BUSY ) { - // Are we already trying to receive a frame??? - ether_dev->stats.rx_errors++; - dbg("ether_dev Rx busy"); - return; - } - - // We are busy, leave us alone! - ether_dev->flags |= CDC_ETHER_RX_BUSY; - - switch ( urb->status ) { - case 0: - break; - case -ETIMEDOUT: - dbg( "no repsonse in BULK IN" ); - ether_dev->flags &= ~CDC_ETHER_RX_BUSY; - break; - default: - dbg( "%s: RX status %d", net->name, urb->status ); - goto goon; - } - - // Check to make sure we got some data... - if ( !count ) { - // We got no data!!! - goto goon; - } - - // Tell the kernel we want some memory - if ( !(skb = dev_alloc_skb(count)) ) { - // We got no receive buffer. - goto goon; - } - - // Here's where it came from - skb->dev = net; - - // Now we copy it over - eth_copy_and_sum(skb, ether_dev->rx_buff, count, 0); - - // Not sure - skb_put(skb, count); - // Not sure here either - skb->protocol = eth_type_trans(skb, net); - - // Ship it off to the kernel - netif_rx(skb); - - // update out statistics - ether_dev->stats.rx_packets++; - ether_dev->stats.rx_bytes += count; - -goon: - // Prep the USB to wait for another frame - FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb, - usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in), - ether_dev->rx_buff, ether_dev->wMaxSegmentSize, - read_bulk_callback, ether_dev ); - - // Give this to the USB subsystem so it can tell us - // when more data arrives. - if ( (res = usb_submit_urb(ether_dev->rx_urb, GFP_KERNEL)) ) { - warn( __FUNCTION__ " failed submint rx_urb %d", res); - } - - // We are no longer busy, show us the frames!!! - ether_dev->flags &= ~CDC_ETHER_RX_BUSY; -} - -static void write_bulk_callback( struct urb *urb ) -{ - ether_dev_t *ether_dev = urb->context; - - // Sanity check - if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) { - // We are insane!!! - err( "write_bulk_callback: device not running" ); - return; - } - - // Do we still have a valid kernel network device? - if ( !netif_device_present(ether_dev->net) ) { - // Someone killed our network interface. - err( "write_bulk_callback: net device not present" ); - return; - } - - // Hmm... What on Earth could have happened??? - if ( urb->status ) { - info("%s: TX status %d", ether_dev->net->name, urb->status); - } - - // Update the network interface and tell it we are - // ready for another frame - ether_dev->net->trans_start = jiffies; - netif_wake_queue( ether_dev->net ); -} - -//static void intr_callback( struct urb *urb ) -//{ -// ether_dev_t *ether_dev = urb->context; -// struct net_device *net; -// __u8 *d; -// -// if ( !ether_dev ) -// return; -// -// switch ( urb->status ) { -// case 0: -// break; -// case -ENOENT: -// return; -// default: -// info("intr status %d", urb->status); -// } -// -// d = urb->transfer_buffer; -// net = ether_dev->net; -// if ( d[0] & 0xfc ) { -// ether_dev->stats.tx_errors++; -// if ( d[0] & TX_UNDERRUN ) -// ether_dev->stats.tx_fifo_errors++; -// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) ) -// ether_dev->stats.tx_aborted_errors++; -// if ( d[0] & LATE_COL ) -// ether_dev->stats.tx_window_errors++; -// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) ) -// ether_dev->stats.tx_carrier_errors++; -// } -//} - -////////////////////////////////////////////////////////////////////////////// -// Routines for turning net traffic on and off on the USB side /////////////// -////////////////////////////////////////////////////////////////////////////// - -static inline int enable_net_traffic( ether_dev_t *ether_dev ) -{ - struct usb_device *usb = ether_dev->usb; - - // Here would be the time to set the data interface to the configuration where - // it has two endpoints that use a protocol we can understand. - - if (usb_set_interface( usb, - ether_dev->data_bInterfaceNumber, - ether_dev->data_bAlternateSetting_with_traffic ) ) { - err("usb_set_interface() failed" ); - err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber); - err("To alternate setting %d", ether_dev->data_bAlternateSetting_with_traffic); - return -1; - } - return 0; -} - -static inline void disable_net_traffic( ether_dev_t *ether_dev ) -{ - // The thing to do is to set the data interface to the alternate setting that has - // no endpoints. This is what the spec suggests. - - if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) { - if (usb_set_interface( ether_dev->usb, - ether_dev->data_bInterfaceNumber, - ether_dev->data_bAlternateSetting_without_traffic ) ) { - err("usb_set_interface() failed"); - } - } else { - // Some devices just may not support this... - warn("No way to disable net traffic"); - } -} - -////////////////////////////////////////////////////////////////////////////// -// Callback routines for kernel Ethernet Device ////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static void CDCEther_tx_timeout( struct net_device *net ) -{ - ether_dev_t *ether_dev = net->priv; - - // Sanity check - if ( !ether_dev ) { - // Seems to be a case of insanity here - return; - } - - // Tell syslog we are hosed. - warn("%s: Tx timed out.", net->name); - - // Tear the waiting frame off the list - ether_dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK; - usb_unlink_urb( ether_dev->tx_urb ); - - // Update statistics - ether_dev->stats.tx_errors++; -} - -static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net ) -{ - ether_dev_t *ether_dev = net->priv; - int count; - int res; - - // If we are told to transmit an ethernet frame that fits EXACTLY - // into an integer number of USB packets, we force it to send one - // more byte so the device will get a runt USB packet signalling the - // end of the ethernet frame - if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) { - // It was not an exact multiple - // no need to add anything extra - count = skb->len; - } else { - // Add one to make it NOT an exact multiple - count = skb->len + 1; - } - - // Tell the kernel, "No more frames 'til we are done - // with this one.' - netif_stop_queue( net ); - - // Copy it from kernel memory to OUR memory - memcpy(ether_dev->tx_buff, skb->data, skb->len); - - // Fill in the URB for shipping it out. - FILL_BULK_URB( ether_dev->tx_urb, ether_dev->usb, - usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out), - ether_dev->tx_buff, ether_dev->wMaxSegmentSize, - write_bulk_callback, ether_dev ); - - // Tell the URB how much it will be transporting today - ether_dev->tx_urb->transfer_buffer_length = count; - - // Send the URB on its merry way. - if ((res = usb_submit_urb(ether_dev->tx_urb, GFP_KERNEL))) { - // Hmm... It didn't go. Tell someone... - warn("failed tx_urb %d", res); - // update some stats... - ether_dev->stats.tx_errors++; - // and tell the kernel to give us another. - // Maybe we'll get it right next time. - netif_start_queue( net ); - } else { - // Okay, it went out. - // Update statistics - ether_dev->stats.tx_packets++; - ether_dev->stats.tx_bytes += skb->len; - // And tell the kernel when the last transmit occurred. - net->trans_start = jiffies; - } - - // We are done with the kernel's memory - dev_kfree_skb(skb); - - // We are done here. - return 0; -} - -static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net ) -{ - // Easy enough! - return &((ether_dev_t *)net->priv)->stats; -} - -static int CDCEther_open(struct net_device *net) -{ - ether_dev_t *ether_dev = (ether_dev_t *)net->priv; - int res; - - // Turn on the USB and let the packets flow!!! - if ( (res = enable_net_traffic( ether_dev )) ) { - err( __FUNCTION__ "can't enable_net_traffic() - %d", res ); - return -EIO; - } - - // Prep a receive URB - FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb, - usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in), - ether_dev->rx_buff, ether_dev->wMaxSegmentSize, - read_bulk_callback, ether_dev ); - - // Put it out there so the device can send us stuff - if ( (res = usb_submit_urb(ether_dev->rx_urb, GFP_KERNEL)) ) - { - // Hmm... Okay... - warn( __FUNCTION__ " failed rx_urb %d", res ); - } - - // Tell the kernel we are ready to start receiving from it - netif_start_queue( net ); - - // We are up and running. - ether_dev->flags |= CDC_ETHER_RUNNING; - - // Let's get ready to move frames!!! - return 0; -} - -static int CDCEther_close( struct net_device *net ) -{ - ether_dev_t *ether_dev = net->priv; - - // We are no longer running. - ether_dev->flags &= ~CDC_ETHER_RUNNING; - - // Tell the kernel to stop sending us stuff - netif_stop_queue( net ); - - // If we are not already unplugged, turn off USB - // traffic - if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) { - disable_net_traffic( ether_dev ); - } - - // We don't need the URBs anymore. - usb_unlink_urb( ether_dev->rx_urb ); - usb_unlink_urb( ether_dev->tx_urb ); - usb_unlink_urb( ether_dev->intr_urb ); - - // That's it. I'm done. - return 0; -} - -static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) -{ - //__u16 *data = (__u16 *)&rq->ifr_data; - //ether_dev_t *ether_dev = net->priv; - - // No support here yet. - // Do we need support??? - switch(cmd) { - case SIOCDEVPRIVATE: - return -EOPNOTSUPP; - case SIOCDEVPRIVATE+1: - return -EOPNOTSUPP; - case SIOCDEVPRIVATE+2: - //return 0; - return -EOPNOTSUPP; - default: - return -EOPNOTSUPP; - } -} - -static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev) -{ - usb_control_msg(ether_dev->usb, - usb_sndctrlpipe(ether_dev->usb, 0), - SET_ETHERNET_PACKET_FILTER, /* request */ - USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */ - cpu_to_le16(ether_dev->mode_flags), /* value */ - cpu_to_le16((u16)ether_dev->comm_interface), /* index */ - NULL, - 0, /* size */ - HZ); /* timeout */ -} - - -static void CDCEther_set_multicast( struct net_device *net ) -{ - ether_dev_t *ether_dev = net->priv; - int i; - __u8 *buff; - - - // Tell the kernel to stop sending us frames while we get this - // all set up. - netif_stop_queue(net); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (net->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - info( "%s: Promiscuous mode enabled", net->name); - ether_dev->mode_flags = MODE_FLAG_PROMISCUOUS | - MODE_FLAG_ALL_MULTICAST | - MODE_FLAG_DIRECTED | - MODE_FLAG_BROADCAST | - MODE_FLAG_MULTICAST; - } else if (net->mc_count > ether_dev->wNumberMCFilters) { - /* Too many to filter perfectly -- accept all multicasts. */ - info("%s: set too many MC filters, using allmulti", net->name); - ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | - MODE_FLAG_DIRECTED | - MODE_FLAG_BROADCAST | - MODE_FLAG_MULTICAST; - } else if (net->flags & IFF_ALLMULTI) { - /* Filter in software */ - info("%s: using allmulti", net->name); - ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | - MODE_FLAG_DIRECTED | - MODE_FLAG_BROADCAST | - MODE_FLAG_MULTICAST; - } else { - /* do multicast filtering in hardware */ - struct dev_mc_list *mclist; - info("%s: set multicast filters", net->name); - ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | - MODE_FLAG_DIRECTED | - MODE_FLAG_BROADCAST | - MODE_FLAG_MULTICAST; - buff = kmalloc(6 * net->mc_count, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - for (i = 0, mclist = net->mc_list; - mclist && i < net->mc_count; - i++, mclist = mclist->next) { - memcpy(&mclist->dmi_addr, &buff[i * 6], 6); - } -#if 0 - usb_control_msg(ether_dev->usb, - usb_sndctrlpipe(ether_dev->usb, 0), - SET_ETHERNET_MULTICAST_FILTER, /* request */ - USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */ - cpu_to_le16(net->mc_count), /* value */ - cpu_to_le16((u16)ether_dev->comm_interface), /* index */ - buff, - (6* net->mc_count), /* size */ - HZ); /* timeout */ -#endif - kfree(buff); - } - -#if 0 - CDC_SetEthernetPacketFilter(ether_dev); -#endif - // Tell the kernel to start giving frames to us again. - netif_wake_queue(net); -} - -////////////////////////////////////////////////////////////////////////////// -// Routines used to parse out the Functional Descriptors ///////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int parse_header_functional_descriptor( int *bFunctionLength, - int bDescriptorType, - int bDescriptorSubtype, - unsigned char *data, - ether_dev_t *ether_dev, - int *requirements ) -{ - // Check to make sure we haven't seen one of these already. - if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) { - err( "Multiple Header Functional Descriptors found." ); - return -1; - } - - // Is it the right size??? - if (*bFunctionLength != 5) { - info( "Invalid length in Header Functional Descriptor" ); - // This is a hack to get around a particular device (NO NAMES) - // It has this function length set to the length of the - // whole class-specific descriptor - *bFunctionLength = 5; - } - - // Nothing extremely useful here. - // We'll keep it for posterity - ether_dev->bcdCDC = data[0] + (data[1] << 8); - dbg( "Found Header descriptor, CDC version %x", ether_dev->bcdCDC); - - // We've seen one of these - *requirements &= ~REQ_HDR_FUNC_DESCR; - - // It's all good. - return 0; -} - -static int parse_union_functional_descriptor( int *bFunctionLength, - int bDescriptorType, - int bDescriptorSubtype, - unsigned char *data, - ether_dev_t *ether_dev, - int *requirements ) -{ - // Check to make sure we haven't seen one of these already. - if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) { - err( "Multiple Union Functional Descriptors found." ); - return -1; - } - - // Is it the right size? - if (*bFunctionLength != 5) { - // It is NOT the size we expected. - err( "Unsupported length in Union Functional Descriptor" ); - return -1; - } - - // Sanity check of sorts - if (ether_dev->comm_interface != data[0]) { - // This tells us that we are chasing the wrong comm - // interface or we are crazy or something else weird. - if (ether_dev->comm_interface == data[1]) { - info( "Probably broken Union descriptor, fudging data interface" ); - // We'll need this in a few microseconds, - // so guess here, and hope for the best - ether_dev->data_interface = data[0]; - } else { - err( "Union Functional Descriptor is broken beyond repair" ); - return -1; - } - } else{ // Descriptor is OK - // We'll need this in a few microseconds! - ether_dev->data_interface = data[1]; - } - - // We've seen one of these now. - *requirements &= ~REQ_UNION_FUNC_DESCR; - - // Done - return 0; -} - -static int parse_ethernet_functional_descriptor( int *bFunctionLength, - int bDescriptorType, - int bDescriptorSubtype, - unsigned char *data, - ether_dev_t *ether_dev, - int *requirements ) -{ - // Check to make sure we haven't seen one of these already. - if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) { - err( "Multiple Ethernet Functional Descriptors found." ); - return -1; - } - - // Is it the right size? - if (*bFunctionLength != 13) { - err( "Invalid length in Ethernet Networking Functional Descriptor" ); - return -1; - } - - // Lots of goodies from this one. They are all important. - ether_dev->iMACAddress = data[0]; - ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24); - ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8); - ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8)) & 0x00007FFF; - if (ether_dev->wNumberMCFilters > multicast_filter_limit) { - ether_dev->wNumberMCFilters = multicast_filter_limit; - } - ether_dev->bNumberPowerFilters = data[9]; - - // We've seen one of these now. - *requirements &= ~REQ_ETH_FUNC_DESCR; - - // That's all she wrote. - return 0; -} - -static int parse_protocol_unit_functional_descriptor( int *bFunctionLength, - int bDescriptorType, - int bDescriptorSubtype, - unsigned char *data, - ether_dev_t *ether_dev, - int *requirements ) -{ - // There should only be one type if we are sane - if (bDescriptorType != CS_INTERFACE) { - info( "Invalid bDescriptorType found." ); - return -1; - } - - // The Subtype tells the tale. - switch (bDescriptorSubtype){ - case 0x00: // Header Functional Descriptor - return parse_header_functional_descriptor( bFunctionLength, - bDescriptorType, - bDescriptorSubtype, - data, - ether_dev, - requirements ); - break; - case 0x06: // Union Functional Descriptor - return parse_union_functional_descriptor( bFunctionLength, - bDescriptorType, - bDescriptorSubtype, - data, - ether_dev, - requirements ); - break; - case 0x0F: // Ethernet Networking Functional Descriptor - return parse_ethernet_functional_descriptor( bFunctionLength, - bDescriptorType, - bDescriptorSubtype, - data, - ether_dev, - requirements ); - break; - default: // We don't support this at this time... - // However that doesn't necessarily indicate an error. - dbg( "Unexpected header type %x:", bDescriptorSubtype ); - return 0; - } - // How did we get here??? - return -1; -} - -static int parse_ethernet_class_information( unsigned char *data, int length, ether_dev_t *ether_dev ) -{ - int loc = 0; - int rc; - int bFunctionLength; - int bDescriptorType; - int bDescriptorSubtype; - int requirements = REQUIREMENTS_TOTAL; - - // As long as there is something here, we will try to parse it - while (loc < length) { - // Length - bFunctionLength = data[loc]; - loc++; - - // Type - bDescriptorType = data[loc]; - loc++; - - // Subtype - bDescriptorSubtype = data[loc]; - loc++; - - // ship this off to be processed elsewhere. - rc = parse_protocol_unit_functional_descriptor( &bFunctionLength, - bDescriptorType, - bDescriptorSubtype, - &data[loc], - ether_dev, - &requirements ); - // Did it process okay? - if (rc) { - // Something was hosed somewhere. - // No need to continue; - err("Bad descriptor parsing: %x", rc ); - return -1; - } - // We have already taken three bytes. - loc += (bFunctionLength - 3); - } - // Check to see if we got everything we need. - if (requirements) { - // We missed some of the requirements... - err( "Not all required functional descriptors present 0x%08X", requirements ); - return -1; - } - // We got everything. - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -// Routine to check for the existence of the Functional Descriptors ////////// -////////////////////////////////////////////////////////////////////////////// - -static int find_and_parse_ethernet_class_information( struct usb_device *device, ether_dev_t *ether_dev ) -{ - struct usb_config_descriptor *conf = NULL; - struct usb_interface *comm_intf_group = NULL; - struct usb_interface_descriptor *comm_intf = NULL; - int rc = -1; - // The assumption here is that find_ethernet_comm_interface - // and find_valid_configuration - // have already filled in the information about where to find - // the a valid commication interface. - - conf = &( device->config[ether_dev->configuration_num] ); - comm_intf_group = &( conf->interface[ether_dev->comm_interface] ); - comm_intf = &( comm_intf_group->altsetting[ether_dev->comm_interface_altset_num] ); - // Let's check and see if it has the extra information we need... - - if (comm_intf->extralen > 0) { - // This is where the information is SUPPOSED to be. - rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev ); - } else if (conf->extralen > 0) { - // This is a hack. The spec says it should be at the interface - // location checked above. However I have seen it here also. - // This is the same device that requires the functional descriptor hack above - warn( "Ethernet information found at device configuration. This is broken." ); - rc = parse_ethernet_class_information( conf->extra, conf->extralen, ether_dev ); - } else { - // I don't know where else to look. - warn( "No ethernet information found." ); - rc = -1; - } - return rc; -} - -////////////////////////////////////////////////////////////////////////////// -// Routines to verify the data interface ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int get_data_interface_endpoints( struct usb_device *device, ether_dev_t *ether_dev ) -{ - struct usb_config_descriptor *conf = NULL; - struct usb_interface *data_intf_group = NULL; - struct usb_interface_descriptor *data_intf = NULL; - - // Walk through and get to the data interface we are checking. - conf = &( device->config[ether_dev->configuration_num] ); - data_intf_group = &( conf->interface[ether_dev->data_interface] ); - data_intf = &( data_intf_group->altsetting[ether_dev->data_interface_altset_num_with_traffic] ); - - // Start out assuming we won't find anything we can use - ether_dev->data_ep_in = 0; - ether_dev->data_ep_out = 0; - - // If these are not BULK endpoints, we don't want them - if ( data_intf->endpoint[0].bmAttributes != 0x02 ) { - return -1; - } if ( data_intf->endpoint[1].bmAttributes != 0x02 ) { - return -1; - } - - // Check the first endpoint to see if it is IN or OUT - if ( data_intf->endpoint[0].bEndpointAddress & 0x80 ) { - // This endpoint is IN - ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F; - } else { - // This endpoint is OUT - ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F; - ether_dev->data_ep_out_size = data_intf->endpoint[0].wMaxPacketSize; - } - - // Check the second endpoint to see if it is IN or OUT - if ( data_intf->endpoint[1].bEndpointAddress & 0x80 ) { - // This endpoint is IN - ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F; - } else { - // This endpoint is OUT - ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F; - ether_dev->data_ep_out_size = data_intf->endpoint[1].wMaxPacketSize; - } - - // Now make sure we got both an IN and an OUT - if (ether_dev->data_ep_in && ether_dev->data_ep_out) { - // We did get both, we are in good shape... - info( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size ); - return 0; - } - return -1; -} - -static int verify_ethernet_data_interface( struct usb_device *device, ether_dev_t *ether_dev ) -{ - struct usb_config_descriptor *conf = NULL; - struct usb_interface *data_intf_group = NULL; - struct usb_interface_descriptor *data_intf = NULL; - int rc = -1; - int status; - int altset_num; - - // The assumption here is that parse_ethernet_class_information() - // and find_valid_configuration() - // have already filled in the information about where to find - // a data interface - conf = &( device->config[ether_dev->configuration_num] ); - data_intf_group = &( conf->interface[ether_dev->data_interface] ); - - // start out assuming we won't find what we are looking for. - ether_dev->data_interface_altset_num_with_traffic = -1; - ether_dev->data_bAlternateSetting_with_traffic = -1; - ether_dev->data_interface_altset_num_without_traffic = -1; - ether_dev->data_bAlternateSetting_without_traffic = -1; - - // Walk through every possible setting for this interface until - // we find what makes us happy. - for ( altset_num = 0; altset_num < data_intf_group->num_altsetting; altset_num++ ) { - data_intf = &( data_intf_group->altsetting[altset_num] ); - - // Is this a data interface we like? - if ( ( data_intf->bInterfaceClass == 0x0A ) - && ( data_intf->bInterfaceSubClass == 0x00 ) - && ( data_intf->bInterfaceProtocol == 0x00 ) ) { - if ( data_intf->bNumEndpoints == 2 ) { - // We are required to have one of these. - // An interface with 2 endpoints to send Ethernet traffic back and forth - // It actually may be possible that the device might only - // communicate in a vendor specific manner. - // That would not be very nice. - // We can add that one later. - ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; - ether_dev->data_interface_altset_num_with_traffic = altset_num; - ether_dev->data_bAlternateSetting_with_traffic = data_intf->bAlternateSetting; - status = get_data_interface_endpoints( device, ether_dev ); - if (!status) { - rc = 0; - } - } - if ( data_intf->bNumEndpoints == 0 ) { - // According to the spec we are SUPPOSED to have one of these - // In fact the device is supposed to come up in this state. - // However, I have seen a device that did not have such an interface. - // So it must be just optional for our driver... - ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; - ether_dev->data_interface_altset_num_without_traffic = altset_num; - ether_dev->data_bAlternateSetting_without_traffic = data_intf->bAlternateSetting; - } - } - } - return rc; -} - -////////////////////////////////////////////////////////////////////////////// -// Routine to find a communication interface ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int find_ethernet_comm_interface( struct usb_device *device, ether_dev_t *ether_dev ) -{ - struct usb_config_descriptor *conf = NULL; - struct usb_interface *comm_intf_group = NULL; - struct usb_interface_descriptor *comm_intf = NULL; - int intf_num; - int altset_num; - int rc; - - conf = &( device->config[ether_dev->configuration_num] ); - - // We need to check and see if any of these interfaces are something we want. - // Walk through each interface one at a time - for ( intf_num = 0; intf_num < conf->bNumInterfaces; intf_num++ ) { - comm_intf_group = &( conf->interface[intf_num] ); - // Now for each of those interfaces, check every possible - // alternate setting. - for ( altset_num = 0; altset_num < comm_intf_group->num_altsetting; altset_num++ ) { - comm_intf = &( comm_intf_group->altsetting[altset_num] ); - - // Is this a communication class of interface of the - // ethernet subclass variety. - if ( ( comm_intf->bInterfaceClass == 0x02 ) - && ( comm_intf->bInterfaceSubClass == 0x06 ) - && ( comm_intf->bInterfaceProtocol == 0x00 ) ) { - if ( comm_intf->bNumEndpoints == 1 ) { - // Good, we found one, we will try this one - // Fill in the structure... - ether_dev->comm_interface = intf_num; - ether_dev->comm_bInterfaceNumber = comm_intf->bInterfaceNumber; - ether_dev->comm_interface_altset_num = altset_num; - ether_dev->comm_bAlternateSetting = comm_intf->bAlternateSetting; - - // Look for the Ethernet Functional Descriptors - rc = find_and_parse_ethernet_class_information( device, ether_dev ); - if (rc) { - // Nope this was no good after all. - continue; - } - - // Check that we really can talk to the data - // interface - // This includes # of endpoints, protocols, - // etc. - rc = verify_ethernet_data_interface( device, ether_dev ); - if (rc) { - // We got something we didn't like - continue; - } - // This communication interface seems to give us everything - // we require. We have all the ethernet info we need. - // Let's get out of here and go home right now. - return 0; - } else { - // bNumEndPoints != 1 - // We found an interface that had the wrong number of - // endpoints but would have otherwise been okay - } // end bNumEndpoints check. - } // end interface specifics check. - } // end for altset_num - } // end for intf_num - return -1; -} - -////////////////////////////////////////////////////////////////////////////// -// Routine to go through all configurations and find one that //////////////// -// is an Ethernet Networking Device ////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int find_valid_configuration( struct usb_device *device, ether_dev_t *ether_dev ) -{ - struct usb_config_descriptor *conf = NULL; - int conf_num; - int rc; - - // We will try each and every possible configuration - for ( conf_num = 0; conf_num < device->descriptor.bNumConfigurations; conf_num++ ) { - conf = &( device->config[conf_num] ); - - // Our first requirement : 2 interfaces - if ( conf->bNumInterfaces != 2 ) { - // I currently don't know how to handle devices with any number of interfaces - // other than 2. - continue; - } - - // This one passed our first check, fill in some - // useful data - ether_dev->configuration_num = conf_num; - ether_dev->bConfigurationValue = conf->bConfigurationValue; - - // Now run it through the ringers and see what comes - // out the other side. - rc = find_ethernet_comm_interface( device, ether_dev ); - - // Check if we found an ethernet Communcation Device - if ( !rc ) { - // We found one. - return 0; - } - } - // None of the configurations suited us. - return -1; -} - -////////////////////////////////////////////////////////////////////////////// -// Routine that checks a given configuration to see if any driver //////////// -// has claimed any of the devices interfaces ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int check_for_claimed_interfaces( struct usb_config_descriptor *config ) -{ - struct usb_interface *comm_intf_group; - int intf_num; - - // Go through all the interfaces and make sure none are - // claimed by anybody else. - for ( intf_num = 0; intf_num < config->bNumInterfaces; intf_num++ ) { - comm_intf_group = &( config->interface[intf_num] ); - if ( usb_interface_claimed( comm_intf_group ) ) { - // Somebody has beat us to this guy. - // We can't change the configuration out from underneath of whoever - // is using this device, so we will go ahead and give up. - return -1; - } - } - // We made it all the way through. - // I guess no one has claimed any of these interfaces. - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -// Routines to ask for and set the kernel network interface's MAC address //// -// Used by driver's probe routine //////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static inline unsigned char hex2dec( unsigned char digit ) -{ - // Is there a standard way to do this??? - // I have written this code TOO MANY times. - if ( (digit >= '0') && (digit <= '9') ) { - return (digit - '0'); - } - if ( (digit >= 'a') && (digit <= 'f') ) { - return (digit - 'a' + 10); - } - if ( (digit >= 'A') && (digit <= 'F') ) { - return (digit - 'A' + 10); - } - return 0; -} - -static void set_ethernet_addr( ether_dev_t *ether_dev ) -{ - unsigned char mac_addr[6]; - int i; - int len; - unsigned char buffer[13]; - - // Let's assume we don't get anything... - mac_addr[0] = 0x00; - mac_addr[1] = 0x00; - mac_addr[2] = 0x00; - mac_addr[3] = 0x00; - mac_addr[4] = 0x00; - mac_addr[5] = 0x00; - - // Let's ask the device... - len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13); - - // Sanity check! - if (len != 12) { - // You gotta love failing sanity checks - err("Attempting to get MAC address returned %d bytes", len); - return; - } - - // Fill in the mac_addr - for (i = 0; i < 6; i++) { - mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] ); - } - - // Now copy it over to the kernel's network driver. - memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) ); -} - -////////////////////////////////////////////////////////////////////////////// -// Routine to print to syslog information about the driver /////////////////// -// Used by driver's probe routine //////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -void log_device_info(ether_dev_t *ether_dev) -{ - int len; - int string_num; - unsigned char manu[256]; - unsigned char prod[256]; - unsigned char sern[256]; - unsigned char *mac_addr; - - // Default empty strings in case we don't find a real one - manu[0] = 0x00; - prod[0] = 0x00; - sern[0] = 0x00; - - // Try to get the device Manufacturer - string_num = ether_dev->usb->descriptor.iManufacturer; - if (string_num) { - // Put it into its buffer - len = usb_string(ether_dev->usb, string_num, manu, 255); - // Just to be safe - manu[len] = 0x00; - } - - // Try to get the device Product Name - string_num = ether_dev->usb->descriptor.iProduct; - if (string_num) { - // Put it into its buffer - len = usb_string(ether_dev->usb, string_num, prod, 255); - // Just to be safe - prod[len] = 0x00; - } - - // Try to get the device Serial Number - string_num = ether_dev->usb->descriptor.iSerialNumber; - if (string_num) { - // Put it into its buffer - len = usb_string(ether_dev->usb, string_num, sern, 255); - // Just to be safe - sern[len] = 0x00; - } - - // This makes it easier for us to print - mac_addr = ether_dev->net->dev_addr; - - // Now send everything we found to the syslog - info( "%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X", - ether_dev->net->name, manu, prod, sern, mac_addr[0], - mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], - mac_addr[5] ); -} - -/* Forward declaration */ -static struct usb_driver CDCEther_driver ; - -////////////////////////////////////////////////////////////////////////////// -// Module's probe routine //////////////////////////////////////////////////// -// claims interfaces if they are for an Ethernet CDC ///////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct net_device *net; - ether_dev_t *ether_dev; - int rc; - - // First we should check the active configuration to see if - // any other driver has claimed any of the interfaces. - if ( check_for_claimed_interfaces( usb->actconfig ) ) { - // Someone has already put there grubby paws on this device. - // We don't want it now... - return NULL; - } - - // We might be finding a device we can use. - // We all go ahead and allocate our storage space. - // We need to because we have to start filling in the data that - // we are going to need later. - if(!(ether_dev = kmalloc(sizeof(ether_dev_t), GFP_KERNEL))) { - err("out of memory allocating device structure"); - return NULL; - } - - // Zero everything out. - memset(ether_dev, 0, sizeof(ether_dev_t)); - - ether_dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ether_dev->rx_urb) { - kfree(ether_dev); - return NULL; - } - ether_dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ether_dev->tx_urb) { - usb_free_urb(ether_dev->rx_urb); - kfree(ether_dev); - return NULL; - } - ether_dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ether_dev->intr_urb) { - usb_free_urb(ether_dev->tx_urb); - usb_free_urb(ether_dev->rx_urb); - kfree(ether_dev); - return NULL; - } - - // Let's see if we can find a configuration we can use. - rc = find_valid_configuration( usb, ether_dev ); - if (rc) { - // Nope we couldn't find one we liked. - // This device was not meant for us to control. - kfree( ether_dev ); - return NULL; - } - - // Now that we FOUND a configuration. let's try to make the - // device go into it. - if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) { - err("usb_set_configuration() failed"); - kfree( ether_dev ); - return NULL; - } - - // Now set the communication interface up as required. - if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) { - err("usb_set_interface() failed"); - kfree( ether_dev ); - return NULL; - } - - // Only turn traffic on right now if we must... - if (ether_dev->data_interface_altset_num_without_traffic >= 0) { - // We found an alternate setting for the data - // interface that allows us to turn off traffic. - // We should use it. - if (usb_set_interface( usb, - ether_dev->data_bInterfaceNumber, - ether_dev->data_bAlternateSetting_without_traffic)) { - err("usb_set_interface() failed"); - kfree( ether_dev ); - return NULL; - } - } else { - // We didn't find an alternate setting for the data - // interface that would let us turn off traffic. - // Oh well, let's go ahead and do what we must... - if (usb_set_interface( usb, - ether_dev->data_bInterfaceNumber, - ether_dev->data_bAlternateSetting_with_traffic)) { - err("usb_set_interface() failed"); - kfree( ether_dev ); - return NULL; - } - } - - // Now we need to get a kernel Ethernet interface. - net = init_etherdev( NULL, 0 ); - if ( !net ) { - // Hmm... The kernel is not sharing today... - // Fine, we didn't want it anyway... - err( "Unable to initialize ethernet device" ); - kfree( ether_dev ); - return NULL; - } - - // Now that we have an ethernet device, let's set it up - // (And I don't mean "set [it] up the bomb".) - net->priv = ether_dev; - SET_MODULE_OWNER(net); - net->open = CDCEther_open; - net->stop = CDCEther_close; - net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT; - net->tx_timeout = CDCEther_tx_timeout; // TX timeout function - net->do_ioctl = CDCEther_ioctl; - net->hard_start_xmit = CDCEther_start_xmit; - net->set_multicast_list = CDCEther_set_multicast; - net->get_stats = CDCEther_netdev_stats; - net->mtu = ether_dev->wMaxSegmentSize - 14; - - // We'll keep track of this information for later... - ether_dev->usb = usb; - ether_dev->net = net; - - // and don't forget the MAC address. - set_ethernet_addr( ether_dev ); - - // Send a message to syslog about what we are handling - log_device_info( ether_dev ); - - // I claim this interface to be a CDC Ethernet Networking device - usb_driver_claim_interface( &CDCEther_driver, - &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]), - ether_dev ); - // I claim this interface to be a CDC Ethernet Networking device - usb_driver_claim_interface( &CDCEther_driver, - &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]), - ether_dev ); - - // Does this REALLY do anything??? - usb_inc_dev_use( usb ); - - // TODO - last minute HACK - ether_dev->comm_ep_in = 5; - - // Okay, we are finally done... - return NULL; -} - - -////////////////////////////////////////////////////////////////////////////// -// Module's disconnect routine /////////////////////////////////////////////// -// Called when the driver is unloaded or the device is unplugged ///////////// -// (Whichever happens first assuming the driver suceeded at its probe) /////// -////////////////////////////////////////////////////////////////////////////// - -static void CDCEther_disconnect( struct usb_device *usb, void *ptr ) -{ - ether_dev_t *ether_dev = ptr; - - // Sanity check!!! - if ( !ether_dev || !ether_dev->usb ) { - // We failed. We are insane!!! - warn("unregistering non-existant device"); - return; - } - - // Make sure we fail the sanity check if we try this again. - ether_dev->usb = NULL; - - // It is possible that this function is called before - // the "close" function. - // This tells the close function we are already disconnected - ether_dev->flags |= CDC_ETHER_UNPLUG; - - // We don't need the network device any more - unregister_netdev( ether_dev->net ); - - // For sanity checks - ether_dev->net = NULL; - - // I ask again, does this do anything??? - usb_dec_dev_use( usb ); - - // We are done with this interface - usb_driver_release_interface( &CDCEther_driver, - &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) ); - - // We are done with this interface too - usb_driver_release_interface( &CDCEther_driver, - &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) ); - - // No more tied up kernel memory - usb_free_urb(ether_dev->intr_urb); - usb_free_urb(ether_dev->rx_urb); - usb_free_urb(ether_dev->rx_urb); - kfree( ether_dev ); - - // This does no good, but it looks nice! - ether_dev = NULL; -} - -////////////////////////////////////////////////////////////////////////////// -// Driver info /////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static struct usb_driver CDCEther_driver = { - name: "CDCEther", - probe: CDCEther_probe, - disconnect: CDCEther_disconnect, - id_table: CDCEther_ids, -}; - -////////////////////////////////////////////////////////////////////////////// -// init and exit routines called when driver is installed and uninstalled //// -////////////////////////////////////////////////////////////////////////////// - -int __init CDCEther_init(void) -{ - info( "%s", version ); - return usb_register( &CDCEther_driver ); -} - -void __exit CDCEther_exit(void) -{ - usb_deregister( &CDCEther_driver ); -} - -////////////////////////////////////////////////////////////////////////////// -// Module info /////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -module_init( CDCEther_init ); -module_exit( CDCEther_exit ); - -MODULE_AUTHOR("Brad Hards and another"); -MODULE_DESCRIPTION("USB CDC Ethernet driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM_DESC (multicast_filter_limit, "CDCEther maximum number of filtered multicast addresses"); - -MODULE_DEVICE_TABLE (usb, CDCEther_ids); - -////////////////////////////////////////////////////////////////////////////// -// End of file /////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// diff --git a/drivers/usb/class/cdc-ether.h b/drivers/usb/class/cdc-ether.h deleted file mode 100644 index e91c2115ac3a..000000000000 --- a/drivers/usb/class/cdc-ether.h +++ /dev/null @@ -1,98 +0,0 @@ -// Portions of this file taken from -// Petko Manolov - Petkan (petkan@dce.bg) -// from his driver pegasus.h - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#define CS_INTERFACE 0x24 - -#define CDC_ETHER_MAX_MTU 1536 - -#define CDC_ETHER_PRESENT 0x00000001 -#define CDC_ETHER_RUNNING 0x00000002 -#define CDC_ETHER_TX_BUSY 0x00000004 -#define CDC_ETHER_RX_BUSY 0x00000008 -#define CDC_ETHER_UNPLUG 0x00000040 - -#define CDC_ETHER_TX_TIMEOUT (HZ*10) - -#define TX_UNDERRUN 0x80 -#define EXCESSIVE_COL 0x40 -#define LATE_COL 0x20 -#define NO_CARRIER 0x10 -#define LOSS_CARRIER 0x08 -#define JABBER_TIMEOUT 0x04 - -#define CDC_ETHER_REQT_READ 0xc0 -#define CDC_ETHER_REQT_WRITE 0x40 -#define CDC_ETHER_REQ_GET_REGS 0xf0 -#define CDC_ETHER_REQ_SET_REGS 0xf1 -#define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS -#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) - -#define MODE_FLAG_PROMISCUOUS (1<<0) -#define MODE_FLAG_ALL_MULTICAST (1<<1) -#define MODE_FLAG_DIRECTED (1<<2) -#define MODE_FLAG_BROADCAST (1<<3) -#define MODE_FLAG_MULTICAST (1<<4) - -#define SET_ETHERNET_MULTICAST_FILTER 0x40 -#define SET_ETHERNET_PACKET_FILTER 0x43 - -typedef struct _ether_dev_t { - struct usb_device *usb; - struct net_device *net; - struct net_device_stats stats; - unsigned flags; - int configuration_num; - int bConfigurationValue; - int comm_interface; - int comm_bInterfaceNumber; - int comm_interface_altset_num; - int comm_bAlternateSetting; - int comm_ep_in; - int data_interface; - int data_bInterfaceNumber; - int data_interface_altset_num_with_traffic; - int data_bAlternateSetting_with_traffic; - int data_interface_altset_num_without_traffic; - int data_bAlternateSetting_without_traffic; - int data_ep_in; - int data_ep_out; - int data_ep_out_size; - __u16 bcdCDC; - __u8 iMACAddress; - __u32 bmEthernetStatistics; - __u16 wMaxSegmentSize; - __u16 mode_flags; - __u16 wNumberMCFilters; - __u8 bNumberPowerFilters; - int intr_interval; - struct urb *rx_urb, *tx_urb, *intr_urb; - unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]); - unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]); - unsigned char ALIGN(intr_buff[8]); -} ether_dev_t; - -#define REQ_HDR_FUNC_DESCR 0x0001 -#define REQ_UNION_FUNC_DESCR 0x0002 -#define REQ_ETH_FUNC_DESCR 0x0004 -#define REQUIREMENTS_TOTAL 0x0007 - - - diff --git a/drivers/usb/class/hid-core.c b/drivers/usb/class/hid-core.c deleted file mode 100644 index 245ad1a0b5af..000000000000 --- a/drivers/usb/class/hid-core.c +++ /dev/null @@ -1,1530 +0,0 @@ -/* - * $Id: hid-core.c,v 1.42 2002/01/27 00:22:46 vojtech Exp $ - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID support for Linux - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/list.h> -#include <linux/mm.h> -#include <linux/smp_lock.h> -#include <linux/spinlock.h> -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/input.h> - -#undef DEBUG -#undef DEBUG_DATA - -#include <linux/usb.h> - -#include "hid.h" -#include <linux/hiddev.h> - -/* - * Version Information - */ - -#define DRIVER_VERSION "v1.31" -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@ucw.cz>" -#define DRIVER_DESC "USB HID core driver" -#define DRIVER_LICENSE "GPL" - -static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", - "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; - -/* - * Register a new report for a device. - */ - -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) -{ - struct hid_report_enum *report_enum = device->report_enum + type; - struct hid_report *report; - - if (report_enum->report_id_hash[id]) - return report_enum->report_id_hash[id]; - - if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL))) - return NULL; - memset(report, 0, sizeof(struct hid_report)); - - if (id != 0) report_enum->numbered = 1; - - report->id = id; - report->type = type; - report->size = 0; - report->device = device; - report_enum->report_id_hash[id] = report; - - list_add_tail(&report->list, &report_enum->report_list); - - return report; -} - -/* - * Register a new field for this report. - */ - -static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) -{ - struct hid_field *field; - - if (report->maxfield == HID_MAX_FIELDS) { - dbg("too many fields in report"); - return NULL; - } - - if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned), GFP_KERNEL))) return NULL; - - memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned)); - - report->field[report->maxfield] = field; - field->usage = (struct hid_usage *)(field + 1); - field->value = (unsigned *)(field->usage + usages); - field->report = report; - field->index = report->maxfield++; - - return field; -} - -/* - * Open a collection. The type/usage is pushed on the stack. - */ - -static int open_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection; - unsigned usage; - - usage = parser->local.usage[0]; - - if (type == HID_COLLECTION_APPLICATION - && parser->device->maxapplication < HID_MAX_APPLICATIONS) - parser->device->application[parser->device->maxapplication++] = usage; - - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - dbg("collection stack overflow"); - return -1; - } - - collection = parser->collection_stack + parser->collection_stack_ptr++; - collection->type = type; - collection->usage = usage; - - return 0; -} - -/* - * Close a collection. - */ - -static int close_collection(struct hid_parser *parser) -{ - if (!parser->collection_stack_ptr) { - dbg("collection stack underflow"); - return -1; - } - parser->collection_stack_ptr--; - return 0; -} - -/* - * Climb up the stack, search for the specified collection type - * and return the usage. - */ - -static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) -{ - int n; - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->collection_stack[n].type == type) - return parser->collection_stack[n].usage; - return 0; /* we know nothing about this usage type */ -} - -/* - * Add a usage to the temporary parser table. - */ - -static int hid_add_usage(struct hid_parser *parser, unsigned usage) -{ - if (parser->local.usage_index >= HID_MAX_USAGES) { - dbg("usage index exceeded"); - return -1; - } - parser->local.usage[parser->local.usage_index++] = usage; - return 0; -} - -/* - * Register a new field for this report. - */ - -static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) -{ - struct hid_report *report; - struct hid_field *field; - int usages; - unsigned offset; - int i; - - if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { - dbg("hid_register_report failed"); - return -1; - } - - if (parser->global.logical_maximum <= parser->global.logical_minimum) { - dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); - return -1; - } - usages = parser->local.usage_index; - - offset = report->size; - report->size += parser->global.report_size * parser->global.report_count; - - if (usages == 0) - return 0; /* ignore padding fields */ - - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) - return 0; - - field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); - field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); - field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - - for (i = 0; i < usages; i++) - field->usage[i].hid = parser->local.usage[i]; - - field->maxusage = usages; - field->flags = flags; - field->report_offset = offset; - field->report_type = report_type; - field->report_size = parser->global.report_size; - field->report_count = parser->global.report_count; - field->logical_minimum = parser->global.logical_minimum; - field->logical_maximum = parser->global.logical_maximum; - field->physical_minimum = parser->global.physical_minimum; - field->physical_maximum = parser->global.physical_maximum; - field->unit_exponent = parser->global.unit_exponent; - field->unit = parser->global.unit; - - return 0; -} - -/* - * Read data value from item. - */ - -static __inline__ __u32 item_udata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.u8; - case 2: return item->data.u16; - case 4: return item->data.u32; - } - return 0; -} - -static __inline__ __s32 item_sdata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.s8; - case 2: return item->data.s16; - case 4: return item->data.s32; - } - return 0; -} - -/* - * Process a global item. - */ - -static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) -{ - switch (item->tag) { - - case HID_GLOBAL_ITEM_TAG_PUSH: - - if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - dbg("global enviroment stack overflow"); - return -1; - } - - memcpy(parser->global_stack + parser->global_stack_ptr++, - &parser->global, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_POP: - - if (!parser->global_stack_ptr) { - dbg("global enviroment stack underflow"); - return -1; - } - - memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, - sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - parser->global.usage_page = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - parser->global.logical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - if (parser->global.logical_minimum < 0) - parser->global.logical_maximum = item_sdata(item); - else - parser->global.logical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - parser->global.physical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - parser->global.unit_exponent = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT: - parser->global.unit = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - if ((parser->global.report_size = item_udata(item)) > 32) { - dbg("invalid report_size %d", parser->global.report_size); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { - dbg("invalid report_count %d", parser->global.report_count); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - if ((parser->global.report_id = item_udata(item)) == 0) { - dbg("report_id 0 is invalid"); - return -1; - } - return 0; - - default: - dbg("unknown global tag 0x%x", item->tag); - return -1; - } -} - -/* - * Process a local item. - */ - -static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - unsigned n; - - if (item->size == 0) { - dbg("item data expected for local item"); - return -1; - } - - data = item_udata(item); - - switch (item->tag) { - - case HID_LOCAL_ITEM_TAG_DELIMITER: - - if (data) { - /* - * We treat items before the first delimiter - * as global to all usage sets (branch 0). - * In the moment we process only these global - * items and the first delimiter set. - */ - if (parser->local.delimiter_depth != 0) { - dbg("nested delimiters"); - return -1; - } - parser->local.delimiter_depth++; - parser->local.delimiter_branch++; - } else { - if (parser->local.delimiter_depth < 1) { - dbg("bogus close delimiter"); - return -1; - } - parser->local.delimiter_depth--; - } - return 1; - - case HID_LOCAL_ITEM_TAG_USAGE: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); - - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - parser->local.usage_minimum = data; - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { - dbg("hid_add_usage failed\n"); - return -1; - } - return 0; - - default: - - dbg("unknown local item tag 0x%x", item->tag); - return 0; - } - return 0; -} - -/* - * Process a main item. - */ - -static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int ret; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 3); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - ret = close_collection(parser); - break; - case HID_MAIN_ITEM_TAG_INPUT: - ret = hid_add_field(parser, HID_INPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - ret = hid_add_field(parser, HID_FEATURE_REPORT, data); - break; - default: - dbg("unknown main item tag 0x%x", item->tag); - ret = 0; - } - - memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ - - return ret; -} - -/* - * Process a reserved item. - */ - -static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) -{ - dbg("reserved item type, tag 0x%x", item->tag); - return 0; -} - -/* - * Free a report and all registered fields. The field->usage and - * field->value table's are allocated behind the field, so we need - * only to free(field) itself. - */ - -static void hid_free_report(struct hid_report *report) -{ - unsigned n; - - for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); - kfree(report); -} - -/* - * Free a device structure, all reports, and all fields. - */ - -static void hid_free_device(struct hid_device *device) -{ - unsigned i,j; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - struct hid_report_enum *report_enum = device->report_enum + i; - - for (j = 0; j < 256; j++) { - struct hid_report *report = report_enum->report_id_hash[j]; - if (report) hid_free_report(report); - } - } - - if (device->rdesc) kfree(device->rdesc); -} - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) -{ - u8 b; - - if ((end - start) <= 0) - return NULL; - - b = *start++; - - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - - if (item->tag == HID_ITEM_TAG_LONG) { - - item->format = HID_ITEM_FORMAT_LONG; - - if ((end - start) < 2) - return NULL; - - item->size = *start++; - item->tag = *start++; - - if ((end - start) < item->size) - return NULL; - - item->data.longdata = start; - start += item->size; - return start; - } - - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - - switch (item->size) { - - case 0: - return start; - - case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; - - case 2: - if ((end - start) < 2) - return NULL; - item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++)); - return start; - - case 3: - item->size++; - if ((end - start) < 4) - return NULL; - item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++)); - return start; - } - - return NULL; -} - -/* - * Parse a report description into a hid_device structure. Reports are - * enumerated, fields are attached to these reports. - */ - -static struct hid_device *hid_parse_report(__u8 *start, unsigned size) -{ - struct hid_device *device; - struct hid_parser *parser; - struct hid_item item; - __u8 *end; - unsigned i; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_parser_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL))) - return NULL; - memset(device, 0, sizeof(struct hid_device)); - - for (i = 0; i < HID_REPORT_TYPES; i++) - INIT_LIST_HEAD(&device->report_enum[i].report_list); - - if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { - kfree(device); - return NULL; - } - memcpy(device->rdesc, start, size); - - if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { - kfree(device->rdesc); - kfree(device); - return NULL; - } - memset(parser, 0, sizeof(struct hid_parser)); - parser->device = device; - - end = start + size; - while ((start = fetch_item(start, end, &item)) != 0) { - - if (item.format != HID_ITEM_FORMAT_SHORT) { - dbg("unexpected long global item"); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (dispatch_type[item.type](parser, &item)) { - dbg("item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (start == end) { - if (parser->collection_stack_ptr) { - dbg("unbalanced collection at end of report description"); - hid_free_device(device); - kfree(parser); - return NULL; - } - if (parser->local.delimiter_depth) { - dbg("unbalanced delimiter at end of report description"); - hid_free_device(device); - kfree(parser); - return NULL; - } - kfree(parser); - return device; - } - } - - dbg("item fetching failed at offset %d\n", (int)(end - start)); - hid_free_device(device); - kfree(parser); - return NULL; -} - -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static __inline__ __s32 snto32(__u32 value, unsigned n) -{ - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (-1 << n) : value; -} - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static __inline__ __u32 s32ton(__s32 value, unsigned n) -{ - __s32 a = value >> (n - 1); - if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - -/* - * Extract/implement a data field from/to a report. - */ - -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) -{ - report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1); -} - -static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) -{ - report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__u64*)report) - & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__u64*)report); -} - -/* - * Search an array for a value. - */ - -static __inline__ int search(__s32 *array, __s32 value, unsigned n) -{ - while (n--) if (*array++ == value) return 0; - return -1; -} - -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - hid_dump_input(usage, value); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value); -#ifdef CONFIG_USB_HIDDEV - if (hid->claimed & HID_CLAIMED_HIDDEV) { - struct hiddev_usage_ref uref; - unsigned type = field->report_type; - uref.report_type = - (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); - uref.report_id = field->report->id; - uref.field_index = field->index; - uref.usage_index = (usage - field->usage); - uref.usage_code = usage->hid; - uref.value = value; - hiddev_hid_event(hid, &uref); - } -#endif -} - -/* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). - */ - -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data) -{ - unsigned n; - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; - __s32 value[count]; /* WARNING: gcc specific */ - - for (n = 0; n < count; n++) { - - value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : - extract(data, offset + n * size, size); - - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ - && value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - return; - } - - for (n = 0; n < count; n++) { - - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - if (!value[n]) continue; - } else { - if (value[n] == field->value[n]) continue; - } - hid_process_event(hid, field, &field->usage[n], value[n]); - continue; - } - - if (field->value[n] >= min && field->value[n] <= max - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0); - - if (value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1); - } - - memcpy(field->value, value, count * sizeof(__s32)); -} - -static int hid_input_report(int type, struct urb *urb) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < n; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - -#ifdef CONFIG_USB_HIDDEV - /* Notify listeners that a report has been received */ - if (hid->claimed & HID_CLAIMED_HIDDEV) { - struct hiddev_usage_ref uref; - memset(&uref, 0, sizeof(uref)); - uref.report_type = - (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); - uref.report_id = report->id; - uref.field_index = HID_FIELD_INDEX_NONE; - hiddev_hid_event(hid, &uref); - } -#endif - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - return -1; - } - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data); - - return 0; -} - -/* - * Input interrupt completion handler. - */ - -static void hid_irq_in(struct urb *urb) -{ - if (urb->status) { - dbg("nonzero status in input irq %d", urb->status); - return; - } - - hid_input_report(HID_INPUT_REPORT, urb); -} - -/* - * Output the field into the report. - */ - -static void hid_output_field(struct hid_field *field, __u8 *data) -{ - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - unsigned n; - - for (n = 0; n < count; n++) { - if (field->logical_minimum < 0) /* signed values */ - implement(data, offset + n * size, size, s32ton(field->value[n], size)); - else /* unsigned values */ - implement(data, offset + n * size, size, field->value[n]); - } -} - -/* - * Create a report. - */ - -void hid_output_report(struct hid_report *report, __u8 *data) -{ - unsigned n; - for (n = 0; n < report->maxfield; n++) - hid_output_field(report->field[n], data); -} - -/* - * Set a field value. The report this field belongs to has to be - * created and transfered to the device, to set this value in the - * device. - */ - -int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) -{ - unsigned size = field->report_size; - - hid_dump_input(field->usage + offset, value); - - if (offset >= field->report_count) { - dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); - hid_dump_field(field, 8); - return -1; - } - if (field->logical_minimum < 0) { - if (value != snto32(s32ton(value, size), size)) { - dbg("value %d is out of range", value); - return -1; - } - } - field->value[offset] = value; - return 0; -} - -int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) -{ - struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT; - struct list_head *list = report_enum->report_list.next; - int i, j; - - while (list != &report_enum->report_list) { - struct hid_report *report = (struct hid_report *) list; - list = list->next; - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) - return j; - } - } - return -1; -} - -/* - * Find a report with a specified HID usage. - */ - -int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type) -{ - struct hid_report_enum *report_enum = hid->report_enum + type; - struct list_head *list = report_enum->report_list.next; - int i, j; - - while (list != &report_enum->report_list) { - *report = (struct hid_report *) list; - list = list->next; - for (i = 0; i < (*report)->maxfield; i++) { - struct hid_field *field = (*report)->field[i]; - for (j = 0; j < field->maxusage; j++) - if (field->logical == wanted_usage) - return j; - } - } - return -1; -} - -int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field) -{ - int i, j; - - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].hid == wanted_usage) - return j; - } - - return -1; -} - -static int hid_submit_out(struct hid_device *hid) -{ - struct hid_report *report; - - report = hid->out[hid->outtail]; - - hid_output_report(report, hid->outbuf); - hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1; - hid->urbout->dev = hid->dev; - - dbg("submitting out urb"); - - if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) { - err("usb_submit_urb(out) failed"); - return -1; - } - - return 0; -} - -static int hid_submit_ctrl(struct hid_device *hid) -{ - struct hid_report *report; - unsigned char dir; - - report = hid->ctrl[hid->ctrltail].report; - dir = hid->ctrl[hid->ctrltail].dir; - - if (dir == USB_DIR_OUT) - hid_output_report(report, hid->ctrlbuf); - - hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT)); - hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); - hid->urbctrl->dev = hid->dev; - - hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; - hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; - hid->cr.wValue = ((report->type + 1) << 8) | report->id; - hid->cr.wIndex = cpu_to_le16(hid->ifnum); - hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); - - dbg("submitting ctrl urb"); - - if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { - err("usb_submit_urb(ctrl) failed"); - return -1; - } - - return 0; -} - -/* - * Output interrupt completion handler. - */ - -static void hid_irq_out(struct urb *urb) -{ - struct hid_device *hid = urb->context; - unsigned long flags; - - if (urb->status) - warn("output irq status %d received", urb->status); - - spin_lock_irqsave(&hid->outlock, flags); - - hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - - if (hid->outhead != hid->outtail) { - hid_submit_out(hid); - spin_unlock_irqrestore(&hid->outlock, flags); - return; - } - - clear_bit(HID_OUT_RUNNING, &hid->iofl); - - spin_unlock_irqrestore(&hid->outlock, flags); - - wake_up(&hid->wait); -} - -/* - * Control pipe completion handler. - */ - -static void hid_ctrl(struct urb *urb) -{ - struct hid_device *hid = urb->context; - unsigned long flags; - - if (urb->status) - warn("ctrl urb status %d received", urb->status); - - spin_lock_irqsave(&hid->ctrllock, flags); - - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb); - - hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - - if (hid->ctrlhead != hid->ctrltail) { - hid_submit_ctrl(hid); - spin_unlock_irqrestore(&hid->ctrllock, flags); - return; - } - - clear_bit(HID_CTRL_RUNNING, &hid->iofl); - - spin_unlock_irqrestore(&hid->ctrllock, flags); - - wake_up(&hid->wait); -} - -void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) -{ - int head; - unsigned long flags; - - if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) - return; - - if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { - - spin_lock_irqsave(&hid->outlock, flags); - - if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { - spin_unlock_irqrestore(&hid->outlock, flags); - warn("output queue full"); - return; - } - - hid->out[hid->outhead] = report; - hid->outhead = head; - - if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) - hid_submit_out(hid); - - spin_unlock_irqrestore(&hid->outlock, flags); - return; - } - - spin_lock_irqsave(&hid->ctrllock, flags); - - if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { - spin_unlock_irqrestore(&hid->ctrllock, flags); - warn("control queue full"); - return; - } - - hid->ctrl[hid->ctrlhead].report = report; - hid->ctrl[hid->ctrlhead].dir = dir; - hid->ctrlhead = head; - - if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) - hid_submit_ctrl(hid); - - spin_unlock_irqrestore(&hid->ctrllock, flags); -} - -int hid_wait_io(struct hid_device *hid) -{ - DECLARE_WAITQUEUE(wait, current); - int timeout = 10*HZ; - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&hid->wait, &wait); - - while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) && - test_bit(HID_OUT_RUNNING, &hid->iofl)) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&hid->wait, &wait); - - if (!timeout) { - dbg("timeout waiting for ctrl or out queue to clear"); - return -1; - } - - return 0; -} - -static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, - unsigned char type, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, - (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT); -} - -int hid_open(struct hid_device *hid) -{ - if (hid->open++) - return 0; - - hid->urbin->dev = hid->dev; - - if (usb_submit_urb(hid->urbin, GFP_KERNEL)) - return -EIO; - - return 0; -} - -void hid_close(struct hid_device *hid) -{ - if (!--hid->open) - usb_unlink_urb(hid->urbin); -} - -/* - * Initialize all reports - */ - -void hid_init_reports(struct hid_device *hid) -{ - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - int len; - - report_enum = hid->report_enum + HID_INPUT_REPORT; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - hid_submit_report(hid, report, USB_DIR_IN); - list = list->next; - } - - report_enum = hid->report_enum + HID_FEATURE_REPORT; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - hid_submit_report(hid, report, USB_DIR_IN); - list = list->next; - } - - if (hid_wait_io(hid)) { - warn("timeout initializing reports\n"); - return; - } - - report_enum = hid->report_enum + HID_INPUT_REPORT; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; - if (len > hid->urbin->transfer_buffer_length) - hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; - usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), - 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, - hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - list = list->next; - } -} - -#define USB_VENDOR_ID_WACOM 0x056a -#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 -#define USB_DEVICE_ID_WACOM_INTUOS 0x0020 - -#define USB_VENDOR_ID_GRIFFIN 0x077d -#define USB_DEVICE_ID_POWERMATE 0x0410 -#define USB_DEVICE_ID_SOUNDKNOB 0x04AA - -#define USB_VENDOR_ID_ATEN 0x0557 -#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 -#define USB_DEVICE_ID_ATEN_CS124U 0x2202 -#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 - -struct hid_blacklist { - __u16 idVendor; - __u16 idProduct; - unsigned quirks; -} hid_blacklist[] = { - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, - { 0, 0 } -}; - -static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) -{ - struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; - struct hid_descriptor *hdesc; - struct hid_device *hid; - unsigned quirks = 0, rsize = 0; - char *buf; - int n; - - for (n = 0; hid_blacklist[n].idVendor; n++) - if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) - quirks = hid_blacklist[n].quirks; - - if (quirks & HID_QUIRK_IGNORE) - return NULL; - - if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || - usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { - dbg("class descriptor not present\n"); - return NULL; - } - - for (n = 0; n < hdesc->bNumDescriptors; n++) - if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) - rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); - - if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { - dbg("weird size of report descriptor (%u)", rsize); - return NULL; - } - - { - __u8 rdesc[rsize]; - - if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { - dbg("reading report descriptor failed"); - return NULL; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); - for (n = 0; n < rsize; n++) - printk(" %02x", (unsigned) rdesc[n]); - printk("\n"); -#endif - - if (!(hid = hid_parse_report(rdesc, rsize))) { - dbg("parsing report descriptor failed"); - return NULL; - } - } - - hid->quirks = quirks; - - for (n = 0; n < interface->bNumEndpoints; n++) { - - struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; - int pipe; - - if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ - continue; - - if (endpoint->bEndpointAddress & USB_DIR_IN) { - if (hid->urbin) - continue; - if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) - goto fail; - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); - } else { - if (hid->urbout) - continue; - if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) - goto fail; - pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress); - FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); - } - } - - if (!hid->urbin) { - err("couldn't find an input interrupt endpoint"); - goto fail; - } - - init_waitqueue_head(&hid->wait); - - hid->outlock = SPIN_LOCK_UNLOCKED; - hid->ctrllock = SPIN_LOCK_UNLOCKED; - - hid->version = hdesc->bcdHID; - hid->country = hdesc->bCountryCode; - hid->dev = dev; - hid->ifnum = interface->bInterfaceNumber; - - hid->name[0] = 0; - - if (!(buf = kmalloc(64, GFP_KERNEL))) - goto fail; - - if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) { - strcat(hid->name, buf); - if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) - sprintf(hid->name, "%s %s", hid->name, buf); - } else - sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); - - usb_make_path(dev, buf, 63); - sprintf(hid->phys, "%s/input%d", buf, ifnum); - - if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) - hid->uniq[0] = 0; - - kfree(buf); - - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); - FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); - - return hid; - -fail: - - hid_free_device(hid); - if (hid->urbin) usb_free_urb(hid->urbin); - if (hid->urbout) usb_free_urb(hid->urbout); - if (hid->urbctrl) usb_free_urb(hid->urbctrl); - - return NULL; -} - -static void* hid_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct hid_device *hid; - char path[64]; - int i; - char *c; - - dbg("HID probe called for ifnum %d", ifnum); - - if (!(hid = usb_hid_configure(dev, ifnum))) - return NULL; - - hid_init_reports(hid); - hid_dump_device(hid); - - if (!hidinput_connect(hid)) - hid->claimed |= HID_CLAIMED_INPUT; - if (!hiddev_connect(hid)) - hid->claimed |= HID_CLAIMED_HIDDEV; - - if (!hid->claimed) { - hid_free_device(hid); - return NULL; - } - - printk(KERN_INFO); - - if (hid->claimed & HID_CLAIMED_INPUT) - printk("input"); - if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) - printk(","); - if (hid->claimed & HID_CLAIMED_HIDDEV) - printk("hiddev%d", hid->minor); - - c = "Device"; - for (i = 0; i < hid->maxapplication; i++) - if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) { - c = hid_types[hid->application[i] & 0xffff]; - break; - } - - usb_make_path(dev, path, 63); - - printk(": USB HID v%x.%02x %s [%s] on %s\n", - hid->version >> 8, hid->version & 0xff, c, hid->name, path); - - return hid; -} - -static void hid_disconnect(struct usb_device *dev, void *ptr) -{ - struct hid_device *hid = ptr; - - usb_unlink_urb(hid->urbin); - usb_unlink_urb(hid->urbout); - usb_unlink_urb(hid->urbctrl); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(hid); - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_disconnect(hid); - - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - if (hid->urbout) - usb_free_urb(hid->urbout); - - hid_free_device(hid); -} - -static struct usb_device_id hid_usb_ids [] = { - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_INTERFACE_CLASS_HID }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, hid_usb_ids); - -static struct usb_driver hid_driver = { - name: "hid", - probe: hid_probe, - disconnect: hid_disconnect, - id_table: hid_usb_ids, -}; - -static int __init hid_init(void) -{ - hiddev_init(); - usb_register(&hid_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); - - return 0; -} - -static void __exit hid_exit(void) -{ - hiddev_exit(); - usb_deregister(&hid_driver); -} - -module_init(hid_init); -module_exit(hid_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/usb/class/hid-debug.h b/drivers/usb/class/hid-debug.h deleted file mode 100644 index ba2f9ef54937..000000000000 --- a/drivers/usb/class/hid-debug.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * - * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> - * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> - * - * Some debug stuff for the HID parser. - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; - -static struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-padUp"}, - {0, 0x91, "D-padDown"}, - {0, 0x92, "D-padRight"}, - {0, 0x93, "D-padLeft"}, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Hotkey" }, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0, 0, NULL } -}; - -static void resolv_usage_page(unsigned page) { - struct hid_usage_entry *p; - - for (p = hid_usage_table; p->description; p++) - if (p->page == page) { - printk("%s", p->description); - return; - } - printk("%04x", page); -} - -static void resolv_usage(unsigned usage) { - struct hid_usage_entry *p; - - resolv_usage_page(usage >> 16); - printk("."); - for (p = hid_usage_table; p->description; p++) - if (p->page == (usage >> 16)) { - for(++p; p->description && p->page == 0; p++) - if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); - return; - } - break; - } - printk("%04x", usage & 0xffff); -} - -__inline__ static void tab(int n) { - while (n--) printk(" "); -} - -static void hid_dump_field(struct hid_field *field, int n) { - int j; - - if (field->physical) { - tab(n); - printk("Physical("); - resolv_usage(field->physical); printk(")\n"); - } - if (field->logical) { - tab(n); - printk("Logical("); - resolv_usage(field->logical); printk(")\n"); - } - tab(n); printk("Usage(%d)\n", field->maxusage); - for (j = 0; j < field->maxusage; j++) { - tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); - } - if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); - } - if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); - } - if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); - } - if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { - { "None", "None", "None", "None", "None", "None", "None", "None" }, - { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, - { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } - }; - - int i; - int sys; - __u32 data = field->unit; - - /* First nibble tells us which system we're in. */ - sys = data & 0xf; - data >>= 4; - - if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); - } - else { - int earlier_unit = 0; - - tab(n); printk("Unit(%s : ", systems[sys]); - - for (i=1 ; i<sizeof(__u32)*2 ; i++) { - char nibble = data & 0xf; - data >>= 4; - if (nibble != 0) { - if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); - if(nibble != 1) { - /* This is a _signed_ nibble(!) */ - - int val = nibble & 0x7; - if(nibble & 0x08) - val = -((0x7 & ~val) +1); - printk("^%d", val); - } - } - } - printk(")\n"); - } - } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); - - tab(n); printk("Flags( "); - j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); -} - -static void hid_dump_device(struct hid_device *device) { - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - - for (i = 0; i < device->maxapplication; i++) { - printk("Application("); - resolv_usage(device->application[i]); - printk(")\n"); - } - - for (i = 0; i < HID_REPORT_TYPES; i++) { - report_enum = device->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); - if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); - for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); - } - list = list->next; - } - } -} - -static void hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hid-debug: input "); - resolv_usage(usage->hid); - printk(" = %d\n", value); -} diff --git a/drivers/usb/class/hid-input.c b/drivers/usb/class/hid-input.c deleted file mode 100644 index b45938b18cc8..000000000000 --- a/drivers/usb/class/hid-input.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * $Id: hid-input.c,v 1.18 2001/11/07 09:01:18 vojtech Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID to Linux Input mapping - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/input.h> -#include <linux/usb.h> - -#include "hid.h" - -#define unk KEY_UNKNOWN - -static unsigned char hid_keyboard[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, - 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189, - 190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk -}; - -static struct { - __s32 x; - __s32 y; -} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) -{ - struct input_dev *input = &device->input; - int max; - int is_abs = 0; - unsigned long *bit; - - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_KEYBOARD: - - set_bit(EV_REP, input->evbit); - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - - if ((usage->hid & HID_USAGE) < 256) { - if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE])) - return; - clear_bit(usage->code, bit); - } else - usage->code = KEY_UNKNOWN; - - break; - - case HID_UP_BUTTON: - - usage->code = ((usage->hid - 1) & 0xf) + 0x100; - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - - switch (field->application) { - case HID_GD_GAMEPAD: usage->code += 0x10; - case HID_GD_JOYSTICK: usage->code += 0x10; - case HID_GD_MOUSE: usage->code += 0x10; break; - default: - if (field->physical == HID_GD_POINTER) - usage->code += 0x10; - break; - } - break; - - case HID_UP_GENDESK: - - if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ - switch (usage->hid & 0xf) { - case 0x1: usage->code = KEY_POWER; break; - case 0x2: usage->code = KEY_SLEEP; break; - case 0x3: usage->code = KEY_WAKEUP; break; - default: usage->code = KEY_UNKNOWN; break; - } - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - break; - } - - usage->code = usage->hid & 0xf; - - if (field->report_size == 1) { - usage->code = BTN_MISC; - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - break; - } - - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - usage->type = EV_REL; bit = input->relbit; max = REL_MAX; - break; - } - - usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; - - if (usage->hid == HID_GD_HATSWITCH) { - usage->code = ABS_HAT0X; - usage->hat_min = field->logical_minimum; - usage->hat_max = field->logical_maximum; - } - break; - - case HID_UP_LED: - - usage->code = (usage->hid - 1) & 0xf; - usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; - break; - - case HID_UP_DIGITIZER: - - switch (usage->hid & 0xff) { - - case 0x30: /* TipPressure */ - - if (!test_bit(BTN_TOUCH, input->keybit)) { - device->quirks |= HID_QUIRK_NOTOUCH; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_TOUCH, input->keybit); - } - usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; - usage->code = ABS_PRESSURE; - clear_bit(usage->code, bit); - break; - - case 0x32: /* InRange */ - - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - switch (field->physical & 0xff) { - case 0x21: usage->code = BTN_TOOL_MOUSE; break; - case 0x22: usage->code = BTN_TOOL_FINGER; break; - default: usage->code = BTN_TOOL_PEN; break; - } - break; - - case 0x3c: /* Invert */ - - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - usage->code = BTN_TOOL_RUBBER; - clear_bit(usage->code, bit); - break; - - case 0x33: /* Touch */ - case 0x42: /* TipSwitch */ - case 0x43: /* TipSwitch2 */ - - device->quirks &= ~HID_QUIRK_NOTOUCH; - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - usage->code = BTN_TOUCH; - clear_bit(usage->code, bit); - break; - - case 0x44: /* BarrelSwitch */ - - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - usage->code = BTN_STYLUS; - clear_bit(usage->code, bit); - break; - - default: goto unknown; - } - break; - - case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ - - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x000: usage->code = 0; break; - case 0x034: usage->code = KEY_SLEEP; break; - case 0x036: usage->code = BTN_MISC; break; - case 0x08a: usage->code = KEY_WWW; break; - case 0x095: usage->code = KEY_HELP; break; - - case 0x0b0: usage->code = KEY_PLAY; break; - case 0x0b1: usage->code = KEY_PAUSE; break; - case 0x0b2: usage->code = KEY_RECORD; break; - case 0x0b3: usage->code = KEY_FASTFORWARD; break; - case 0x0b4: usage->code = KEY_REWIND; break; - case 0x0b5: usage->code = KEY_NEXTSONG; break; - case 0x0b6: usage->code = KEY_PREVIOUSSONG; break; - case 0x0b7: usage->code = KEY_STOPCD; break; - case 0x0b8: usage->code = KEY_EJECTCD; break; - case 0x0cd: usage->code = KEY_PLAYPAUSE; break; - case 0x0e0: is_abs = 1; - usage->code = ABS_VOLUME; - break; - case 0x0e2: usage->code = KEY_MUTE; break; - case 0x0e5: usage->code = KEY_BASSBOOST; break; - case 0x0e9: usage->code = KEY_VOLUMEUP; break; - case 0x0ea: usage->code = KEY_VOLUMEDOWN; break; - - case 0x183: usage->code = KEY_CONFIG; break; - case 0x18a: usage->code = KEY_MAIL; break; - case 0x192: usage->code = KEY_CALC; break; - case 0x194: usage->code = KEY_FILE; break; - case 0x21a: usage->code = KEY_UNDO; break; - case 0x21b: usage->code = KEY_COPY; break; - case 0x21c: usage->code = KEY_CUT; break; - case 0x21d: usage->code = KEY_PASTE; break; - - case 0x221: usage->code = KEY_FIND; break; - case 0x223: usage->code = KEY_HOMEPAGE; break; - case 0x224: usage->code = KEY_BACK; break; - case 0x225: usage->code = KEY_FORWARD; break; - case 0x226: usage->code = KEY_STOP; break; - case 0x227: usage->code = KEY_REFRESH; break; - case 0x22a: usage->code = KEY_BOOKMARKS; break; - - default: usage->code = KEY_UNKNOWN; break; - } - - if (is_abs) { - usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; - } else { - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - } - break; - - case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ - - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x021: usage->code = KEY_PRINT; break; - case 0x070: usage->code = KEY_HP; break; - case 0x071: usage->code = KEY_CAMERA; break; - case 0x072: usage->code = KEY_SOUND; break; - case 0x073: usage->code = KEY_QUESTION; break; - - case 0x080: usage->code = KEY_EMAIL; break; - case 0x081: usage->code = KEY_CHAT; break; - case 0x082: usage->code = KEY_SEARCH; break; - case 0x083: usage->code = KEY_CONNECT; break; - case 0x084: usage->code = KEY_FINANCE; break; - case 0x085: usage->code = KEY_SPORT; break; - case 0x086: usage->code = KEY_SHOP; break; - - default: usage->code = KEY_UNKNOWN; break; - - } - - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - break; - - default: - unknown: - - if (field->report_size == 1) { - - if (field->report->type == HID_OUTPUT_REPORT) { - usage->code = LED_MISC; - usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; - break; - } - - usage->code = BTN_MISC; - usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; - break; - } - - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - usage->code = REL_MISC; - usage->type = EV_REL; bit = input->relbit; max = REL_MAX; - break; - } - - usage->code = ABS_MISC; - usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; - break; - } - - set_bit(usage->type, input->evbit); - - while (usage->code <= max && test_and_set_bit(usage->code, bit)) { - usage->code = find_next_zero_bit(bit, max + 1, usage->code); - } - - if (usage->code > max) return; - - if (usage->type == EV_ABS) { - int a = field->logical_minimum; - int b = field->logical_maximum; - - input->absmin[usage->code] = a; - input->absmax[usage->code] = b; - input->absfuzz[usage->code] = (b - a) >> 8; - input->absflat[usage->code] = (b - a) >> 4; - } - - if (usage->hat_min != usage->hat_max) { - int i; - for (i = usage->code; i < usage->code + 2 && i <= max; i++) { - input->absmax[i] = 1; - input->absmin[i] = -1; - input->absfuzz[i] = 0; - input->absflat[i] = 0; - } - set_bit(usage->code + 1, input->absbit); - } -} - -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct input_dev *input = &hid->input; - int *quirks = &hid->quirks; - - if (usage->hat_min != usage->hat_max) { - value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; - if (value < 0 || value > 8) value = 0; - input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */ - return; - - input_event(input, usage->type, usage->code, value); - - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) - input_event(input, usage->type, usage->code, 0); -} - -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct hid_device *hid = dev->private; - struct hid_field *field = NULL; - int offset; - - if ((offset = hid_find_field(hid, type, code, &field)) == -1) { - warn("event field not found"); - return -1; - } - - hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); - - return 0; -} - -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return hid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - hid_close(hid); -} - -/* - * Register the input device; print a message. - * Configure the input layer interface - * Read all reports and initalize the absoulte field values. - */ - -int hidinput_connect(struct hid_device *hid) -{ - struct usb_device *dev = hid->dev; - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - int i, j, k; - - for (i = 0; i < hid->maxapplication; i++) - if (IS_INPUT_APPLICATION(hid->application[i])) - break; - - if (i == hid->maxapplication) - return -1; - - hid->input.private = hid; - hid->input.event = hidinput_input_event; - hid->input.open = hidinput_open; - hid->input.close = hidinput_close; - - hid->input.name = hid->name; - hid->input.phys = hid->phys; - hid->input.uniq = hid->uniq; - hid->input.idbus = BUS_USB; - hid->input.idvendor = dev->descriptor.idVendor; - hid->input.idproduct = dev->descriptor.idProduct; - hid->input.idversion = dev->descriptor.bcdDevice; - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { - report_enum = hid->report_enum + k; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hid, report->field[i], report->field[i]->usage + j); - list = list->next; - } - } - - input_register_device(&hid->input); - - return 0; -} - -void hidinput_disconnect(struct hid_device *hid) -{ - input_unregister_device(&hid->input); -} diff --git a/drivers/usb/class/hid.h b/drivers/usb/class/hid.h deleted file mode 100644 index 357e31bd3814..000000000000 --- a/drivers/usb/class/hid.h +++ /dev/null @@ -1,421 +0,0 @@ -#ifndef __HID_H -#define __HID_H - -/* - * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/list.h> - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* - * HID class requests - */ - -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B - -/* - * HID class descriptor types - */ - -#define HID_DT_HID (USB_TYPE_CLASS | 0x01) -#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - -/* - * HID report descriptor item type (prefix bit 2,3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 - -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 - -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - -/* - * HID usage tables - */ - -#define HID_USAGE_PAGE 0xffff0000 - -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 -#define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 -#define HID_UP_HPVENDOR 0xff7f0000 - -#define HID_USAGE 0x0000ffff - -#define HID_GD_POINTER 0x00010001 -#define HID_GD_MOUSE 0x00010002 -#define HID_GD_JOYSTICK 0x00010004 -#define HID_GD_GAMEPAD 0x00010005 -#define HID_GD_HATSWITCH 0x00010039 - -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -/* - * HID device quirks. - */ - -#define HID_QUIRK_INVERT 0x01 -#define HID_QUIRK_NOTOUCH 0x02 -#define HID_QUIRK_IGNORE 0x04 -#define HID_QUIRK_NOGET 0x08 - -/* - * This is the global enviroment of the parser. This information is - * persistent for main-items. The global enviroment can be saved and - * restored with PUSH/POP statements. - */ - -struct hid_global { - unsigned usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - unsigned report_id; - unsigned report_size; - unsigned report_count; -}; - -/* - * This is the local enviroment. It is resistent up the next main-item. - */ - -#define HID_MAX_DESCRIPTOR_SIZE 4096 -#define HID_MAX_USAGES 1024 -#define HID_MAX_APPLICATIONS 16 - -struct hid_local { - unsigned usage[HID_MAX_USAGES]; /* usage array */ - unsigned usage_index; - unsigned usage_minimum; - unsigned delimiter_depth; - unsigned delimiter_branch; -}; - -/* - * This is the collection stack. We climb up the stack to determine - * application and function of each field. - */ - -struct hid_collection { - unsigned type; - unsigned usage; -}; - -struct hid_usage { - unsigned hid; /* hid usage code */ - __u16 code; /* input driver code */ - __u8 type; /* input driver type */ - __s8 hat_min; /* hat switch fun */ - __s8 hat_max; /* ditto */ -}; - -struct hid_field { - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ - struct hid_usage *usage; /* usage table for this function */ - unsigned maxusage; /* maximum usage index */ - unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ - unsigned report_offset; /* bit offset in the report */ - unsigned report_size; /* size of this field in the report */ - unsigned report_count; /* number of this field in the report */ - unsigned report_type; /* (input,output,feature) */ - __s32 *value; /* last known value(s) */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - struct hid_report *report; /* associated report */ - unsigned index; /* index into report->field[] */ -}; - -#define HID_MAX_FIELDS 64 - -struct hid_report { - struct list_head list; - unsigned id; /* id of this report */ - unsigned type; /* report type */ - struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ - unsigned maxfield; /* maximum valid field index */ - unsigned size; /* size of the report (bits) */ - struct hid_device *device; /* associated device */ -}; - -struct hid_report_enum { - unsigned numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -#define HID_REPORT_TYPES 3 - -#define HID_BUFFER_SIZE 32 -#define HID_CONTROL_FIFO_SIZE 64 -#define HID_OUTPUT_FIFO_SIZE 64 - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; -}; - -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 - -#define HID_CTRL_RUNNING 1 -#define HID_OUT_RUNNING 2 - -struct hid_device { /* device report descriptor */ - __u8 *rdesc; - unsigned rsize; - unsigned application[HID_MAX_APPLICATIONS]; /* List of HID applications */ - unsigned maxapplication; /* Number of applications */ - unsigned version; /* HID version */ - unsigned country; /* HID country */ - struct hid_report_enum report_enum[HID_REPORT_TYPES]; - - struct usb_device *dev; /* USB device */ - int ifnum; /* USB interface number */ - - unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - - struct urb *urbin; /* Input URB */ - char inbuf[HID_BUFFER_SIZE]; /* Input buffer */ - - struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest cr; /* Control request struct */ - struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ - unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char ctrlbuf[HID_BUFFER_SIZE]; /* Control buffer */ - spinlock_t ctrllock; /* Control fifo spinlock */ - - struct urb *urbout; /* Output URB */ - struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ - unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char outbuf[HID_BUFFER_SIZE]; /* Output buffer */ - spinlock_t outlock; /* Output fifo spinlock */ - - unsigned claimed; /* Claimed by hidinput, hiddev? */ - unsigned quirks; /* Various quirks the device can pull on us */ - - struct input_dev input; /* The input structure */ - void *hiddev; /* The hiddev structure */ - int minor; /* Hiddev minor number */ - - wait_queue_head_t wait; /* For sleeping */ - - int open; /* is the device open by anyone? */ - char name[128]; /* Device name */ - char phys[64]; /* Device physical location */ - char uniq[64]; /* Device unique identifier (serial #) */ -}; - -#define HID_GLOBAL_STACK_SIZE 4 -#define HID_COLLECTION_STACK_SIZE 4 - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; - unsigned global_stack_ptr; - struct hid_local local; - struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; - unsigned collection_stack_ptr; - struct hid_device *device; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __u16 wDescriptorLength; -} __attribute__ ((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - - struct hid_class_descriptor desc[1]; -} __attribute__ ((packed)); - -#ifdef DEBUG -#include "hid-debug.h" -#else -#define hid_dump_input(a,b) do { } while (0) -#define hid_dump_device(c) do { } while (0) -#define hid_dump_field(a,b) do { } while (0) -#endif - -#endif - -#ifdef CONFIG_USB_HIDINPUT -/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ -/* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001)) -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -extern int hidinput_connect(struct hid_device *); -extern void hidinput_disconnect(struct hid_device *); -#else -#define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } -static inline void hidinput_disconnect(struct hid_device *hid) { } -#endif - -int hid_open(struct hid_device *); -void hid_close(struct hid_device *); -int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **); -int hid_set_field(struct hid_field *, unsigned, __s32); -void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); -void hid_init_reports(struct hid_device *hid); diff --git a/drivers/usb/class/hiddev.c b/drivers/usb/class/hiddev.c deleted file mode 100644 index 206531c7aef7..000000000000 --- a/drivers/usb/class/hiddev.c +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Copyright (c) 2001 Paul Stewart - * Copyright (c) 2001 Vojtech Pavlik - * - * HID char devices, giving access to raw HID device events. - * - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net> - */ - -#define HIDDEV_MINOR_BASE 96 -#define HIDDEV_MINORS 16 -#define HIDDEV_BUFFER_SIZE 64 - -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/smp_lock.h> -#include <linux/input.h> -#include <linux/usb.h> -#include "hid.h" -#include <linux/hiddev.h> - -struct hiddev { - int exist; - int open; - int minor; - wait_queue_head_t wait; - devfs_handle_t devfs; - struct hid_device *hid; - struct hiddev_list *list; -}; - -struct hiddev_list { - struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; - int head; - int tail; - unsigned flags; - struct fasync_struct *fasync; - struct hiddev *hiddev; - struct hiddev_list *next; -}; - -static struct hiddev *hiddev_table[HIDDEV_MINORS]; -static devfs_handle_t hiddev_devfs_handle; - -/* - * Find a report, given the report's type and ID. The ID can be specified - * indirectly by REPORT_ID_FIRST (which returns the first report of the given - * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the - * given type which follows old_id. - */ -static struct hid_report * -hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) -{ - struct hid_report_enum *report_enum; - struct list_head *list; - - if (rinfo->report_type < HID_REPORT_TYPE_MIN || - rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL; - - report_enum = hid->report_enum + - (rinfo->report_type - HID_REPORT_TYPE_MIN); - if ((rinfo->report_id & ~HID_REPORT_ID_MASK) != 0) { - switch (rinfo->report_id & ~HID_REPORT_ID_MASK) { - case HID_REPORT_ID_FIRST: - list = report_enum->report_list.next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - - case HID_REPORT_ID_NEXT: - list = (struct list_head *) - report_enum->report_id_hash[rinfo->report_id & - HID_REPORT_ID_MASK]; - if (list == NULL) return NULL; - list = list->next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - - default: - return NULL; - } - } - - return report_enum->report_id_hash[rinfo->report_id]; -} - -/* - * Perform an exhaustive search of the report table for a usage, given its - * type and usage id. - */ -static struct hid_field * -hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) -{ - int i, j; - struct hid_report *report; - struct hid_report_enum *report_enum; - struct list_head *list; - struct hid_field *field; - - if (uref->report_type < HID_REPORT_TYPE_MIN || - uref->report_type > HID_REPORT_TYPE_MAX) return NULL; - - report_enum = hid->report_enum + - (uref->report_type - HID_REPORT_TYPE_MIN); - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - for (i = 0; i < report->maxfield; i++) { - field = report->field[i]; - for (j = 0; j < field->maxusage; j++) { - if (field->usage[j].hid == uref->usage_code) { - uref->report_id = report->id; - uref->field_index = i; - uref->usage_index = j; - return field; - } - } - } - list = list->next; - } - - return NULL; -} - -/* - * This is where hid.c calls into hiddev to pass an event that occurred over - * the interrupt pipe - */ -void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) -{ - struct hiddev *hiddev = hid->hiddev; - struct hiddev_list *list = hiddev->list; - - while (list) { - if (uref->field_index != HID_FIELD_INDEX_NONE || - (list->flags & HIDDEV_FLAG_REPORT) != 0) { - list->buffer[list->head] = *uref; - list->head = (list->head + 1) & - (HIDDEV_BUFFER_SIZE - 1); - kill_fasync(&list->fasync, SIGIO, POLL_IN); - } - - list = list->next; - } - - wake_up_interruptible(&hiddev->wait); -} - -/* - * fasync file op - */ -static int hiddev_fasync(int fd, struct file *file, int on) -{ - int retval; - struct hiddev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &list->fasync); - return retval < 0 ? retval : 0; -} - -/* - * De-allocate a hiddev structure - */ -static void hiddev_cleanup(struct hiddev *hiddev) -{ - devfs_unregister(hiddev->devfs); - hiddev_table[hiddev->minor] = NULL; - kfree(hiddev); -} - -/* - * release file op - */ -static int hiddev_release(struct inode * inode, struct file * file) -{ - struct hiddev_list *list = file->private_data; - struct hiddev_list **listptr; - - listptr = &list->hiddev->list; - hiddev_fasync(-1, file, 0); - - while (*listptr && (*listptr != list)) - listptr = &((*listptr)->next); - *listptr = (*listptr)->next; - - if (!--list->hiddev->open) { - if (list->hiddev->exist) - hid_close(list->hiddev->hid); - else - hiddev_cleanup(list->hiddev); - } - - kfree(list); - - return 0; -} - -/* - * open file op - */ -static int hiddev_open(struct inode * inode, struct file * file) { - struct hiddev_list *list; - - int i = minor(inode->i_rdev) - HIDDEV_MINOR_BASE; - - if (i >= HIDDEV_MINORS || !hiddev_table[i]) - return -ENODEV; - - if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL))) - return -ENOMEM; - memset(list, 0, sizeof(struct hiddev_list)); - - list->hiddev = hiddev_table[i]; - list->next = hiddev_table[i]->list; - hiddev_table[i]->list = list; - - file->private_data = list; - - if (!list->hiddev->open++) - if (list->hiddev->exist) - hid_open(hiddev_table[i]->hid); - - return 0; -} - -/* - * "write" file op - */ -static ssize_t hiddev_write(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/* - * "read" file op - */ -static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, - loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct hiddev_list *list = file->private_data; - int event_size; - int retval = 0; - - event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? - sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); - - if (count < event_size) return 0; - - while (retval == 0) { - if (list->head == list->tail) { - add_wait_queue(&list->hiddev->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - while (list->head == list->tail) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - if (!list->hiddev->exist) { - retval = -EIO; - break; - } - - schedule(); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&list->hiddev->wait, &wait); - } - - if (retval) - return retval; - - - while (list->head != list->tail && - retval + event_size <= count) { - if ((list->flags & HIDDEV_FLAG_UREF) == 0) { - if (list->buffer[list->tail].field_index != - HID_FIELD_INDEX_NONE) { - struct hiddev_event event; - event.hid = list->buffer[list->tail].usage_code; - event.value = list->buffer[list->tail].value; - if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) - return -EFAULT; - retval += sizeof(struct hiddev_event); - } - } else { - if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || - (list->flags & HIDDEV_FLAG_REPORT) != 0) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) - return -EFAULT; - retval += sizeof(struct hiddev_usage_ref); - } - } - list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); - } - - } - - return retval; -} - -/* - * "poll" file op - * No kernel lock - fine - */ -static unsigned int hiddev_poll(struct file *file, poll_table *wait) -{ - struct hiddev_list *list = file->private_data; - poll_wait(file, &list->hiddev->wait, wait); - if (list->head != list->tail) - return POLLIN | POLLRDNORM; - if (!list->hiddev->exist) - return POLLERR | POLLHUP; - return 0; -} - -/* - * "ioctl" file op - */ -static int hiddev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct hiddev_list *list = file->private_data; - struct hiddev *hiddev = list->hiddev; - struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid->dev; - struct hiddev_report_info rinfo; - struct hiddev_usage_ref uref; - struct hid_report *report; - struct hid_field *field; - - if (!hiddev->exist) return -EIO; - - switch (cmd) { - - case HIDIOCGVERSION: - return put_user(HID_VERSION, (int *) arg); - - case HIDIOCAPPLICATION: - if (arg < 0 || arg >= hid->maxapplication) - return -EINVAL; - return hid->application[arg]; - - case HIDIOCGDEVINFO: - { - struct hiddev_devinfo dinfo; - dinfo.bustype = BUS_USB; - dinfo.busnum = dev->bus->busnum; - dinfo.devnum = dev->devnum; - dinfo.ifnum = hid->ifnum; - dinfo.vendor = dev->descriptor.idVendor; - dinfo.product = dev->descriptor.idProduct; - dinfo.version = dev->descriptor.bcdDevice; - dinfo.num_applications = hid->maxapplication; - return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); - } - - case HIDIOCGFLAG: - return put_user(list->flags, (int *) arg); - - case HIDIOCSFLAG: - { - int newflags; - if (get_user(newflags, (int *) arg)) - return -EFAULT; - - if ((newflags & ~HIDDEV_FLAGS) != 0 || - ((newflags & HIDDEV_FLAG_REPORT) != 0 && - (newflags & HIDDEV_FLAG_UREF) == 0)) - return -EINVAL; - - list->flags = newflags; - - return 0; - } - - case HIDIOCGSTRING: - { - int idx, len; - char *buf; - - if (get_user(idx, (int *) arg)) - return -EFAULT; - - if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { - kfree(buf); - return -EINVAL; - } - - if (copy_to_user((void *) (arg+sizeof(int)), buf, len+1)) { - kfree(buf); - return -EFAULT; - } - - kfree(buf); - - return len; - } - - case HIDIOCINITREPORT: - - hid_init_reports(hid); - - return 0; - - case HIDIOCGREPORT: - if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo))) - return -EFAULT; - - if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) - return -EINVAL; - - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - hid_submit_report(hid, report, USB_DIR_IN); - - return 0; - - case HIDIOCSREPORT: - if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo))) - return -EFAULT; - - if (rinfo.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; - - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - hid_submit_report(hid, report, USB_DIR_OUT); - - return 0; - - case HIDIOCGREPORTINFO: - if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo))) - return -EFAULT; - - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - rinfo.num_fields = report->maxfield; - - return copy_to_user((void *) arg, &rinfo, sizeof(rinfo)); - - case HIDIOCGFIELDINFO: - { - struct hiddev_field_info finfo; - if (copy_from_user(&finfo, (void *) arg, sizeof(finfo))) - return -EFAULT; - rinfo.report_type = finfo.report_type; - rinfo.report_id = finfo.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - if (finfo.field_index >= report->maxfield) - return -EINVAL; - - field = report->field[finfo.field_index]; - memset(&finfo, 0, sizeof(finfo)); - finfo.report_type = rinfo.report_type; - finfo.report_id = rinfo.report_id; - finfo.field_index = field->report_count - 1; - finfo.maxusage = field->maxusage; - finfo.flags = field->flags; - finfo.physical = field->physical; - finfo.logical = field->logical; - finfo.application = field->application; - finfo.logical_minimum = field->logical_minimum; - finfo.logical_maximum = field->logical_maximum; - finfo.physical_minimum = field->physical_minimum; - finfo.physical_maximum = field->physical_maximum; - finfo.unit_exponent = field->unit_exponent; - finfo.unit = field->unit; - - return copy_to_user((void *) arg, &finfo, sizeof(finfo)); - } - - case HIDIOCGUCODE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; - - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - if (uref.field_index >= report->maxfield) - return -EINVAL; - - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; - - uref.usage_code = field->usage[uref.usage_index].hid; - - return copy_to_user((void *) arg, &uref, sizeof(uref)); - - case HIDIOCGUSAGE: - case HIDIOCSUSAGE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; - - if (cmd == HIDIOCSUSAGE && - uref.report_type != HID_REPORT_TYPE_OUTPUT) - return -EINVAL; - - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); - if (field == NULL) - return -EINVAL; - } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - if (uref.field_index >= report->maxfield) - return -EINVAL; - - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; - } - - if (cmd == HIDIOCGUSAGE) { - uref.value = field->value[uref.usage_index]; - return copy_to_user((void *) arg, &uref, sizeof(uref)); - } else { - field->value[uref.usage_index] = uref.value; - } - - return 0; - - default: - - if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) - return -EINVAL; - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { - int len; - if (!hid->name) return 0; - len = strlen(hid->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user((char *) arg, hid->name, len) ? - -EFAULT : len; - } - } - return -EINVAL; -} - -static struct file_operations hiddev_fops = { - owner: THIS_MODULE, - read: hiddev_read, - write: hiddev_write, - poll: hiddev_poll, - open: hiddev_open, - release: hiddev_release, - ioctl: hiddev_ioctl, - fasync: hiddev_fasync, -}; - -/* - * This is where hid.c calls us to connect a hid device to the hiddev driver - */ -int hiddev_connect(struct hid_device *hid) -{ - struct hiddev *hiddev; - int minor, i; - char devfs_name[16]; - - for (i = 0; i < hid->maxapplication; i++) - if (!IS_INPUT_APPLICATION(hid->application[i])) - break; - - if (i == hid->maxapplication) - return -1; - - for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++); - if (minor == HIDDEV_MINORS) { - printk(KERN_ERR "hiddev: no more free hiddev devices\n"); - return -1; - } - - if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) - return -1; - memset(hiddev, 0, sizeof(struct hiddev)); - - init_waitqueue_head(&hiddev->wait); - - hiddev->minor = minor; - hiddev_table[minor] = hiddev; - - hiddev->hid = hid; - hiddev->exist = 1; - - sprintf(devfs_name, "hiddev%d", minor); - hiddev->devfs = devfs_register(hiddev_devfs_handle, devfs_name, - DEVFS_FL_DEFAULT, USB_MAJOR, - minor + HIDDEV_MINOR_BASE, - S_IFCHR | S_IRUGO | S_IWUSR, - &hiddev_fops, NULL); - hid->minor = minor; - hid->hiddev = hiddev; - - return 0; -} - -/* - * This is where hid.c calls us to disconnect a hiddev device from the - * corresponding hid device (usually because the usb device has disconnected) - */ -void hiddev_disconnect(struct hid_device *hid) -{ - struct hiddev *hiddev = hid->hiddev; - - hiddev->exist = 0; - - if (hiddev->open) { - hid_close(hiddev->hid); - wake_up_interruptible(&hiddev->wait); - } else { - hiddev_cleanup(hiddev); - } -} - -/* Currently this driver is a USB driver. It's not a conventional one in - * the sense that it doesn't probe at the USB level. Instead it waits to - * be connected by HID through the hiddev_connect / hiddev_disconnect - * routines. The reason to register as a USB device is to gain part of the - * minor number space from the USB major. - * - * In theory, should the HID code be generalized to more than one physical - * medium (say, IEEE 1384), this driver will probably need to register its - * own major number, and in doing so, no longer need to register with USB. - * At that point the probe routine and hiddev_driver struct below will no - * longer be useful. - */ - - -/* We never attach in this manner, and rely on HID to connect us. This - * is why there is no disconnect routine defined in the usb_driver either. - */ -static void *hiddev_usbd_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *hiddev_info) -{ - return NULL; -} - - -static /* const */ struct usb_driver hiddev_driver = { - name: "hiddev", - probe: hiddev_usbd_probe, - fops: &hiddev_fops, - minor: HIDDEV_MINOR_BASE -}; - -int __init hiddev_init(void) -{ - hiddev_devfs_handle = - devfs_mk_dir(devfs_find_handle(NULL, "usb", 0, 0, 0, 0), "hid", NULL); - usb_register(&hiddev_driver); - return 0; -} - -void __exit hiddev_exit(void) -{ - devfs_unregister(hiddev_devfs_handle); - usb_deregister(&hiddev_driver); -} diff --git a/drivers/usb/class/storage/Makefile b/drivers/usb/class/storage/Makefile deleted file mode 100644 index 0181d2e727ca..000000000000 --- a/drivers/usb/class/storage/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# Makefile for the USB Mass Storage device drivers. -# -# 15 Aug 2000, Christoph Hellwig <hch@infradead.org> -# Rewritten to use lists instead of if-statements. -# - -O_TARGET := storage.o -EXTRA_CFLAGS := -I../../../scsi/ - -list-multi := usb-storage.o - -obj-$(CONFIG_USB_STORAGE) += usb-storage.o - -usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o -usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o -usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o -usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o -usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA) += shuttle_sm.o -usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o -usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o -usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o -usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o -usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o - -usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ - initializers.o $(usb-storage-obj-y) - -include $(TOPDIR)/Rules.make - -usb-storage.o: $(usb-storage-objs) - $(LD) -r -o $@ $(usb-storage-objs) diff --git a/drivers/usb/class/storage/datafab.c b/drivers/usb/class/storage/datafab.c deleted file mode 100644 index d1aca3be8627..000000000000 --- a/drivers/usb/class/storage/datafab.c +++ /dev/null @@ -1,806 +0,0 @@ -/* Driver for Datafab USB Compact Flash reader - * - * datafab driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver - * which I used as a template for this driver. - * Some bugfixes and scatter-gather code by Gregory P. Smith - * (greg-usb@electricrain.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, 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. - */ - -/* - * This driver attempts to support USB CompactFlash reader/writer devices - * based on Datafab USB-to-ATA chips. It was specifically developed for the - * Datafab MDCFE-B USB CompactFlash reader but has since been found to work - * with a variety of Datafab-based devices from a number of manufacturers. - * I've received a report of this driver working with a Datafab-based - * SmartMedia device though please be aware that I'm personally unable to - * test SmartMedia support. - * - * This driver supports reading and writing. If you're truly paranoid, - * however, you can force the driver into a write-protected state by setting - * the WP enable bits in datafab_handle_mode_sense(). Basically this means - * setting mode_param_header[3] = 0x80. - */ - -#include "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "datafab.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> - -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - -static int datafab_determine_lun(struct us_data *us, struct datafab_info *info); - - -static void datafab_dump_data(unsigned char *data, int len) -{ - unsigned char buf[80]; - int sofar = 0; - - if (!data) - return; - - memset(buf, 0, sizeof(buf)); - - for (sofar = 0; sofar < len; sofar++) { - sprintf(buf + strlen(buf), "%02x ", - ((unsigned int) data[sofar]) & 0xFF); - - if (sofar % 16 == 15) { - US_DEBUGP("datafab: %s\n", buf); - memset(buf, 0, sizeof(buf)); - } - } - - if (strlen(buf) != 0) - US_DEBUGP("datafab: %s\n", buf); -} - - -static int datafab_raw_bulk(int direction, - struct us_data *us, - unsigned char *data, - unsigned int len) -{ - int result; - int act_len; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); - - // if we stall, we need to clear it before we go on - if (result == -EPIPE) { - US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); - } - - if (result) { - // NAK - that means we've retried a few times already - if (result == -ETIMEDOUT) { - US_DEBUGP("datafab_raw_bulk: device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - // -ENOENT -- we canceled this transfer - if (result == -ENOENT) { - US_DEBUGP("datafab_raw_bulk: transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - if (result == -EPIPE) { - US_DEBUGP("datafab_raw_bulk: output pipe stalled\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - // the catch-all case - US_DEBUGP("datafab_raw_bulk: unknown error\n"); - return US_BULK_TRANSFER_FAILED; - } - - if (act_len != len) { - US_DEBUGP("datafab_raw_bulk: Warning. Transferred only %d bytes\n", act_len); - return US_BULK_TRANSFER_SHORT; - } - - US_DEBUGP("datafab_raw_bulk: Transfered %d of %d bytes\n", act_len, len); - return US_BULK_TRANSFER_GOOD; -} - -static inline int datafab_bulk_read(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_TRANSPORT_GOOD; - - US_DEBUGP("datafab_bulk_read: len = %d\n", len); - return datafab_raw_bulk(SCSI_DATA_READ, us, data, len); -} - - -static inline int datafab_bulk_write(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_TRANSPORT_GOOD; - - US_DEBUGP("datafab_bulk_write: len = %d\n", len); - return datafab_raw_bulk(SCSI_DATA_WRITE, us, data, len); -} - - -static int datafab_read_data(struct us_data *us, - struct datafab_info *info, - u32 sector, - u32 sectors, - unsigned char *dest, - int use_sg) -{ - unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x20, 0x01 }; - unsigned char *buffer = NULL; - unsigned char *ptr; - unsigned char thistime; - struct scatterlist *sg = NULL; - int totallen, len, result; - int sg_idx = 0, current_sg_offset = 0; - int transferred, rc; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Datafab - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sectors > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - rc = datafab_determine_lun(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - } - - command[5] += (info->lun << 4); - - // If we're using scatter-gather, we have to create a new - // buffer to read all of the data in first, since a - // scatter-gather buffer could in theory start in the middle - // of a page, which would be bad. A developer who wants a - // challenge might want to write a limited-buffer - // version of this code. - - totallen = sectors * info->ssize; - - do { - // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit) - len = min_t(int, totallen, 65536); - - if (use_sg) { - sg = (struct scatterlist *) dest; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - ptr = buffer; - } else { - ptr = dest; - } - - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] |= (sector >> 24) & 0x0F; - - // send the command - US_DEBUGP("datafab_read_data: sending following command\n"); - datafab_dump_data(command, sizeof(command)); - - result = datafab_bulk_write(us, command, sizeof(command)); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - // read the result - result = datafab_bulk_read(us, ptr, len); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - US_DEBUGP("datafab_read_data results: %d bytes\n", len); - // datafab_dump_data(ptr, len); - - sectors -= thistime; - sector += thistime; - - if (use_sg) { - transferred = 0; - while (sg_idx < use_sg && transferred < len) { - if (len - transferred >= sg[sg_idx].length - current_sg_offset) { - US_DEBUGP("datafab_read_data: adding %d bytes to %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length); - memcpy(sg[sg_idx].address + current_sg_offset, - buffer + transferred, - sg[sg_idx].length - current_sg_offset); - transferred += sg[sg_idx].length - current_sg_offset; - current_sg_offset = 0; - // on to the next sg buffer - ++sg_idx; - } else { - US_DEBUGP("datafab_read_data: adding %d bytes to %d byte sg buffer\n", len - transferred, sg[sg_idx].length); - memcpy(sg[sg_idx].address + current_sg_offset, - buffer + transferred, - len - transferred); - current_sg_offset += len - transferred; - // this sg buffer is only partially full and we're out of data to copy in - break; - } - } - kfree(buffer); - } else { - dest += len; - } - - totallen -= len; - } while (totallen > 0); - - return USB_STOR_TRANSPORT_GOOD; -} - - -static int datafab_write_data(struct us_data *us, - struct datafab_info *info, - u32 sector, - u32 sectors, - unsigned char *src, - int use_sg) -{ - unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x30, 0x02 }; - unsigned char reply[2] = { 0, 0 }; - unsigned char *buffer = NULL; - unsigned char *ptr; - unsigned char thistime; - struct scatterlist *sg = NULL; - int totallen, len, result; - int sg_idx = 0, current_sg_offset = 0; - int transferred, rc; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Datafab - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sectors > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - rc = datafab_determine_lun(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - } - - command[5] += (info->lun << 4); - - // If we're using scatter-gather, we have to create a new - // buffer to read all of the data in first, since a - // scatter-gather buffer could in theory start in the middle - // of a page, which would be bad. A developer who wants a - // challenge might want to write a limited-buffer - // version of this code. - - totallen = sectors * info->ssize; - - do { - // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit) - len = min_t(int, totallen, 65536); - - if (use_sg) { - sg = (struct scatterlist *) src; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - ptr = buffer; - - memset(buffer, 0, len); - - // copy the data from the sg bufs into the big contiguous buf - // - transferred = 0; - while (transferred < len) { - if (len - transferred >= sg[sg_idx].length - current_sg_offset) { - US_DEBUGP("datafab_write_data: getting %d bytes from %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length); - memcpy(ptr + transferred, - sg[sg_idx].address + current_sg_offset, - sg[sg_idx].length - current_sg_offset); - transferred += sg[sg_idx].length - current_sg_offset; - current_sg_offset = 0; - // on to the next sg buffer - ++sg_idx; - } else { - US_DEBUGP("datafab_write_data: getting %d bytes from %d byte sg buffer\n", len - transferred, sg[sg_idx].length); - memcpy(ptr + transferred, - sg[sg_idx].address + current_sg_offset, - len - transferred); - current_sg_offset += len - transferred; - // we only copied part of this sg buffer - break; - } - } - } else { - ptr = src; - } - - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] |= (sector >> 24) & 0x0F; - - // send the command - US_DEBUGP("datafab_write_data: sending following command\n"); - datafab_dump_data(command, sizeof(command)); - - result = datafab_bulk_write(us, command, sizeof(command)); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - // send the data - result = datafab_bulk_write(us, ptr, len); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - // read the result - result = datafab_bulk_read(us, reply, sizeof(reply)); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - if (reply[0] != 0x50 && reply[1] != 0) { - US_DEBUGP("datafab_write_data: Gah! write return code: %02x %02x\n", reply[0], reply[1]); - if (use_sg) - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; - } - - sectors -= thistime; - sector += thistime; - - if (use_sg) { - kfree(buffer); - } else { - src += len; - } - - totallen -= len; - } while (totallen > 0); - - return USB_STOR_TRANSPORT_GOOD; -} - - -static int datafab_determine_lun(struct us_data *us, - struct datafab_info *info) -{ - // dual-slot readers can be thought of as dual-LUN devices. we need to - // determine which card slot is being used. we'll send an IDENTIFY DEVICE - // command and see which LUN responds... - // - // there might be a better way of doing this? - // - unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; - unsigned char buf[512]; - int count = 0, rc; - - if (!us || !info) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("datafab_determine_lun: locating...\n"); - - // we'll try 10 times before giving up... - // - while (count++ < 10) { - command[5] = 0xa0; - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - rc = datafab_bulk_read(us, buf, sizeof(buf)); - if (rc == USB_STOR_TRANSPORT_GOOD) { - info->lun = 0; - return USB_STOR_TRANSPORT_GOOD; - } - - command[5] = 0xb0; - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - rc = datafab_bulk_read(us, buf, sizeof(buf)); - if (rc == USB_STOR_TRANSPORT_GOOD) { - info->lun = 1; - return USB_STOR_TRANSPORT_GOOD; - } - - wait_ms(20); - } - - return USB_STOR_TRANSPORT_FAILED; -} - -static int datafab_id_device(struct us_data *us, - struct datafab_info *info) -{ - // this is a variation of the ATA "IDENTIFY DEVICE" command...according - // to the ATA spec, 'Sector Count' isn't used but the Windows driver - // sets this bit so we do too... - // - unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; - unsigned char reply[512]; - int rc; - - if (!us || !info) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - rc = datafab_determine_lun(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - } - - command[5] += (info->lun << 4); - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - // we'll go ahead and extract the media capacity while we're here... - // - rc = datafab_bulk_read(us, reply, sizeof(reply)); - if (rc == USB_STOR_TRANSPORT_GOOD) { - // capacity is at word offset 57-58 - // - info->sectors = ((u32)(reply[117]) << 24) | - ((u32)(reply[116]) << 16) | - ((u32)(reply[115]) << 8) | - ((u32)(reply[114]) ); - } - - return rc; -} - - -static int datafab_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, - unsigned char *ptr, - int sense_6) -{ - unsigned char mode_param_header[8] = { - 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char rw_err_page[12] = { - 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 - }; - unsigned char cache_page[12] = { - 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char rbac_page[12] = { - 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char timer_page[8] = { - 0x1C, 0x6, 0, 0, 0, 0 - }; - unsigned char pc, page_code; - unsigned short total_len = 0; - unsigned short param_len, i = 0; - - // most of this stuff is just a hack to get things working. the - // datafab reader doesn't present a SCSI interface so we - // fudge the SCSI commands... - // - - if (sense_6) - param_len = srb->cmnd[4]; - else - param_len = ((u16) (srb->cmnd[7]) >> 8) | ((u16) (srb->cmnd[8])); - - pc = srb->cmnd[2] >> 6; - page_code = srb->cmnd[2] & 0x3F; - - switch (pc) { - case 0x0: - US_DEBUGP("datafab_handle_mode_sense: Current values\n"); - break; - case 0x1: - US_DEBUGP("datafab_handle_mode_sense: Changeable values\n"); - break; - case 0x2: - US_DEBUGP("datafab_handle_mode_sense: Default values\n"); - break; - case 0x3: - US_DEBUGP("datafab_handle_mode_sense: Saves values\n"); - break; - } - - mode_param_header[3] = 0x80; // write enable - - switch (page_code) { - case 0x0: - // vendor-specific mode - return USB_STOR_TRANSPORT_ERROR; - - case 0x1: - total_len = sizeof(rw_err_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - break; - - case 0x8: - total_len = sizeof(cache_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - break; - - case 0x1B: - total_len = sizeof(rbac_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - break; - - case 0x1C: - total_len = sizeof(timer_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, timer_page, sizeof(timer_page)); - break; - - case 0x3F: // retrieve all pages - total_len = sizeof(timer_page) + sizeof(rbac_page) + - sizeof(cache_page) + sizeof(rw_err_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - break; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -void datafab_info_destructor(void *extra) -{ - // this routine is a placeholder... - // currently, we don't allocate any extra memory so we're okay -} - - -// Transport for the Datafab MDCFE-B -// -int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) -{ - struct datafab_info *info; - int rc; - unsigned long block, blocks; - unsigned char *ptr = NULL; - unsigned char inquiry_reply[36] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - if (!us->extra) { - us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("datafab_transport: Gah! Can't allocate storage for Datafab info struct!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - memset(us->extra, 0, sizeof(struct datafab_info)); - us->extra_destructor = datafab_info_destructor; - ((struct datafab_info *)us->extra)->lun = -1; - } - - info = (struct datafab_info *) (us->extra); - ptr = (unsigned char *) srb->request_buffer; - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response"); - memset( inquiry_reply + 8, 0, 28 ); - fill_inquiry_response(us, inquiry_reply, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec - rc = datafab_id_device(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); - - // build the reply - // - ptr[0] = (info->sectors >> 24) & 0xFF; - ptr[1] = (info->sectors >> 16) & 0xFF; - ptr[2] = (info->sectors >> 8) & 0xFF; - ptr[3] = (info->sectors) & 0xFF; - - ptr[4] = (info->ssize >> 24) & 0xFF; - ptr[5] = (info->ssize >> 16) & 0xFF; - ptr[6] = (info->ssize >> 8) & 0xFF; - ptr[7] = (info->ssize) & 0xFF; - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("datafab_transport: Gah! MODE_SELECT_10.\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - // don't bother implementing READ_6 or WRITE_6. Just set MODE_XLATE and - // let the usb storage code convert to READ_10/WRITE_10 - // - if (srb->cmnd[0] == READ_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("datafab_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); - return datafab_read_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == READ_12) { - // we'll probably never see a READ_12 but we'll do it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("datafab_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); - return datafab_read_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == WRITE_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("datafab_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); - return datafab_write_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == WRITE_12) { - // we'll probably never see a WRITE_12 but we'll do it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); - return datafab_write_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n"); - return datafab_id_device(us, info); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("datafab_transport: REQUEST_SENSE. Returning faked response\n"); - - // this response is pretty bogus right now. eventually if necessary - // we can set the correct sense data. so far though it hasn't been - // necessary - // - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); - return datafab_handle_mode_sense(us, srb, ptr, TRUE); - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); - return datafab_handle_mode_sense(us, srb, ptr, FALSE); - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from - // popping the media out of the device (no locking doors, etc) - // - return USB_STOR_TRANSPORT_GOOD; - } - - US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); - return USB_STOR_TRANSPORT_ERROR; -} diff --git a/drivers/usb/class/storage/datafab.h b/drivers/usb/class/storage/datafab.h deleted file mode 100644 index 5515583ddce3..000000000000 --- a/drivers/usb/class/storage/datafab.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Driver for Datafab MDCFE-B USB Compact Flash reader - * Header File - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * - * See datafab.c for more explanation - * - * 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, 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. - */ - -#ifndef _USB_DATAFAB_MDCFE_B_H -#define _USB_DATAFAB_MDCFE_B_H - -extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); - -struct datafab_info { - unsigned long sectors; // total sector count - unsigned long ssize; // sector size in bytes - char lun; // used for dual-slot readers - - // the following aren't used yet - unsigned char sense_key; - unsigned long sense_asc; // additional sense code - unsigned long sense_ascq; // additional sense code qualifier -}; - -#endif diff --git a/drivers/usb/class/storage/debug.c b/drivers/usb/class/storage/debug.c deleted file mode 100644 index 3556bfd41500..000000000000 --- a/drivers/usb/class/storage/debug.c +++ /dev/null @@ -1,369 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Debugging Functions Source Code File - * - * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "debug.h" - -void usb_stor_show_command(Scsi_Cmnd *srb) -{ - char *what = NULL; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; - case REZERO_UNIT: what = "REZERO_UNIT"; break; - case REQUEST_SENSE: what = "REQUEST_SENSE"; break; - case FORMAT_UNIT: what = "FORMAT_UNIT"; break; - case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; - case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; - case READ_6: what = "READ_6"; break; - case WRITE_6: what = "WRITE_6"; break; - case SEEK_6: what = "SEEK_6"; break; - case READ_REVERSE: what = "READ_REVERSE"; break; - case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; - case SPACE: what = "SPACE"; break; - case INQUIRY: what = "INQUIRY"; break; - case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; - case MODE_SELECT: what = "MODE_SELECT"; break; - case RESERVE: what = "RESERVE"; break; - case RELEASE: what = "RELEASE"; break; - case COPY: what = "COPY"; break; - case ERASE: what = "ERASE"; break; - case MODE_SENSE: what = "MODE_SENSE"; break; - case START_STOP: what = "START_STOP"; break; - case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; - case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; - case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; - case SET_WINDOW: what = "SET_WINDOW"; break; - case READ_CAPACITY: what = "READ_CAPACITY"; break; - case READ_10: what = "READ_10"; break; - case WRITE_10: what = "WRITE_10"; break; - case SEEK_10: what = "SEEK_10"; break; - case WRITE_VERIFY: what = "WRITE_VERIFY"; break; - case VERIFY: what = "VERIFY"; break; - case SEARCH_HIGH: what = "SEARCH_HIGH"; break; - case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; - case SEARCH_LOW: what = "SEARCH_LOW"; break; - case SET_LIMITS: what = "SET_LIMITS"; break; - case READ_POSITION: what = "READ_POSITION"; break; - case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; - case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; - case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; - case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; - case COMPARE: what = "COMPARE"; break; - case COPY_VERIFY: what = "COPY_VERIFY"; break; - case WRITE_BUFFER: what = "WRITE_BUFFER"; break; - case READ_BUFFER: what = "READ_BUFFER"; break; - case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; - case READ_LONG: what = "READ_LONG"; break; - case WRITE_LONG: what = "WRITE_LONG"; break; - case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; - case WRITE_SAME: what = "WRITE_SAME"; break; - case GPCMD_READ_SUBCHANNEL: what = "READ SUBCHANNEL"; break; - case READ_TOC: what = "READ_TOC"; break; - case GPCMD_READ_HEADER: what = "READ HEADER"; break; - case GPCMD_PLAY_AUDIO_10: what = "PLAY AUDIO (10)"; break; - case GPCMD_PLAY_AUDIO_MSF: what = "PLAY AUDIO MSF"; break; - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - what = "GET EVENT/STATUS NOTIFICATION"; break; - case GPCMD_PAUSE_RESUME: what = "PAUSE/RESUME"; break; - case LOG_SELECT: what = "LOG_SELECT"; break; - case LOG_SENSE: what = "LOG_SENSE"; break; - case GPCMD_STOP_PLAY_SCAN: what = "STOP PLAY/SCAN"; break; - case GPCMD_READ_DISC_INFO: what = "READ DISC INFORMATION"; break; - case GPCMD_READ_TRACK_RZONE_INFO: - what = "READ TRACK INFORMATION"; break; - case GPCMD_RESERVE_RZONE_TRACK: what = "RESERVE TRACK"; break; - case GPCMD_SEND_OPC: what = "SEND OPC"; break; - case MODE_SELECT_10: what = "MODE_SELECT_10"; break; - case GPCMD_REPAIR_RZONE_TRACK: what = "REPAIR TRACK"; break; - case 0x59: what = "READ MASTER CUE"; break; - case MODE_SENSE_10: what = "MODE_SENSE_10"; break; - case GPCMD_CLOSE_TRACK: what = "CLOSE TRACK/SESSION"; break; - case 0x5C: what = "READ BUFFER CAPACITY"; break; - case 0x5D: what = "SEND CUE SHEET"; break; - case GPCMD_BLANK: what = "BLANK"; break; - case MOVE_MEDIUM: what = "MOVE_MEDIUM or PLAY AUDIO (12)"; break; - case READ_12: what = "READ_12"; break; - case WRITE_12: what = "WRITE_12"; break; - case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; - case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; - case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; - case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; - case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; - case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; - case GPCMD_READ_CD_MSF: what = "READ CD MSF"; break; - case GPCMD_SCAN: what = "SCAN"; break; - case GPCMD_SET_SPEED: what = "SET CD SPEED"; break; - case GPCMD_MECHANISM_STATUS: what = "MECHANISM STATUS"; break; - case GPCMD_READ_CD: what = "READ CD"; break; - case 0xE1: what = "WRITE CONTINUE"; break; - case WRITE_LONG_2: what = "WRITE_LONG_2"; break; - default: what = "(unknown command)"; break; - } - US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len); - US_DEBUGP("%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], - srb->cmnd[4], srb->cmnd[5], srb->cmnd[6], srb->cmnd[7], - srb->cmnd[8], srb->cmnd[9], srb->cmnd[10], - srb->cmnd[11]); -} - -void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ) -{ - int i=0, bufferSize = cmd->request_bufflen; - u8* buffer = cmd->request_buffer; - struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer; - - US_DEBUGP("Dumping information about %p.\n", cmd ); - US_DEBUGP("cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] ); - US_DEBUGP("(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n", - MODE_SENSE, MODE_SENSE_10 ); - - US_DEBUGP("buffer is %p with length %d.\n", buffer, bufferSize ); - for ( i=0; i<bufferSize; i+=16 ) - { - US_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x\n" - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - buffer[i], - buffer[i+1], - buffer[i+2], - buffer[i+3], - buffer[i+4], - buffer[i+5], - buffer[i+6], - buffer[i+7], - buffer[i+8], - buffer[i+9], - buffer[i+10], - buffer[i+11], - buffer[i+12], - buffer[i+13], - buffer[i+14], - buffer[i+15] ); - } - - US_DEBUGP("Buffer has %d scatterlists.\n", cmd->use_sg ); - for ( i=0; i<cmd->use_sg; i++ ) - { - char *adr = page_address(sg[i].page) + sg[i].offset; - - US_DEBUGP("Length of scatterlist %d is %d.\n",i,sg[i].length); - US_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x\n" - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - adr[0], - adr[1], - adr[2], - adr[3], - adr[4], - adr[5], - adr[6], - adr[7], - adr[8], - adr[9], - adr[10], - adr[11], - adr[12], - adr[13], - adr[14], - adr[15]); - } -} - -void usb_stor_show_sense( - unsigned char key, - unsigned char asc, - unsigned char ascq) { - - char *keys[] = { - "No Sense", - "Recovered Error", - "Not Ready", - "Medium Error", - "Hardware Error", - "Illegal Request", - "Unit Attention", - "Data Protect", - "Blank Check", - "Vendor Specific", - "Copy Aborted", - "Aborted Command", - "(Obsolete)", - "Volume Overflow", - "Miscompare" - }; - - unsigned short qual = asc; - - char *what = 0; - char *keystr = 0; - - qual <<= 8; - qual |= ascq; - - if (key>0x0E) - keystr = "(Unknown Key)"; - else - keystr = keys[key]; - - switch (qual) { - - case 0x0000: what="no additional sense information"; break; - case 0x0001: what="filemark detected"; break; - case 0x0002: what="end of partition/medium detected"; break; - case 0x0003: what="setmark detected"; break; - case 0x0004: what="beginning of partition/medium detected"; break; - case 0x0005: what="end of data detected"; break; - case 0x0006: what="I/O process terminated"; break; - case 0x0011: what="audio play operation in progress"; break; - case 0x0012: what="audio play operation paused"; break; - case 0x0013: what="audio play operation stopped due to error"; break; - case 0x0014: what="audio play operation successfully completed"; break; - case 0x0015: what="no current audio status to return"; break; - case 0x0016: what="operation in progress"; break; - case 0x0017: what="cleaning requested"; break; - case 0x0100: what="no index/sector signal"; break; - case 0x0200: what="no seek complete"; break; - case 0x0300: what="peripheral device write fault"; break; - case 0x0301: what="no write current"; break; - case 0x0302: what="excessive write errors"; break; - case 0x0400: what="LUN not ready, cause not reportable"; break; - case 0x0401: what="LUN in process of becoming ready"; break; - case 0x0402: what="LUN not ready, initializing cmd. required"; break; - case 0x0403: what="LUN not ready, manual intervention required"; break; - case 0x0404: what="LUN not ready, format in progress"; break; - case 0x0405: what="LUN not ready, rebuild in progress"; break; - case 0x0406: what="LUN not ready, recalculation in progress"; break; - case 0x0407: what="LUN not ready, operation in progress"; break; - case 0x0408: what="LUN not ready, long write in progress"; break; - case 0x0500: what="LUN doesn't respond to selection"; break; - case 0x0A00: what="error log overflow"; break; - case 0x0C04: what="compression check miscompare error"; break; - case 0x0C05: what="data expansion occurred during compression"; break; - case 0x0C06: what="block not compressible"; break; - case 0x1102: what="error too long to correct"; break; - case 0x1106: what="CIRC unrecovered error"; break; - case 0x1107: what="data resynchronization error"; break; - case 0x110D: what="decompression CRC error"; break; - case 0x110E: what="can't decompress using declared algorithm"; break; - case 0x110F: what="error reading UPC/EAN number"; break; - case 0x1110: what="error reading ISRC number"; break; - case 0x1200: what="address mark not found for ID field"; break; - case 0x1300: what="address mark not found for data field"; break; - case 0x1403: what="end of data not found"; break; - case 0x1404: what="block sequence error"; break; - case 0x1600: what="data sync mark error"; break; - case 0x1601: what="data sync error: data rewritten"; break; - case 0x1602: what="data sync error: recommend rewrite"; break; - case 0x1603: what="data sync error: data auto-reallocated"; break; - case 0x1604: what="data sync error: recommend reassignment"; break; - case 0x1900: what="defect list error"; break; - case 0x1901: what="defect list not available"; break; - case 0x1902: what="defect list error in primary list"; break; - case 0x1903: what="defect list error in grown list"; break; - case 0x1C00: what="defect list not found"; break; - case 0x2400: what="invalid field in CDB"; break; - case 0x2703: what="associated write protect"; break; - case 0x2800: what="not ready to ready transition"; break; - case 0x2903: what="bus device reset function occurred"; break; - case 0x2904: what="device internal reset"; break; - case 0x2B00: what="copy can't execute / host can't disconnect"; break; - case 0x2C00: what="command sequence error"; break; - case 0x2C03: what="current program area is not empty"; break; - case 0x2C04: what="current program area is empty"; break; - case 0x2F00: what="commands cleared by another initiator"; break; - case 0x3001: what="can't read medium: unknown format"; break; - case 0x3002: what="can't read medium: incompatible format"; break; - case 0x3003: what="cleaning cartridge installed"; break; - case 0x3004: what="can't write medium: unknown format"; break; - case 0x3005: what="can't write medium: incompatible format"; break; - case 0x3006: what="can't format medium: incompatible medium"; break; - case 0x3007: what="cleaning failure"; break; - case 0x3008: what="can't write: application code mismatch"; break; - case 0x3009: what="current session not fixated for append"; break; - case 0x3201: what="defect list update failure"; break; - case 0x3400: what="enclosure failure"; break; - case 0x3500: what="enclosure services failure"; break; - case 0x3502: what="enclosure services unavailable"; break; - case 0x3503: what="enclosure services transfer failure"; break; - case 0x3504: what="enclosure services transfer refused"; break; - case 0x3B0F: what="end of medium reached"; break; - case 0x3F02: what="changed operating definition"; break; - case 0x4100: what="data path failure (should use 40 NN)"; break; - case 0x4A00: what="command phase error"; break; - case 0x4B00: what="data phase error"; break; - case 0x5100: what="erase failure"; break; - case 0x5200: what="cartridge fault"; break; - case 0x6300: what="end of user area encountered on this track"; break; - case 0x6600: what="automatic document feeder cover up"; break; - case 0x6601: what="automatic document feeder lift up"; break; - case 0x6602: what="document jam in auto doc feeder"; break; - case 0x6603: what="document miss feed auto in doc feeder"; break; - case 0x6700: what="configuration failure"; break; - case 0x6701: what="configuration of incapable LUN's failed"; break; - case 0x6702: what="add logical unit failed"; break; - case 0x6706: what="attachment of logical unit failed"; break; - case 0x6707: what="creation of logical unit failed"; break; - case 0x6900: what="data loss on logical unit"; break; - case 0x6E00: what="command to logical unit failed"; break; - case 0x7100: what="decompression exception long algorithm ID"; break; - case 0x7204: what="empty or partially written reserved track"; break; - case 0x7300: what="CD control error"; break; - - default: - if (asc==0x40) { - US_DEBUGP("%s: diagnostic failure on component" - " %02X\n", keystr, ascq); - return; - } - if (asc==0x70) { - US_DEBUGP("%s: decompression exception short" - " algorithm ID of %02X\n", keystr, ascq); - return; - } - what = "(unknown ASC/ASCQ)"; - } - - US_DEBUGP("%s: %s\n", keystr, what); -} - diff --git a/drivers/usb/class/storage/debug.h b/drivers/usb/class/storage/debug.h deleted file mode 100644 index c5477dcaf55d..000000000000 --- a/drivers/usb/class/storage/debug.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Debugging Functions Header File - * - * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -#ifndef _DEBUG_H_ -#define _DEBUG_H_ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/blk.h> -#include <linux/cdrom.h> -#include "scsi.h" - -#define USB_STORAGE "usb-storage: " - -#ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(Scsi_Cmnd *srb); -void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ); -void usb_stor_show_sense( unsigned char key, - unsigned char asc, unsigned char ascq ); -#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) -#define US_DEBUGPX(x...) printk( x ) -#define US_DEBUG(x) x -#else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) -#define US_DEBUG(x) -#endif - -#endif diff --git a/drivers/usb/class/storage/dpcm.c b/drivers/usb/class/storage/dpcm.c deleted file mode 100644 index 5f7e8d4673a6..000000000000 --- a/drivers/usb/class/storage/dpcm.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader - * - * $Id: dpcm.c,v 1.4 2001/06/11 02:54:25 mdharm Exp $ - * - * DPCM driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Brian Webb (webbb@earthlink.net) - * - * This device contains both a CompactFlash card reader, which - * uses the Control/Bulk w/o Interrupt protocol and - * a SmartMedia card reader that uses the same protocol - * as the SDDR09. - * - * 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, 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 "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "dpcm.h" -#include "sddr09.h" - -/* - * Transport for the Microtech DPCM-USB - * - */ -int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int ret; - - if(srb == NULL) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("dpcm_transport: LUN=%d\n", srb->lun); - - switch(srb->lun) { - case 0: - - /* - * LUN 0 corresponds to the CompactFlash card reader. - */ - return usb_stor_CB_transport(srb, us); - -#ifdef CONFIG_USB_STORAGE_SDDR09 - case 1: - - /* - * LUN 1 corresponds to the SmartMedia card reader. - */ - - /* - * Set the LUN to 0 (just in case). - */ - srb->lun = 0; us->srb->lun = 0; - ret = sddr09_transport(srb, us); - srb->lun = 1; us->srb->lun = 1; - - return ret; -#endif - - default: - US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->lun); - return USB_STOR_TRANSPORT_ERROR; - } -} diff --git a/drivers/usb/class/storage/dpcm.h b/drivers/usb/class/storage/dpcm.h deleted file mode 100644 index e6e5637d65a9..000000000000 --- a/drivers/usb/class/storage/dpcm.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader - * - * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $ - * - * DPCM driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Brian Webb (webbb@earthlink.net) - * - * See dpcm.c for more explanation - * - * 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, 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. - */ - -#ifndef _MICROTECH_DPCM_USB_H -#define _MICROTECH_DPCM_USB_H - -extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); - -#endif diff --git a/drivers/usb/class/storage/freecom.c b/drivers/usb/class/storage/freecom.c deleted file mode 100644 index f273ea54f635..000000000000 --- a/drivers/usb/class/storage/freecom.c +++ /dev/null @@ -1,707 +0,0 @@ -/* Driver for Freecom USB/IDE adaptor - * - * $Id: freecom.c,v 1.21 2001/12/29 03:47:33 mdharm Exp $ - * - * Freecom v0.1: - * - * First release - * - * Current development and maintenance by: - * (C) 2000 David Brown <usb-storage@davidb.org> - * - * 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, 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. - * - * This driver was developed with information provided in FREECOM's USB - * Programmers Reference Guide. For further information contact Freecom - * (http://www.freecom.de/) - */ - -#include <linux/config.h> -#include "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "freecom.h" -#include "linux/hdreg.h" - -#ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *, int); -#endif - -struct freecom_udata { - __u8 buffer[64]; /* Common command block. */ -}; -typedef struct freecom_udata *freecom_udata_t; - -/* All of the outgoing packets are 64 bytes long. */ -struct freecom_cb_wrap { - __u8 Type; /* Command type. */ - __u8 Timeout; /* Timeout in seconds. */ - __u8 Atapi[12]; /* An ATAPI packet. */ - __u8 Filler[50]; /* Padding Data. */ -}; - -struct freecom_xfer_wrap { - __u8 Type; /* Command type. */ - __u8 Timeout; /* Timeout in seconds. */ - __u32 Count; /* Number of bytes to transfer. */ - __u8 Pad[58]; -} __attribute__ ((packed)); - -struct freecom_ide_out { - __u8 Type; /* Type + IDE register. */ - __u8 Pad; - __u16 Value; /* Value to write. */ - __u8 Pad2[60]; -}; - -struct freecom_ide_in { - __u8 Type; /* Type | IDE register. */ - __u8 Pad[63]; -}; - -struct freecom_status { - __u8 Status; - __u8 Reason; - __u16 Count; - __u8 Pad[60]; -}; - -/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide - * register. */ -#define FCM_INT_STATUS 0x02 /* INDEX_STAT */ -#define FCM_STATUS_BUSY 0x80 - -/* These are the packet types. The low bit indicates that this command - * should wait for an interrupt. */ -#define FCM_PACKET_ATAPI 0x21 -#define FCM_PACKET_STATUS 0x20 - -/* Receive data from the IDE interface. The ATAPI packet has already - * waited, so the data should be immediately available. */ -#define FCM_PACKET_INPUT 0x81 - -/* Send data to the IDE interface. */ -#define FCM_PACKET_OUTPUT 0x01 - -/* Write a value to an ide register. Or the ide register to write after - * munging the address a bit. */ -#define FCM_PACKET_IDE_WRITE 0x40 -#define FCM_PACKET_IDE_READ 0xC0 - -/* All packets (except for status) are 64 bytes long. */ -#define FCM_PACKET_LENGTH 64 - -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); - - /* End this if we're done */ - if (transfer_amount == total_transferred) - break; - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - page_address(sg[i].page) + sg[i].offset, sg[i].length); - total_transferred += sg[i].length; - } else { - result = usb_stor_transfer_partial(us, - page_address(sg[i].page) + sg[i].offset, - transfer_amount - total_transferred); - total_transferred += transfer_amount - total_transferred; - } - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - -#if 0 -/* Write a value to an ide register. */ -static int -freecom_ide_write (struct us_data *us, int reg, int value) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_ide_out *ideout = - (struct freecom_ide_out *) extra->buffer; - int opipe; - int result, partial; - - US_DEBUGP("IDE out 0x%02x <- 0x%02x\n", reg, value); - - /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - - if (reg < 0 || reg > 8) - return USB_STOR_TRANSPORT_ERROR; - if (reg < 8) - reg |= 0x20; - else - reg = 0x0e; - - ideout->Type = FCM_PACKET_IDE_WRITE | reg; - ideout->Pad = 0; - ideout->Value = cpu_to_le16 (value); - memset (ideout->Pad2, 0, sizeof (ideout->Pad2)); - - result = usb_stor_bulk_msg (us, ideout, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* Read a value from an ide register. */ -static int -freecom_ide_read (struct us_data *us, int reg, int *value) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_ide_in *idein = - (struct freecom_ide_in *) extra->buffer; - __u8 *buffer = extra->buffer; - int ipipe, opipe; - int result, partial; - int desired_length; - - /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); - - if (reg < 0 || reg > 8) - return USB_STOR_TRANSPORT_ERROR; - if (reg < 8) - reg |= 0x10; - else - reg = 0x0e; - - US_DEBUGP("IDE in request for register 0x%02x\n", reg); - - idein->Type = FCM_PACKET_IDE_READ | reg; - memset (idein->Pad, 0, sizeof (idein->Pad)); - - result = usb_stor_bulk_msg (us, idein, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - - desired_length = 1; - if (reg == 0x10) - desired_length = 2; - - result = usb_stor_bulk_msg (us, buffer, ipipe, - desired_length, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - US_DEBUGP("IDE in partial is %d\n", partial); - - if (desired_length == 1) - *value = buffer[0]; - else - *value = le16_to_cpu (*(__u16 *) buffer); - - US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value); - - return USB_STOR_TRANSPORT_GOOD; -} -#endif - -static int -freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_xfer_wrap *fxfr = - (struct freecom_xfer_wrap *) extra->buffer; - int result, partial; - - fxfr->Type = FCM_PACKET_INPUT | 0x00; - fxfr->Timeout = 0; /* Short timeout for debugging. */ - fxfr->Count = cpu_to_le32 (count); - memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - - US_DEBUGP("Read data Freecom! (c=%d)\n", count); - - /* Issue the transfer command. */ - result = usb_stor_bulk_msg (us, fxfr, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n", - result, partial); - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_readdata(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - return USB_STOR_TRANSPORT_ERROR; - } - US_DEBUGP("Done issuing read request: %d %d\n", result, partial); - - /* Now transfer all of our blocks. */ - US_DEBUGP("Start of read\n"); - us_transfer_freecom(srb, us, count); - US_DEBUGP("freecom_readdata done!\n"); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int -freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_xfer_wrap *fxfr = - (struct freecom_xfer_wrap *) extra->buffer; - int result, partial; - - fxfr->Type = FCM_PACKET_OUTPUT | 0x00; - fxfr->Timeout = 0; /* Short timeout for debugging. */ - fxfr->Count = cpu_to_le32 (count); - memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - - US_DEBUGP("Write data Freecom! (c=%d)\n", count); - - /* Issue the transfer command. */ - result = usb_stor_bulk_msg (us, fxfr, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n", - result, partial); - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_writedata(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - return USB_STOR_TRANSPORT_ERROR; - } - US_DEBUGP("Done issuing write request: %d %d\n", - result, partial); - - /* Now transfer all of our blocks. */ - US_DEBUGP("Start of write\n"); - us_transfer_freecom(srb, us, count); - - US_DEBUGP("freecom_writedata done!\n"); - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Transport for the Freecom USB/IDE adaptor. - * - */ -int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - struct freecom_cb_wrap *fcb; - struct freecom_status *fst; - int ipipe, opipe; /* We need both pipes. */ - int result; - int partial; - int length; - freecom_udata_t extra; - - extra = (freecom_udata_t) us->extra; - - fcb = (struct freecom_cb_wrap *) extra->buffer; - fst = (struct freecom_status *) extra->buffer; - - US_DEBUGP("Freecom TRANSPORT STARTED\n"); - - /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); - - /* The ATAPI Command always goes out first. */ - fcb->Type = FCM_PACKET_ATAPI | 0x00; - fcb->Timeout = 0; - memcpy (fcb->Atapi, srb->cmnd, 12); - memset (fcb->Filler, 0, sizeof (fcb->Filler)); - - US_DEBUG(pdump (srb->cmnd, 12)); - - /* Send it out. */ - result = usb_stor_bulk_msg (us, fcb, opipe, - FCM_PACKET_LENGTH, &partial); - - /* The Freecom device will only fail if there is something wrong in - * USB land. It returns the status in its own registers, which - * come back in the bulk pipe. */ - if (result != 0) { - US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", - result, partial); - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_transport(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - return USB_STOR_TRANSPORT_ERROR; - } - - /* There are times we can optimize out this status read, but it - * doesn't hurt us to always do it now. */ - result = usb_stor_bulk_msg (us, fst, ipipe, - FCM_PACKET_LENGTH, &partial); - US_DEBUGP("foo Status result %d %d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_transport(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - US_DEBUG(pdump ((void *) fst, partial)); - - /* The firmware will time-out commands after 20 seconds. Some commands - * can legitimately take longer than this, so we use a different - * command that only waits for the interrupt and then sends status, - * without having to send a new ATAPI command to the device. - * - * NOTE: There is some indication that a data transfer after a timeout - * may not work, but that is a condition that should never happen. - */ - while (fst->Status & FCM_STATUS_BUSY) { - US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occured!\n"); - US_DEBUGP("fst->Status is %x\n", fst->Status); - - /* Get the status again */ - fcb->Type = FCM_PACKET_STATUS; - fcb->Timeout = 0; - memset (fcb->Atapi, 0, sizeof(fcb->Atapi)); - memset (fcb->Filler, 0, sizeof (fcb->Filler)); - - /* Send it out. */ - result = usb_stor_bulk_msg (us, fcb, opipe, - FCM_PACKET_LENGTH, &partial); - - /* The Freecom device will only fail if there is something - * wrong in USB land. It returns the status in its own - * registers, which come back in the bulk pipe. - */ - if (result != 0) { - US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", - result, partial); - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_transport(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - return USB_STOR_TRANSPORT_ERROR; - } - - /* get the data */ - result = usb_stor_bulk_msg (us, fst, ipipe, - FCM_PACKET_LENGTH, &partial); - - US_DEBUGP("bar Status result %d %d\n", result, partial); - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("freecom_transport(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - US_DEBUG(pdump ((void *) fst, partial)); - } - - if (partial != 4 || result != 0) { - return USB_STOR_TRANSPORT_ERROR; - } - if ((fst->Status & 1) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - /* The device might not have as much data available as we - * requested. If you ask for more than the device has, this reads - * and such will hang. */ - US_DEBUGP("Device indicates that it has %d bytes available\n", - le16_to_cpu (fst->Count)); - US_DEBUGP("SCSI requested %d\n", usb_stor_transfer_length(srb)); - - /* Find the length we desire to read. */ - switch (srb->cmnd[0]) { - case INQUIRY: - case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */ - case MODE_SENSE: - case MODE_SENSE_10: - length = fst->Count; - break; - default: - length = usb_stor_transfer_length (srb); - } - - /* verify that this amount is legal */ - if (length > srb->request_bufflen) { - length = srb->request_bufflen; - US_DEBUGP("Truncating request to match buffer length: %d\n", length); - } - - /* What we do now depends on what direction the data is supposed to - * move in. */ - - switch (us->srb->sc_data_direction) { - case SCSI_DATA_READ: - /* Make sure that the status indicates that the device - * wants data as well. */ - if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { - US_DEBUGP("SCSI wants data, drive doesn't have any\n"); - return USB_STOR_TRANSPORT_FAILED; - } - result = freecom_readdata (srb, us, ipipe, opipe, length); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("FCM: Waiting for status\n"); - result = usb_stor_bulk_msg (us, fst, ipipe, - FCM_PACKET_LENGTH, &partial); - US_DEBUG(pdump ((void *) fst, partial)); - if (result == -ENOENT) { - US_DEBUGP ("freecom_transport: transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - if (partial != 4 || result != 0) - return USB_STOR_TRANSPORT_ERROR; - if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); - return USB_STOR_TRANSPORT_FAILED; - } - US_DEBUGP("Transfer happy\n"); - break; - - case SCSI_DATA_WRITE: - /* Make sure the status indicates that the device wants to - * send us data. */ - /* !!IMPLEMENT!! */ - result = freecom_writedata (srb, us, ipipe, opipe, length); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("FCM: Waiting for status\n"); - result = usb_stor_bulk_msg (us, fst, ipipe, - FCM_PACKET_LENGTH, &partial); - if (result == -ENOENT) { - US_DEBUGP ("freecom_transport: transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - if (partial != 4 || result != 0) - return USB_STOR_TRANSPORT_ERROR; - if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - US_DEBUGP("Transfer happy\n"); - break; - - - case SCSI_DATA_NONE: - /* Easy, do nothing. */ - break; - - default: - US_DEBUGP ("freecom unimplemented direction: %d\n", - us->srb->sc_data_direction); - // Return fail, SCSI seems to handle this better. - return USB_STOR_TRANSPORT_FAILED; - break; - } - - return USB_STOR_TRANSPORT_GOOD; - - US_DEBUGP("Freecom: transfer_length = %d\n", - usb_stor_transfer_length (srb)); - - US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction); - - return USB_STOR_TRANSPORT_ERROR; -} - -int -freecom_init (struct us_data *us) -{ - int result; - char buffer[33]; - - /* Allocate a buffer for us. The upper usb transport code will - * free this for us when cleaning up. */ - if (us->extra == NULL) { - us->extra = kmalloc (sizeof (struct freecom_udata), - GFP_KERNEL); - if (us->extra == NULL) { - US_DEBUGP("Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; - } - } - - result = usb_control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev, 0), - 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); - buffer[32] = '\0'; - US_DEBUGP("String returned from FC init is: %s\n", buffer); - - /* Special thanks to the people at Freecom for providing me with - * this "magic sequence", which they use in their Windows and MacOS - * drivers to make sure that all the attached perhiperals are - * properly reset. - */ - - /* send reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), - 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from activate reset is %d\n", result); - - /* wait 250ms */ - mdelay(250); - - /* clear reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), - 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from clear reset is %d\n", result); - - /* wait 3 seconds */ - mdelay(3 * 1000); - - return USB_STOR_TRANSPORT_GOOD; -} - -int usb_stor_freecom_reset(struct us_data *us) -{ - printk (KERN_CRIT "freecom reset called\n"); - - /* We don't really have this feature. */ - return FAILED; -} - -#ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *ibuffer, int length) -{ - static char line[80]; - int offset = 0; - unsigned char *buffer = (unsigned char *) ibuffer; - int i, j; - int from, base; - - offset = 0; - for (i = 0; i < length; i++) { - if ((i & 15) == 0) { - if (i > 0) { - offset += sprintf (line+offset, " - "); - for (j = i - 16; j < i; j++) { - if (buffer[j] >= 32 && buffer[j] <= 126) - line[offset++] = buffer[j]; - else - line[offset++] = '.'; - } - line[offset] = 0; - US_DEBUGP("%s\n", line); - offset = 0; - } - offset += sprintf (line+offset, "%08x:", i); - } - else if ((i & 7) == 0) { - offset += sprintf (line+offset, " -"); - } - offset += sprintf (line+offset, " %02x", buffer[i] & 0xff); - } - - /* Add the last "chunk" of data. */ - from = (length - 1) % 16; - base = ((length - 1) / 16) * 16; - - for (i = from + 1; i < 16; i++) - offset += sprintf (line+offset, " "); - if (from < 8) - offset += sprintf (line+offset, " "); - offset += sprintf (line+offset, " - "); - - for (i = 0; i <= from; i++) { - if (buffer[base+i] >= 32 && buffer[base+i] <= 126) - line[offset++] = buffer[base+i]; - else - line[offset++] = '.'; - } - line[offset] = 0; - US_DEBUGP("%s\n", line); - offset = 0; -} -#endif - diff --git a/drivers/usb/class/storage/freecom.h b/drivers/usb/class/storage/freecom.h deleted file mode 100644 index 8c0ada8bbeb6..000000000000 --- a/drivers/usb/class/storage/freecom.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Driver for Freecom USB/IDE adaptor - * - * $Id: freecom.h,v 1.4 2000/08/29 14:49:15 dlbrown Exp $ - * - * Freecom v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 David Brown <usb-storage@davidb.org> - * - * See freecom.c for more explanation - * - * 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, 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. - */ - -#ifndef _FREECOM_USB_H -#define _FREECOM_USB_H - -extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); -extern int usb_stor_freecom_reset(struct us_data *us); -extern int freecom_init (struct us_data *us); - -#endif diff --git a/drivers/usb/class/storage/initializers.c b/drivers/usb/class/storage/initializers.c deleted file mode 100644 index dd03ef7ae3ce..000000000000 --- a/drivers/usb/class/storage/initializers.c +++ /dev/null @@ -1,60 +0,0 @@ -/* Special Initializers for certain USB Mass Storage devices - * - * $Id: initializers.c,v 1.2 2000/09/06 22:35:57 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "initializers.h" -#include "debug.h" - -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ -int usb_stor_euscsi_init(struct us_data *us) -{ - unsigned char data = 0x1; - int result; - - US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), - 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, &data, 0x1, 5*HZ); - US_DEBUGP("-- result is %d\n", result); - US_DEBUGP("-- data afterwards is %d\n", data); - - return 0; -} - - diff --git a/drivers/usb/class/storage/initializers.h b/drivers/usb/class/storage/initializers.h deleted file mode 100644 index 51bb0241e161..000000000000 --- a/drivers/usb/class/storage/initializers.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Header file for Special Initializers for certain USB Mass Storage devices - * - * $Id: initializers.h,v 1.1 2000/08/29 23:07:02 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "usb.h" - -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ -int usb_stor_euscsi_init(struct us_data *us); diff --git a/drivers/usb/class/storage/isd200.c b/drivers/usb/class/storage/isd200.c deleted file mode 100644 index f43f4a5d8f24..000000000000 --- a/drivers/usb/class/storage/isd200.c +++ /dev/null @@ -1,1749 +0,0 @@ -/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC - * - * First release - * - * Current development and maintenance by: - * (c) 2000 In-System Design, Inc. (support@in-system.com) - * - * The ISD200 ASIC does not natively support ATA devices. The chip - * does implement an interface, the ATA Command Block (ATACB) which provides - * a means of passing ATA commands and ATA register accesses to a device. - * - * 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, 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. - * - * History: - * - * 2001-02-24: Removed lots of duplicate code and simplified the structure. - * (bjorn@haxx.se) - */ - - -/* Include files */ - -#include "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "scsiglue.h" -#include "isd200.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/hdreg.h> -#include <linux/ide.h> - -/* - * Inquiry defines. Used to interpret data returned from target as result - * of inquiry command. - * - * DeviceType field - */ - -#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ - -/* Timeout defines (in Seconds) */ - -#define ISD200_ENUM_BSY_TIMEOUT 35 -#define ISD200_ENUM_DETECT_TIMEOUT 30 -#define ISD200_DEFAULT_TIMEOUT 30 - -/* device flags */ -#define DF_ATA_DEVICE 0x0001 -#define DF_MEDIA_STATUS_ENABLED 0x0002 -#define DF_REMOVABLE_MEDIA 0x0004 - -/* capability bit definitions */ -#define CAPABILITY_DMA 0x01 -#define CAPABILITY_LBA 0x02 - -/* command_setX bit definitions */ -#define COMMANDSET_REMOVABLE 0x02 -#define COMMANDSET_MEDIA_STATUS 0x10 - -/* ATA Vendor Specific defines */ -#define ATA_ADDRESS_DEVHEAD_STD 0xa0 -#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40 -#define ATA_ADDRESS_DEVHEAD_SLAVE 0x10 - -/* Action Select bits */ -#define ACTION_SELECT_0 0x01 -#define ACTION_SELECT_1 0x02 -#define ACTION_SELECT_2 0x04 -#define ACTION_SELECT_3 0x08 -#define ACTION_SELECT_4 0x10 -#define ACTION_SELECT_5 0x20 -#define ACTION_SELECT_6 0x40 -#define ACTION_SELECT_7 0x80 - -/* ATA error definitions not in <linux/hdreg.h> */ -#define ATA_ERROR_MEDIA_CHANGE 0x20 - -/* ATA command definitions not in <linux/hdreg.h> */ -#define ATA_COMMAND_GET_MEDIA_STATUS 0xDA -#define ATA_COMMAND_MEDIA_EJECT 0xED - -/* ATA drive control definitions */ -#define ATA_DC_DISABLE_INTERRUPTS 0x02 -#define ATA_DC_RESET_CONTROLLER 0x04 -#define ATA_DC_REENABLE_CONTROLLER 0x00 - -/* - * General purpose return codes - */ - -#define ISD200_ERROR -1 -#define ISD200_GOOD 0 - -/* - * Transport return codes - */ - -#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */ -#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ -#define ISD200_TRANSPORT_ABORTED 3 /* Transport aborted */ -#define ISD200_TRANSPORT_SHORT 4 /* Transport short */ - -/* driver action codes */ -#define ACTION_READ_STATUS 0 -#define ACTION_RESET 1 -#define ACTION_REENABLE 2 -#define ACTION_SOFT_RESET 3 -#define ACTION_ENUM 4 -#define ACTION_IDENTIFY 5 - - -/* - * ata_cdb struct - */ - - -union ata_cdb { - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ActionSelect; - unsigned char RegisterSelect; - unsigned char TransferBlockSize; - unsigned char WriteData3F6; - unsigned char WriteData1F1; - unsigned char WriteData1F2; - unsigned char WriteData1F3; - unsigned char WriteData1F4; - unsigned char WriteData1F5; - unsigned char WriteData1F6; - unsigned char WriteData1F7; - unsigned char Reserved[3]; - } generic; - - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectAlternateStatus : 1; - unsigned char SelectError : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectStatus : 1; - unsigned char TransferBlockSize; - unsigned char AlternateStatusByte; - unsigned char ErrorByte; - unsigned char SectorCountByte; - unsigned char SectorNumberByte; - unsigned char CylinderLowByte; - unsigned char CylinderHighByte; - unsigned char DeviceHeadByte; - unsigned char StatusByte; - unsigned char Reserved[3]; - } read; - - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectDeviceControl : 1; - unsigned char SelectFeatures : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectCommand : 1; - unsigned char TransferBlockSize; - unsigned char DeviceControlByte; - unsigned char FeaturesByte; - unsigned char SectorCountByte; - unsigned char SectorNumberByte; - unsigned char CylinderLowByte; - unsigned char CylinderHighByte; - unsigned char DeviceHeadByte; - unsigned char CommandByte; - unsigned char Reserved[3]; - } write; -}; - - -/* - * Inquiry data structure. This is the data returned from the target - * after it receives an inquiry. - * - * This structure may be extended by the number of bytes specified - * in the field AdditionalLength. The defined size constant only - * includes fields through ProductRevisionLevel. - */ - -struct inquiry_data { - unsigned char DeviceType : 5; - unsigned char DeviceTypeQualifier : 3; - unsigned char DeviceTypeModifier : 7; - unsigned char RemovableMedia : 1; - unsigned char Versions; - unsigned char ResponseDataFormat : 4; - unsigned char HiSupport : 1; - unsigned char NormACA : 1; - unsigned char ReservedBit : 1; - unsigned char AERC : 1; - unsigned char AdditionalLength; - unsigned char Reserved[2]; - unsigned char SoftReset : 1; - unsigned char CommandQueue : 1; - unsigned char Reserved2 : 1; - unsigned char LinkedCommands : 1; - unsigned char Synchronous : 1; - unsigned char Wide16Bit : 1; - unsigned char Wide32Bit : 1; - unsigned char RelativeAddressing : 1; - unsigned char VendorId[8]; - unsigned char ProductId[16]; - unsigned char ProductRevisionLevel[4]; - unsigned char VendorSpecific[20]; - unsigned char Reserved3[40]; -} __attribute__ ((packed)); - -/* - * INQUIRY data buffer size - */ - -#define INQUIRYDATABUFFERSIZE 36 - - -/* - * ISD200 CONFIG data struct - */ - -struct isd200_config { - unsigned char EventNotification; - unsigned char ExternalClock; - unsigned char ATAInitTimeout; - unsigned char ATATiming : 4; - unsigned char ATAPIReset : 1; - unsigned char MasterSlaveSelection : 1; - unsigned char ATAPICommandBlockSize : 2; - unsigned char ATAMajorCommand; - unsigned char ATAMinorCommand; - unsigned char LastLUNIdentifier : 3; - unsigned char DescriptOverride : 1; - unsigned char ATA3StateSuspend : 1; - unsigned char SkipDeviceBoot : 1; - unsigned char ConfigDescriptor2 : 1; - unsigned char InitStatus : 1; - unsigned char SRSTEnable : 1; - unsigned char Reserved0 : 7; -}; - - -/* - * ISD200 driver information struct - */ - -struct isd200_info { - struct inquiry_data InquiryData; - struct hd_driveid drive; - struct isd200_config ConfigData; - unsigned char ATARegs[8]; - unsigned char DeviceHead; - unsigned char DeviceFlags; - - /* maximum number of LUNs supported */ - unsigned char MaxLUNs; -}; - - -/* - * Read Capacity Data - returned in Big Endian format - */ - -struct read_capacity_data { - unsigned long LogicalBlockAddress; - unsigned long BytesPerBlock; -}; - -/* - * Read Block Limits Data - returned in Big Endian format - * This structure returns the maximum and minimum block - * size for a TAPE device. - */ - -struct read_block_limits { - unsigned char Reserved; - unsigned char BlockMaximumSize[3]; - unsigned char BlockMinimumSize[2]; -}; - - -/* - * Sense Data Format - */ - -struct sense_data { - unsigned char ErrorCode:7; - unsigned char Valid:1; - unsigned char SegmentNumber; - unsigned char SenseKey:4; - unsigned char Reserved:1; - unsigned char IncorrectLength:1; - unsigned char EndOfMedia:1; - unsigned char FileMark:1; - unsigned char Information[4]; - unsigned char AdditionalSenseLength; - unsigned char CommandSpecificInformation[4]; - unsigned char AdditionalSenseCode; - unsigned char AdditionalSenseCodeQualifier; - unsigned char FieldReplaceableUnitCode; - unsigned char SenseKeySpecific[3]; -} __attribute__ ((packed)); - -/* - * Default request sense buffer size - */ - -#define SENSE_BUFFER_SIZE 18 - -/*********************************************************************** - * Helper routines - ***********************************************************************/ - - -/************************************************************************** - * isd200_build_sense - * - * Builds an artificial sense buffer to report the results of a - * failed command. - * - * RETURNS: - * void - */ -void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; - unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; - - if(error & ATA_ERROR_MEDIA_CHANGE) { - buf->ErrorCode = 0x70; - buf->Valid = 1; - buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if(error & MCR_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; - buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if(error & TRK0_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; - buf->AdditionalSenseLength = 0xb; - buf->SenseKey = NOT_READY; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if(error & ECC_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; - buf->AdditionalSenseLength = 0xb; - buf->SenseKey = DATA_PROTECT; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else { - buf->ErrorCode = 0; - buf->Valid = 0; - buf->AdditionalSenseLength = 0; - buf->SenseKey = 0; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } -} - -/*********************************************************************** - * Data transfer routines - ***********************************************************************/ - - -/************************************************************************** - * Transfer one SCSI scatter-gather buffer via bulk transfer - * - * Note that this function is necessary because we want the ability to - * use scatter-gather memory. Good performance is achieved by a combination - * of scatter-gather and clustering (which makes each chunk bigger). - * - * Note that the lower layer will always retry when a NAK occurs, up to the - * timeout limit. Thus we don't have to worry about it for individual - * packets. - */ -static int isd200_transfer_partial( struct us_data *us, - unsigned char dataDirection, - char *buf, int length ) -{ - int result; - int partial; - int pipe; - - /* calculate the appropriate pipe information */ - if (dataDirection == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* transfer the data */ - US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length); - result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); - US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", - result, partial, length); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - } - - /* did we send all the data? */ - if (partial == length) { - US_DEBUGP("isd200_transfer_partial(): transfer complete\n"); - return ISD200_TRANSPORT_GOOD; - } - - /* uh oh... we have an error code, so something went wrong. */ - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("isd200_transfer_partial(): device NAKed\n"); - return ISD200_TRANSPORT_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("isd200_transfer_partial(): transfer aborted\n"); - return ISD200_TRANSPORT_ABORTED; - } - - /* the catch-all case */ - US_DEBUGP("isd200_transfer_partial(): unknown error\n"); - return ISD200_TRANSPORT_FAILED; - } - - /* no error code, so we must have transferred some data, - * just not all of it */ - return ISD200_TRANSPORT_SHORT; -} - - -/************************************************************************** - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses us_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb ) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - int dir = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_WRITE; - transfer_amount = usb_stor_transfer_length(srb); - srb->sc_data_direction = dir; - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = isd200_transfer_partial(us, - srb->sc_data_direction, - page_address(sg[i].page) + sg[i].offset, - sg[i].length); - total_transferred += sg[i].length; - } else - result = isd200_transfer_partial(us, - srb->sc_data_direction, - page_address(sg[i].page) + sg[i].offset, - transfer_amount - total_transferred); - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = isd200_transfer_partial(us, - srb->sc_data_direction, - srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - - -/************************************************************************** - * ISD200 Bulk Transport - * - * Note: This routine was copied from the usb_stor_Bulk_transport routine - * located in the transport.c source file. The scsi command is limited to - * only 12 bytes while the CDB for the ISD200 must be 16 bytes. - */ -int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, - union ata_cdb *AtaCdb, unsigned char AtaCdbLength ) -{ - struct bulk_cb_wrap bcb; - struct bulk_cs_wrap bcs; - int result; - int pipe; - int partial; - unsigned int transfer_amount; - - int dir = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_WRITE; - transfer_amount = usb_stor_transfer_length(srb); - srb->sc_data_direction = dir; - - /* set up the command wrapper */ - bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(transfer_amount); - bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; - bcb.Tag = srb->serial_number; - bcb.Lun = srb->cmnd[1] >> 5; - if (us->flags & US_FL_SCM_MULT_TARG) - bcb.Lun |= srb->target << 4; - - bcb.Length = AtaCdbLength; - - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* copy the command payload */ - memset(bcb.CDB, 0, sizeof(bcb.CDB)); - memcpy(bcb.CDB, AtaCdb, bcb.Length); - - /* send it to out endpoint */ - US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", - le32_to_cpu(bcb.Signature), bcb.Tag, - (bcb.Lun >> 4), (bcb.Lun & 0xFF), - bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); - US_DEBUGP("Bulk command transfer result=%d\n", result); - - if (result == -ENOENT) - return ISD200_TRANSPORT_ABORTED; - else if (result == -EPIPE) { - /* if we stall, we need to clear it before we go on */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - } else if (result) - return ISD200_TRANSPORT_ERROR; - - /* if the command transfered well, then we go to the data stage */ - if (!result && bcb.DataTransferLength) { - isd200_transfer(us, srb); - US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result); - - if (srb->result == ISD200_TRANSPORT_ABORTED) - return ISD200_TRANSPORT_ABORTED; - } - - /* See flow chart on pg 15 of the Bulk Only Transport spec for - * an explanation of how this code works. - */ - - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - - /* get CSW for device status */ - US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); - if (result == -ENOENT) - return ISD200_TRANSPORT_ABORTED; - - /* did the attempt to read the CSW fail? */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - - /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, - US_BULK_CS_WRAP_LEN, &partial); - - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return ISD200_TRANSPORT_ABORTED; - - /* if it fails again, we need a reset and return an error*/ - if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - return ISD200_TRANSPORT_ERROR; - } - } - - /* if we still have a failure at this point, we're in trouble */ - US_DEBUGP("Bulk status result = %d\n", result); - if (result) - return ISD200_TRANSPORT_ERROR; - - /* check bulk status */ - US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", - le32_to_cpu(bcs.Signature), bcs.Tag, - bcs.Residue, bcs.Status); - if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || - bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { - US_DEBUGP("Bulk logical error\n"); - return ISD200_TRANSPORT_ERROR; - } - - /* based on the status code, we report good or bad */ - switch (bcs.Status) { - case US_BULK_STAT_OK: - /* command good -- note that we could be short on data */ - return ISD200_TRANSPORT_GOOD; - - case US_BULK_STAT_FAIL: - /* command failed */ - return ISD200_TRANSPORT_FAILED; - - case US_BULK_STAT_PHASE: - /* phase error */ - usb_stor_Bulk_reset(us); - return ISD200_TRANSPORT_ERROR; - } - - /* we should never get here, but if we do, we're in trouble */ - return ISD200_TRANSPORT_ERROR; -} - - -/************************************************************************** - * isd200_action - * - * Routine for sending commands to the isd200 - * - * RETURNS: - * ISD status code - */ -static int isd200_action( struct us_data *us, int action, - void* pointer, int value ) -{ - union ata_cdb ata; - struct scsi_cmnd srb; - struct isd200_info *info = (struct isd200_info *)us->extra; - int status; - - memset(&ata, 0, sizeof(ata)); - memset(&srb, 0, sizeof(srb)); - - ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ata.generic.TransferBlockSize = 1; - - switch ( action ) { - case ACTION_READ_STATUS: - US_DEBUGP(" isd200_action(READ_STATUS)\n"); - ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; - ata.read.SelectStatus = 1; - ata.read.SelectError = 1; - ata.read.SelectCylinderHigh = 1; - ata.read.SelectCylinderLow = 1; - srb.sc_data_direction = SCSI_DATA_READ; - srb.request_buffer = pointer; - srb.request_bufflen = value; - break; - - case ACTION_ENUM: - US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4| - ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; - ata.write.DeviceHeadByte = value; - srb.sc_data_direction = SCSI_DATA_NONE; - break; - - case ACTION_RESET: - US_DEBUGP(" isd200_action(RESET)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; - ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb.sc_data_direction = SCSI_DATA_NONE; - break; - - case ACTION_REENABLE: - US_DEBUGP(" isd200_action(REENABLE)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; - ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb.sc_data_direction = SCSI_DATA_NONE; - break; - - case ACTION_SOFT_RESET: - US_DEBUGP(" isd200_action(SOFT_RESET)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; - ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.SelectCommand = 1; - ata.write.CommandByte = WIN_SRST; - srb.sc_data_direction = SCSI_DATA_NONE; - break; - - case ACTION_IDENTIFY: - US_DEBUGP(" isd200_action(IDENTIFY)\n"); - ata.write.SelectCommand = 1; - ata.write.CommandByte = WIN_IDENTIFY; - srb.sc_data_direction = SCSI_DATA_READ; - srb.request_buffer = (void *)&info->drive; - srb.request_bufflen = sizeof(struct hd_driveid); - break; - - default: - US_DEBUGP("Error: Undefined action %d\n",action); - break; - } - - status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic)); - if (status != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status); - status = ISD200_ERROR; - /* need to reset device here */ - } - - return status; -} - -/************************************************************************** - * isd200_read_regs - * - * Read ATA Registers - * - * RETURNS: - * ISD status code - */ -int isd200_read_regs( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_IssueATAReadRegs\n"); - - transferStatus = isd200_action( us, ACTION_READ_STATUS, - info->ATARegs, sizeof(info->ATARegs) ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error reading ATA registers\n"); - retStatus = ISD200_ERROR; - } else { - US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", - info->ATARegs[IDE_ERROR_OFFSET]); - } - - return retStatus; -} - - -/************************************************************************** - * Invoke the transport and basic error-handling/recovery methods - * - * This is used by the protocol layers to actually send the message to - * the device and receive the response. - */ -void isd200_invoke_transport( struct us_data *us, - Scsi_Cmnd *srb, - union ata_cdb *ataCdb ) -{ - int need_auto_sense = 0; - int transferStatus; - - /* send the command to the transport layer */ - transferStatus = isd200_Bulk_transport(us, srb, ataCdb, - sizeof(ataCdb->generic)); - switch (transferStatus) { - - case ISD200_TRANSPORT_GOOD: - /* Indicate a good result */ - srb->result = GOOD; - break; - - case ISD200_TRANSPORT_ABORTED: - /* if the command gets aborted by the higher layers, we need to - * short-circuit all other processing - */ - US_DEBUGP("-- transport indicates command was aborted\n"); - srb->result = DID_ABORT << 16; - break; - - case ISD200_TRANSPORT_FAILED: - US_DEBUGP("-- transport indicates command failure\n"); - need_auto_sense = 1; - break; - - case ISD200_TRANSPORT_ERROR: - US_DEBUGP("-- transport indicates transport failure\n"); - srb->result = DID_ERROR << 16; - break; - - case ISD200_TRANSPORT_SHORT: - if (!((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY) || - (srb->cmnd[0] == MODE_SENSE) || - (srb->cmnd[0] == LOG_SENSE) || - (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); - need_auto_sense = 1; - } - break; - - default: - US_DEBUGP("-- transport indicates unknown failure\n"); - srb->result = DID_ERROR << 16; - - } - - if (need_auto_sense) - if (isd200_read_regs(us) == ISD200_GOOD) - isd200_build_sense(us, srb); - - /* Regardless of auto-sense, if we _know_ we have an error - * condition, show that in the result code - */ - if (transferStatus == ISD200_TRANSPORT_FAILED) - srb->result = CHECK_CONDITION; -} - - -/************************************************************************** - * isd200_write_config - * - * Write the ISD200 Configuraton data - * - * RETURNS: - * ISD status code - */ -int isd200_write_config( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int result; - - - US_DEBUGP("Entering isd200_write_config\n"); - - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); - - /* let's send the command via the control pipe */ - result = usb_stor_control_msg( - us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x01, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0000, - 0x0002, - (void *) &info->ConfigData, - sizeof(info->ConfigData)); - - if (result >= 0) { - US_DEBUGP(" ISD200 Config Data was written successfully\n"); - } else { - US_DEBUGP(" Request to write ISD200 Config Data failed!\n"); - - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - - } - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_read_config - * - * Reads the ISD200 Configuraton data - * - * RETURNS: - * ISD status code - */ -int isd200_read_config( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int result; - - US_DEBUGP("Entering isd200_read_config\n"); - - /* read the configuration information from ISD200. Use this to */ - /* determine what the special ATA CDB bytes are. */ - - result = usb_stor_control_msg( - us, - usb_rcvctrlpipe(us->pusb_dev,0), - 0x02, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0000, - 0x0002, - (void *) &info->ConfigData, - sizeof(info->ConfigData)); - - - if (result >= 0) { - US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); - } else { - US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); - - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - - } - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_atapi_soft_reset - * - * Perform an Atapi Soft Reset on the device - * - * RETURNS: - * NT status code - */ -int isd200_atapi_soft_reset( struct us_data *us ) -{ - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_atapi_soft_reset\n"); - - transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing Atapi Soft Reset\n"); - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_srst - * - * Perform an SRST on the device - * - * RETURNS: - * ISD status code - */ -int isd200_srst( struct us_data *us ) -{ - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_SRST\n"); - - transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 ); - - /* check to see if this request failed */ - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing SRST\n"); - retStatus = ISD200_ERROR; - } else { - /* delay 10ms to give the drive a chance to see it */ - wait_ms(10); - - transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error taking drive out of reset\n"); - retStatus = ISD200_ERROR; - } else { - /* delay 50ms to give the drive a chance to recover after SRST */ - wait_ms(50); - } - } - - US_DEBUGP("Leaving isd200_srst %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_try_enum - * - * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS - * and tries to analyze the status registers - * - * RETURNS: - * ISD status code - */ -static int isd200_try_enum(struct us_data *us, unsigned char master_slave, - int detect ) -{ - int status = ISD200_GOOD; - unsigned char regs[8]; - unsigned long endTime; - struct isd200_info *info = (struct isd200_info *)us->extra; - int recheckAsMaster = FALSE; - - if ( detect ) - endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; - else - endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; - - /* loop until we detect !BSY or timeout */ - while(TRUE) { -#ifdef CONFIG_USB_STORAGE_DEBUG - char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? - "Master" : "Slave"; -#endif - - status = isd200_action( us, ACTION_ENUM, NULL, master_slave ); - if ( status != ISD200_GOOD ) - break; - - status = isd200_action( us, ACTION_READ_STATUS, - regs, sizeof(regs) ); - if ( status != ISD200_GOOD ) - break; - - if (!detect) { - if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) { - US_DEBUGP(" %s status is still BSY, try again...\n",mstr); - } else { - US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); - break; - } - } - /* check for BUSY_STAT and */ - /* WRERR_STAT (workaround ATA Zip drive) and */ - /* ERR_STAT (workaround for Archos CD-ROM) */ - else if (regs[IDE_STATUS_OFFSET] & - (BUSY_STAT | WRERR_STAT | ERR_STAT )) { - US_DEBUGP(" Status indicates it is not ready, try again...\n"); - } - /* check for DRDY, ATA devices set DRDY after SRST */ - else if (regs[IDE_STATUS_OFFSET] & READY_STAT) { - US_DEBUGP(" Identified ATA device\n"); - info->DeviceFlags |= DF_ATA_DEVICE; - info->DeviceHead = master_slave; - break; - } - /* check Cylinder High/Low to - determine if it is an ATAPI device - */ - else if ((regs[IDE_HCYL_OFFSET] == 0xEB) && - (regs[IDE_LCYL_OFFSET] == 0x14)) { - /* It seems that the RICOH - MP6200A CD/RW drive will - report itself okay as a - slave when it is really a - master. So this check again - as a master device just to - make sure it doesn't report - itself okay as a master also - */ - if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && - (recheckAsMaster == FALSE)) { - US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); - recheckAsMaster = TRUE; - master_slave = ATA_ADDRESS_DEVHEAD_STD; - } else { - US_DEBUGP(" Identified ATAPI device\n"); - info->DeviceHead = master_slave; - - status = isd200_atapi_soft_reset(us); - break; - } - } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); - } - - /* check for timeout on this request */ - if (jiffies >= endTime) { - if (!detect) - US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); - else - US_DEBUGP(" Device detect timeout!\n"); - break; - } - } - - return status; -} - -/************************************************************************** - * isd200_manual_enum - * - * Determines if the drive attached is an ATA or ATAPI and if it is a - * master or slave. - * - * RETURNS: - * ISD status code - */ -int isd200_manual_enum(struct us_data *us) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - - US_DEBUGP("Entering isd200_manual_enum\n"); - - retStatus = isd200_read_config(us); - if (retStatus == ISD200_GOOD) { - int isslave; - /* master or slave? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, FALSE ); - if (retStatus == ISD200_GOOD) - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, FALSE ); - - if (retStatus == ISD200_GOOD) { - retStatus = isd200_srst(us); - if (retStatus == ISD200_GOOD) - /* ata or atapi? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, TRUE ); - } - - isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; - if (info->ConfigData.MasterSlaveSelection != isslave) { - US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); - info->ConfigData.MasterSlaveSelection = isslave; - retStatus = isd200_write_config(us); - } - } - - US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus); - return(retStatus); -} - - -/************************************************************************** - * isd200_get_inquiry_data - * - * Get inquiry data - * - * RETURNS: - * ISD status code - */ -int isd200_get_inquiry_data( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - - US_DEBUGP("Entering isd200_get_inquiry_data\n"); - - /* set default to Master */ - info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; - - /* attempt to manually enumerate this device */ - retStatus = isd200_manual_enum(us); - if (retStatus == ISD200_GOOD) { - int transferStatus; - - /* check for an ATA device */ - if (info->DeviceFlags & DF_ATA_DEVICE) { - /* this must be an ATA device */ - /* perform an ATA Commmand Identify */ - transferStatus = isd200_action( us, ACTION_IDENTIFY, - &info->drive, - sizeof(struct hd_driveid) ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - /* Error issuing ATA Command Identify */ - US_DEBUGP(" Error issuing ATA Command Identify\n"); - retStatus = ISD200_ERROR; - } else { - /* ATA Command Identify successful */ - int i; - - US_DEBUGP(" Identify Data Structure:\n"); - US_DEBUGP(" config = 0x%x\n", info->drive.config); - US_DEBUGP(" cyls = 0x%x\n", info->drive.cyls); - US_DEBUGP(" heads = 0x%x\n", info->drive.heads); - US_DEBUGP(" track_bytes = 0x%x\n", info->drive.track_bytes); - US_DEBUGP(" sector_bytes = 0x%x\n", info->drive.sector_bytes); - US_DEBUGP(" sectors = 0x%x\n", info->drive.sectors); - US_DEBUGP(" serial_no[0] = 0x%x\n", info->drive.serial_no[0]); - US_DEBUGP(" buf_type = 0x%x\n", info->drive.buf_type); - US_DEBUGP(" buf_size = 0x%x\n", info->drive.buf_size); - US_DEBUGP(" ecc_bytes = 0x%x\n", info->drive.ecc_bytes); - US_DEBUGP(" fw_rev[0] = 0x%x\n", info->drive.fw_rev[0]); - US_DEBUGP(" model[0] = 0x%x\n", info->drive.model[0]); - US_DEBUGP(" max_multsect = 0x%x\n", info->drive.max_multsect); - US_DEBUGP(" dword_io = 0x%x\n", info->drive.dword_io); - US_DEBUGP(" capability = 0x%x\n", info->drive.capability); - US_DEBUGP(" tPIO = 0x%x\n", info->drive.tPIO); - US_DEBUGP(" tDMA = 0x%x\n", info->drive.tDMA); - US_DEBUGP(" field_valid = 0x%x\n", info->drive.field_valid); - US_DEBUGP(" cur_cyls = 0x%x\n", info->drive.cur_cyls); - US_DEBUGP(" cur_heads = 0x%x\n", info->drive.cur_heads); - US_DEBUGP(" cur_sectors = 0x%x\n", info->drive.cur_sectors); - US_DEBUGP(" cur_capacity = 0x%x\n", (info->drive.cur_capacity1 << 16) + info->drive.cur_capacity0 ); - US_DEBUGP(" multsect = 0x%x\n", info->drive.multsect); - US_DEBUGP(" lba_capacity = 0x%x\n", info->drive.lba_capacity); - US_DEBUGP(" command_set_1 = 0x%x\n", info->drive.command_set_1); - US_DEBUGP(" command_set_2 = 0x%x\n", info->drive.command_set_2); - - memset(&info->InquiryData, 0, sizeof(info->InquiryData)); - - /* Standard IDE interface only supports disks */ - info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; - - /* Fix-up the return data from an INQUIRY command to show - * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us - * in Linux. - */ - info->InquiryData.Versions = 0x2; - - /* The length must be at least 36 (5 + 31) */ - info->InquiryData.AdditionalLength = 0x1F; - - if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { - /* set the removable bit */ - info->InquiryData.RemovableMedia = 1; - info->DeviceFlags |= DF_REMOVABLE_MEDIA; - } - - /* Fill in vendor identification fields */ - for (i = 0; i < 20; i += 2) { - info->InquiryData.VendorId[i] = - info->drive.model[i + 1]; - info->InquiryData.VendorId[i+1] = - info->drive.model[i]; - } - - /* Initialize unused portion of product id */ - for (i = 0; i < 4; i++) { - info->InquiryData.ProductId[12+i] = ' '; - } - - /* Move firmware revision from IDENTIFY data to */ - /* product revision in INQUIRY data */ - for (i = 0; i < 4; i += 2) { - info->InquiryData.ProductRevisionLevel[i] = - info->drive.fw_rev[i+1]; - info->InquiryData.ProductRevisionLevel[i+1] = - info->drive.fw_rev[i]; - } - - /* determine if it supports Media Status Notification */ - if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { - US_DEBUGP(" Device supports Media Status Notification\n"); - - /* Indicate that it is enabled, even though it is not - * This allows the lock/unlock of the media to work - * correctly. - */ - info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; - } - else - info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED; - - } - } else { - /* - * this must be an ATAPI device - * use an ATAPI protocol (Transparent SCSI) - */ - us->protocol_name = "Transparent SCSI"; - us->proto_handler = usb_stor_transparent_scsi_command; - - US_DEBUGP("Protocol changed to: %s\n", us->protocol_name); - - /* Free driver structure */ - if (us->extra != NULL) { - kfree(us->extra); - us->extra = NULL; - us->extra_destructor = NULL; - } - } - } - - US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus); - - return(retStatus); -} - - -/************************************************************************** - * isd200_data_copy - * - * Copy data into the srb request buffer. Use scatter gather if required. - * - * RETURNS: - * void - */ -void isd200_data_copy(Scsi_Cmnd *srb, char * src, int length) -{ - unsigned int len = length; - struct scatterlist *sg; - - if (srb->use_sg) { - int i; - unsigned int total = 0; - - /* Add up the sizes of all the sg segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - - if (length > total) - len = total; - - total = 0; - - /* Copy data into sg buffer(s) */ - for (i = 0; i < srb->use_sg; i++) { - if ((len > total) && (len > 0)) { - /* transfer the lesser of the next buffer or the - * remaining data */ - if (len - total >= sg[i].length) { - memcpy(page_address(sg[i].page) + sg[i].offset, src + total, sg[i].length); - total += sg[i].length; - } else { - memcpy(page_address(sg[i].page) + sg[i].offset, src + total, len - total); - total = len; - } - } - else - break; - } - } else { - /* Make sure length does not exceed buffer length */ - if (length > srb->request_bufflen) - len = srb->request_bufflen; - - if (len > 0) - memcpy(srb->request_buffer, src, len); - } -} - - -/************************************************************************** - * isd200_scsi_to_ata - * - * Translate SCSI commands to ATA commands. - * - * RETURNS: - * TRUE if the command needs to be sent to the transport layer - * FALSE otherwise - */ -int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, - union ata_cdb * ataCdb) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int sendToTransport = TRUE; - unsigned char sectnum, head; - unsigned short cylinder; - unsigned long lba; - unsigned long blockCount; - unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - memset(ataCdb, 0, sizeof(union ata_cdb)); - - /* SCSI Command */ - switch (srb->cmnd[0]) { - case INQUIRY: - US_DEBUGP(" ATA OUT - INQUIRY\n"); - - if (srb->request_bufflen > sizeof(struct inquiry_data)) - srb->request_bufflen = sizeof(struct inquiry_data); - - /* copy InquiryData */ - isd200_data_copy(srb, (char *) &info->InquiryData, srb->request_bufflen); - srb->result = GOOD; - sendToTransport = FALSE; - break; - - case MODE_SENSE: - US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n"); - - /* Initialize the return buffer */ - isd200_data_copy(srb, (char *) &senseData, 8); - - if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) - { - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; - } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = GOOD; - sendToTransport = FALSE; - } - break; - - case TEST_UNIT_READY: - US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n"); - - /* Initialize the return buffer */ - isd200_data_copy(srb, (char *) &senseData, 8); - - if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) - { - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; - } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = GOOD; - sendToTransport = FALSE; - } - break; - - case READ_CAPACITY: - { - unsigned long capacity; - struct read_capacity_data readCapacityData; - - US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); - - if (info->drive.capability & CAPABILITY_LBA ) { - capacity = info->drive.lba_capacity - 1; - } else { - capacity = (info->drive.heads * - info->drive.cyls * - info->drive.sectors) - 1; - } - readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); - readCapacityData.BytesPerBlock = cpu_to_be32(0x200); - - if (srb->request_bufflen > sizeof(struct read_capacity_data)) - srb->request_bufflen = sizeof(struct read_capacity_data); - - isd200_data_copy(srb, (char *) &readCapacityData, srb->request_bufflen); - srb->result = GOOD; - sendToTransport = FALSE; - } - break; - - case READ_10: - US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); - - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); - blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - - if (info->drive.capability & CAPABILITY_LBA) { - sectnum = (unsigned char)(lba); - cylinder = (unsigned short)(lba>>8); - head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); - } else { - sectnum = (unsigned char)((lba % info->drive.sectors) + 1); - cylinder = (unsigned short)(lba / (info->drive.sectors * - info->drive.heads)); - head = (unsigned char)((lba / info->drive.sectors) % - info->drive.heads); - } - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; - ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; - ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; - ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; - ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; - ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = WIN_READ; - break; - - case WRITE_10: - US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); - - lba = *(unsigned long *)&srb->cmnd[2]; - lba = cpu_to_be32(lba); - blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - - if (info->drive.capability & CAPABILITY_LBA) { - sectnum = (unsigned char)(lba); - cylinder = (unsigned short)(lba>>8); - head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); - } else { - sectnum = (unsigned char)((lba % info->drive.sectors) + 1); - cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads)); - head = (unsigned char)((lba / info->drive.sectors) % info->drive.heads); - } - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; - ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; - ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; - ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; - ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; - ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = WIN_WRITE; - break; - - case ALLOW_MEDIUM_REMOVAL: - US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); - - if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); - - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? - WIN_DOORLOCK : WIN_DOORUNLOCK; - srb->request_bufflen = 0; - } else { - US_DEBUGP(" Not removeable media, just report okay\n"); - srb->result = GOOD; - sendToTransport = FALSE; - } - break; - - case START_STOP: - US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n"); - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); - - /* Initialize the return buffer */ - isd200_data_copy(srb, (char *) &senseData, 8); - - if ((srb->cmnd[4] & 0x3) == 0x2) { - US_DEBUGP(" Media Eject\n"); - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 0; - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; - } else if ((srb->cmnd[4] & 0x3) == 0x1) { - US_DEBUGP(" Get Media Status\n"); - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; - } else { - US_DEBUGP(" Nothing to do, just report okay\n"); - srb->result = GOOD; - sendToTransport = FALSE; - } - break; - - default: - US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); - srb->result = DID_ERROR << 16; - sendToTransport = FALSE; - break; - } - - return(sendToTransport); -} - - -/************************************************************************** - * isd200_init_info - * - * Allocates (if necessary) and initializes the driver structure. - * - * RETURNS: - * ISD status code - */ -int isd200_init_info(struct us_data *us) -{ - int retStatus = ISD200_GOOD; - - if (!us->extra) { - us->extra = (void *) kmalloc(sizeof(struct isd200_info), GFP_KERNEL); - if (!us->extra) { - US_DEBUGP("ERROR - kmalloc failure\n"); - retStatus = ISD200_ERROR; - } - } - - if (retStatus == ISD200_GOOD) { - memset(us->extra, 0, sizeof(struct isd200_info)); - } - - return(retStatus); -} - -/************************************************************************** - * Initialization for the ISD200 - */ - -int isd200_Initialization(struct us_data *us) -{ - US_DEBUGP("ISD200 Initialization...\n"); - - /* Initialize ISD200 info struct */ - - if (isd200_init_info(us) == ISD200_ERROR) { - US_DEBUGP("ERROR Initializing ISD200 Info struct\n"); - } else { - /* Get device specific data */ - - if (isd200_get_inquiry_data(us) != ISD200_GOOD) - US_DEBUGP("ISD200 Initialization Failure\n"); - else - US_DEBUGP("ISD200 Initialization complete\n"); - } - - return 0; -} - - -/************************************************************************** - * Protocol and Transport for the ISD200 ASIC - * - * This protocol and transport are for ATA devices connected to an ISD200 - * ASIC. An ATAPI device that is conected as a slave device will be - * detected in the driver initialization function and the protocol will - * be changed to an ATAPI protocol (Transparent SCSI). - * - */ - -void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us) -{ - int sendToTransport = TRUE; - union ata_cdb ataCdb; - - /* Make sure driver was initialized */ - - if (us->extra == NULL) - US_DEBUGP("ERROR Driver not initialized\n"); - - /* Convert command */ - sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); - - /* send the command to the transport layer */ - if (sendToTransport) - isd200_invoke_transport(us, srb, &ataCdb); -} diff --git a/drivers/usb/class/storage/isd200.h b/drivers/usb/class/storage/isd200.h deleted file mode 100644 index 70ebe1c39a86..000000000000 --- a/drivers/usb/class/storage/isd200.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Header File for In-System Design, Inc. ISD200 ASIC - * - * First release - * - * Current development and maintenance by: - * (c) 2000 In-System Design, Inc. (support@in-system.com) - * - * See isd200.c for more information. - * - * 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, 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. - */ - -#ifndef _USB_ISD200_H -#define _USB_ISD200_H - -extern void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us); -extern int isd200_Initialization(struct us_data *us); - -#endif diff --git a/drivers/usb/class/storage/jumpshot.c b/drivers/usb/class/storage/jumpshot.c deleted file mode 100644 index 94b9941cff01..000000000000 --- a/drivers/usb/class/storage/jumpshot.c +++ /dev/null @@ -1,804 +0,0 @@ -/* Driver for Lexar "Jumpshot" Compact Flash reader - * - * jumpshot driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver - * which I used as a template for this driver. - * Some bugfixes and scatter-gather code by Gregory P. Smith - * (greg-usb@electricrain.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, 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. - */ - - /* - * This driver attempts to support the Lexar Jumpshot USB CompactFlash - * reader. Like many other USB CompactFlash readers, the Jumpshot contains - * a USB-to-ATA chip. - * - * This driver supports reading and writing. If you're truly paranoid, - * however, you can force the driver into a write-protected state by setting - * the WP enable bits in jumpshot_handle_mode_sense. Basically this means - * setting mode_param_header[3] = 0x80. - */ - -#include "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "jumpshot.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> - -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, - u16 index, void *data, u16 size); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - -#if 0 -static void jumpshot_dump_data(unsigned char *data, int len) -{ - unsigned char buf[80]; - int sofar = 0; - - if (!data) - return; - - memset(buf, 0, sizeof(buf)); - - for (sofar = 0; sofar < len; sofar++) { - sprintf(buf + strlen(buf), "%02x ", - ((unsigned int) data[sofar]) & 0xFF); - - if (sofar % 16 == 15) { - US_DEBUGP("jumpshot: %s\n", buf); - memset(buf, 0, sizeof(buf)); - } - } - - if (strlen(buf) != 0) - US_DEBUGP("jumpshot: %s\n", buf); -} -#endif - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - * This routine snarfed from the SanDisk SDDR-09 driver - * - */ -static int jumpshot_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned short value, - unsigned short index, - unsigned char *xfer_data, - unsigned int xfer_len) -{ - int result; - - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, - value, index, xfer_data, xfer_len); - - // Check the return code for the command. - - if (result < 0) { - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* a stall is a fatal condition from the device */ - if (result == -EPIPE) { - US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("jumpshot_send_control: -- usb_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - - -static int jumpshot_raw_bulk(int direction, - struct us_data *us, - unsigned char *data, - unsigned int len) -{ - int result; - int act_len; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); - - // if we stall, we need to clear it before we go on - if (result == -EPIPE) { - US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); - } - - if (result) { - // NAK - that means we've retried a few times already - if (result == -ETIMEDOUT) { - US_DEBUGP("jumpshot_raw_bulk: device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - // -ENOENT -- we canceled this transfer - if (result == -ENOENT) { - US_DEBUGP("jumpshot_raw_bulk: transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - if (result == -EPIPE) { - US_DEBUGP("jumpshot_raw_bulk: output pipe stalled\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - // the catch-all case - US_DEBUGP("jumpshot_raw_bulk: unknown error\n"); - return US_BULK_TRANSFER_FAILED; - } - - if (act_len != len) { - US_DEBUGP("jumpshot_raw_bulk: Warning. Transferred only %d bytes\n", act_len); - return US_BULK_TRANSFER_SHORT; - } - - US_DEBUGP("jumpshot_raw_bulk: Transfered %d of %d bytes\n", act_len, len); - return US_BULK_TRANSFER_GOOD; -} - -static inline int jumpshot_bulk_read(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_TRANSPORT_GOOD; - - US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); - return jumpshot_raw_bulk(SCSI_DATA_READ, us, data, len); -} - - -static inline int jumpshot_bulk_write(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_TRANSPORT_GOOD; - - US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); - return jumpshot_raw_bulk(SCSI_DATA_WRITE, us, data, len); -} - - -static int jumpshot_get_status(struct us_data *us) -{ - unsigned char reply; - int rc; - - if (!us) - return USB_STOR_TRANSPORT_ERROR; - - // send the setup - rc = jumpshot_send_control(us, - usb_rcvctrlpipe(us->pusb_dev, 0), - 0, 0xA0, 0, 7, &reply, 1); - - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - if (reply != 0x50) { - US_DEBUGP("jumpshot_get_status: 0x%2x\n", - (unsigned short) (reply)); - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int jumpshot_read_data(struct us_data *us, - struct jumpshot_info *info, - u32 sector, - u32 sectors, - unsigned char *dest, - int use_sg) -{ - unsigned char command[] = { 0, 0, 0, 0, 0, 0xe0, 0x20 }; - unsigned char *buffer = NULL; - unsigned char *ptr; - unsigned char thistime; - struct scatterlist *sg = NULL; - int totallen, len, result; - int sg_idx = 0, current_sg_offset = 0; - int transferred; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - // If we're using scatter-gather, we have to create a new - // buffer to read all of the data in first, since a - // scatter-gather buffer could in theory start in the middle - // of a page, which would be bad. A developer who wants a - // challenge might want to write a limited-buffer - // version of this code. - - totallen = sectors * info->ssize; - - do { - // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit) - len = min_t(int, totallen, 65536); - - if (use_sg) { - sg = (struct scatterlist *) dest; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - ptr = buffer; - } else { - ptr = dest; - } - - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] |= (sector >> 24) & 0x0F; - - // send the setup + command - result = jumpshot_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), - 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - // read the result - result = jumpshot_bulk_read(us, ptr, len); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - US_DEBUGP("jumpshot_read_data: %d bytes\n", len); - //jumpshot_dump_data(ptr, len); - - sectors -= thistime; - sector += thistime; - - if (use_sg) { - transferred = 0; - while (sg_idx < use_sg && transferred < len) { - if (len - transferred >= sg[sg_idx].length - current_sg_offset) { - US_DEBUGP("jumpshot_read_data: adding %d bytes to %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length); - memcpy(sg[sg_idx].address + current_sg_offset, - buffer + transferred, - sg[sg_idx].length - current_sg_offset); - transferred += sg[sg_idx].length - current_sg_offset; - current_sg_offset = 0; - // on to the next sg buffer - ++sg_idx; - } else { - US_DEBUGP("jumpshot_read_data: adding %d bytes to %d byte sg buffer\n", len - transferred, sg[sg_idx].length); - memcpy(sg[sg_idx].address + current_sg_offset, - buffer + transferred, - len - transferred); - current_sg_offset += len - transferred; - // this sg buffer is only partially full and we're out of data to copy in - break; - } - } - kfree(buffer); - } else { - dest += len; - } - - totallen -= len; - } while (totallen > 0); - - return USB_STOR_TRANSPORT_GOOD; -} - - -static int jumpshot_write_data(struct us_data *us, - struct jumpshot_info *info, - u32 sector, - u32 sectors, - unsigned char *src, - int use_sg) -{ - unsigned char command[7] = { 0, 0, 0, 0, 0, 0xE0, 0x30 }; - unsigned char *buffer = NULL; - unsigned char *ptr; - unsigned char thistime; - struct scatterlist *sg = NULL; - int totallen, len, result, waitcount; - int sg_idx = 0, current_sg_offset = 0; - int transferred; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - // If we're using scatter-gather, we have to create a new - // buffer to read all of the data in first, since a - // scatter-gather buffer could in theory start in the middle - // of a page, which would be bad. A developer who wants a - // challenge might want to write a limited-buffer - // version of this code. - - totallen = sectors * info->ssize; - - do { - // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit) - len = min_t(int, totallen, 65536); - - if (use_sg) { - sg = (struct scatterlist *) src; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - ptr = buffer; - - memset(buffer, 0, len); - - // copy the data from the sg bufs into the big contiguous buf - // - transferred = 0; - while (transferred < len) { - if (len - transferred >= sg[sg_idx].length - current_sg_offset) { - US_DEBUGP("jumpshot_write_data: getting %d bytes from %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length); - memcpy(ptr + transferred, - sg[sg_idx].address + current_sg_offset, - sg[sg_idx].length - current_sg_offset); - transferred += sg[sg_idx].length - current_sg_offset; - current_sg_offset = 0; - // on to the next sg buffer - ++sg_idx; - } else { - US_DEBUGP("jumpshot_write_data: getting %d bytes from %d byte sg buffer\n", len - transferred, sg[sg_idx].length); - memcpy(ptr + transferred, - sg[sg_idx].address + current_sg_offset, - len - transferred); - current_sg_offset += len - transferred; - // we only copied part of this sg buffer - break; - } - } - } else { - ptr = src; - } - - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] |= (sector >> 24) & 0x0F; - - // send the setup + command - result = jumpshot_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), - 0, 0x20, 0, 1, command, 7); - - // send the data - result = jumpshot_bulk_write(us, ptr, len); - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - // read the result. apparently the bulk write can complete before the - // jumpshot drive is finished writing. so we loop here until we - // get a good return code - waitcount = 0; - do { - result = jumpshot_get_status(us); - if (result != USB_STOR_TRANSPORT_GOOD) { - // I have not experimented to find the smallest value. - // - wait_ms(50); - } - } while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10)); - - if (result != USB_STOR_TRANSPORT_GOOD) - US_DEBUGP("jumpshot_write_data: Gah! Waitcount = 10. Bad write!?\n"); - - sectors -= thistime; - sector += thistime; - - if (use_sg) { - kfree(buffer); - } else { - src += len; - } - - totallen -= len; - } while (totallen > 0); - - return result; -} - -static int jumpshot_id_device(struct us_data *us, - struct jumpshot_info *info) -{ - unsigned char command[2] = { 0xe0, 0xec }; - unsigned char reply[512]; - int rc; - - if (!us || !info) - return USB_STOR_TRANSPORT_ERROR; - - // send the setup - rc = jumpshot_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), - 0, 0x20, 0, 6, command, 2); - - if (rc != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("jumpshot_id_device: Gah! send_control for read_capacity failed\n"); - return rc; - } - - // read the reply - rc = jumpshot_bulk_read(us, reply, sizeof(reply)); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - info->sectors = ((u32)(reply[117]) << 24) | - ((u32)(reply[116]) << 16) | - ((u32)(reply[115]) << 8) | - ((u32)(reply[114]) ); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int jumpshot_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, - unsigned char *ptr, - int sense_6) -{ - unsigned char mode_param_header[8] = { - 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char rw_err_page[12] = { - 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 - }; - unsigned char cache_page[12] = { - 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char rbac_page[12] = { - 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char timer_page[8] = { - 0x1C, 0x6, 0, 0, 0, 0 - }; - unsigned char pc, page_code; - unsigned short total_len = 0; - unsigned short param_len, i = 0; - - - if (sense_6) - param_len = srb->cmnd[4]; - else - param_len = ((u32) (srb->cmnd[7]) >> 8) | ((u32) (srb->cmnd[8])); - - - pc = srb->cmnd[2] >> 6; - page_code = srb->cmnd[2] & 0x3F; - - switch (pc) { - case 0x0: - US_DEBUGP("jumpshot_handle_mode_sense: Current values\n"); - break; - case 0x1: - US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n"); - break; - case 0x2: - US_DEBUGP("jumpshot_handle_mode_sense: Default values\n"); - break; - case 0x3: - US_DEBUGP("jumpshot_handle_mode_sense: Saves values\n"); - break; - } - - mode_param_header[3] = 0x80; // write enable - - switch (page_code) { - case 0x0: - // vendor-specific mode - return USB_STOR_TRANSPORT_ERROR; - - case 0x1: - total_len = sizeof(rw_err_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - break; - - case 0x8: - total_len = sizeof(cache_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - break; - - case 0x1B: - total_len = sizeof(rbac_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - break; - - case 0x1C: - total_len = sizeof(timer_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, timer_page, sizeof(timer_page)); - break; - - case 0x3F: - total_len = sizeof(timer_page) + sizeof(rbac_page) + - sizeof(cache_page) + sizeof(rw_err_page); - mode_param_header[0] = total_len >> 8; - mode_param_header[1] = total_len & 0xFF; - mode_param_header[3] = 0x00; // WP enable: 0x80 - - memcpy(ptr, mode_param_header, sizeof(mode_param_header)); - i += sizeof(mode_param_header); - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - break; - } - - return USB_STOR_TRANSPORT_GOOD; -} - - -void jumpshot_info_destructor(void *extra) -{ - // this routine is a placeholder... - // currently, we don't allocate any extra blocks so we're okay -} - - - -// Transport for the Lexar 'Jumpshot' -// -int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) -{ - struct jumpshot_info *info; - int rc; - unsigned long block, blocks; - unsigned char *ptr = NULL; - unsigned char inquiry_response[36] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - - if (!us->extra) { - us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - memset(us->extra, 0, sizeof(struct jumpshot_info)); - us->extra_destructor = jumpshot_info_destructor; - } - - info = (struct jumpshot_info *) (us->extra); - ptr = (unsigned char *) srb->request_buffer; - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n"); - memset(inquiry_response + 8, 0, 28); - fill_inquiry_response(us, inquiry_response, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec - - rc = jumpshot_get_status(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - rc = jumpshot_id_device(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("jumpshot_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); - - // build the reply - // - ptr[0] = (info->sectors >> 24) & 0xFF; - ptr[1] = (info->sectors >> 16) & 0xFF; - ptr[2] = (info->sectors >> 8) & 0xFF; - ptr[3] = (info->sectors) & 0xFF; - - ptr[4] = (info->ssize >> 24) & 0xFF; - ptr[5] = (info->ssize >> 16) & 0xFF; - ptr[6] = (info->ssize >> 8) & 0xFF; - ptr[7] = (info->ssize) & 0xFF; - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("jumpshot_transport: Gah! MODE_SELECT_10.\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (srb->cmnd[0] == READ_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("jumpshot_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); - return jumpshot_read_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == READ_12) { - // I don't think we'll ever see a READ_12 but support it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("jumpshot_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); - return jumpshot_read_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == WRITE_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("jumpshot_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); - return jumpshot_write_data(us, info, block, blocks, ptr, srb->use_sg); - } - - if (srb->cmnd[0] == WRITE_12) { - // I don't think we'll ever see a WRITE_12 but support it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); - return jumpshot_write_data(us, info, block, blocks, ptr, srb->use_sg); - } - - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n"); - return jumpshot_get_status(us); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("jumpshot_transport: REQUEST_SENSE. Returning NO SENSE for now\n"); - - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); - return jumpshot_handle_mode_sense(us, srb, ptr, TRUE); - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); - return jumpshot_handle_mode_sense(us, srb, ptr, FALSE); - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from popping - // the media out of the device (no locking doors, etc) - // - return USB_STOR_TRANSPORT_GOOD; - } - - US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); - return USB_STOR_TRANSPORT_ERROR; -} diff --git a/drivers/usb/class/storage/jumpshot.h b/drivers/usb/class/storage/jumpshot.h deleted file mode 100644 index 8147197cd4fc..000000000000 --- a/drivers/usb/class/storage/jumpshot.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Driver for Lexar "Jumpshot" USB Compact Flash reader - * Header File - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * - * See jumpshot.c for more explanation - * - * 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, 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. - */ - -#ifndef _USB_JUMPSHOT_H -#define _USB_JUMPSHOT_H - -extern int jumpshot_transport(Scsi_Cmnd *srb, struct us_data *us); - -struct jumpshot_info { - unsigned long sectors; // total sector count - unsigned long ssize; // sector size in bytes - - // the following aren't used yet - unsigned char sense_key; - unsigned long sense_asc; // additional sense code - unsigned long sense_ascq; // additional sense code qualifier -}; - -#endif diff --git a/drivers/usb/class/storage/protocol.c b/drivers/usb/class/storage/protocol.c deleted file mode 100644 index c2bc41be7357..000000000000 --- a/drivers/usb/class/storage/protocol.c +++ /dev/null @@ -1,339 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "protocol.h" -#include "usb.h" -#include "debug.h" -#include "scsiglue.h" -#include "transport.h" - -/*********************************************************************** - * Helper routines - ***********************************************************************/ - -/* Fix-up the return data from an INQUIRY command to show - * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us - */ -void fix_inquiry_data(Scsi_Cmnd *srb) -{ - unsigned char *data_ptr; - - /* verify that it's an INQUIRY command */ - if (srb->cmnd[0] != INQUIRY) - return; - - US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n"); - - /* find the location of the data */ - if (srb->use_sg) - BUG(); - - data_ptr = (unsigned char *) srb->request_buffer; - - /* Change the SCSI revision number */ - data_ptr[2] = (data_ptr[2] & ~7) | 2; -} - -/*********************************************************************** - * Protocol routines - ***********************************************************************/ - -void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) -{ - /* Pad the ATAPI command with zeros - * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available - */ - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - /* set command length to 12 bytes */ - srb->cmd_len = 12; - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); -} - -void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) -{ - int old_cmnd = 0; - - /* Fix some commands -- this is a form of mode translation - * ATAPI devices only accept 12 byte long commands - * - * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available - */ - - /* Pad the ATAPI command with zeros */ - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - /* set command length to 12 bytes */ - srb->cmd_len = 12; - - /* determine the correct (or minimum) data length for these commands */ - switch (srb->cmnd[0]) { - - /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ - case MODE_SENSE: - case MODE_SELECT: - /* save the command so we can tell what it was */ - old_cmnd = srb->cmnd[0]; - - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - - /* change READ_6/WRITE_6 to READ_10/WRITE_10, which - * are ATAPI commands */ - case WRITE_6: - case READ_6: - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - } /* end switch on cmnd[0] */ - - /* convert MODE_SELECT data here */ - if (old_cmnd == MODE_SELECT) - usb_stor_scsiSense6to10(srb); - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); - - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); -} - - -void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) -{ - int old_cmnd = 0; - - /* fix some commands -- this is a form of mode translation - * UFI devices only accept 12 byte long commands - * - * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available - */ - - /* set command length to 12 bytes (this affects the transport layer) */ - srb->cmd_len = 12; - - /* determine the correct (or minimum) data length for these commands */ - switch (srb->cmnd[0]) { - - /* for INQUIRY, UFI devices only ever return 36 bytes */ - case INQUIRY: - srb->cmnd[4] = 36; - break; - - /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ - case MODE_SENSE: - case MODE_SELECT: - /* save the command so we can tell what it was */ - old_cmnd = srb->cmnd[0]; - - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - - /* if we're sending data, we send all. If getting data, - * get the minimum */ - if (srb->cmnd[0] == MODE_SELECT) - srb->cmnd[8] = srb->cmnd[4]; - else - srb->cmnd[8] = 8; - - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - - /* again, for MODE_SENSE_10, we get the minimum (8) */ - case MODE_SENSE_10: - srb->cmnd[7] = 0; - srb->cmnd[8] = 8; - break; - - /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ - case REQUEST_SENSE: - srb->cmnd[4] = 18; - break; - - /* change READ_6/WRITE_6 to READ_10/WRITE_10, which - * are UFI commands */ - case WRITE_6: - case READ_6: - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - } /* end switch on cmnd[0] */ - - /* convert MODE_SELECT data here */ - if (old_cmnd == MODE_SELECT) - usb_stor_scsiSense6to10(srb); - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); - - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* Fix the data for an INQUIRY, if necessary */ - fix_inquiry_data(srb); -} - -void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) -{ - int old_cmnd = 0; - - /* This code supports devices which do not support {READ|WRITE}_6 - * Apparently, neither Windows or MacOS will use these commands, - * so some devices do not support them - */ - if (us->flags & US_FL_MODE_XLATE) { - US_DEBUGP("Invoking Mode Translation\n"); - /* save the old command for later */ - old_cmnd = srb->cmnd[0]; - - switch (srb->cmnd[0]) { - /* change READ_6/WRITE_6 to READ_10/WRITE_10 */ - case WRITE_6: - case READ_6: - srb->cmd_len = 12; - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - - /* convert MODE_SELECT data here */ - case MODE_SENSE: - case MODE_SELECT: - srb->cmd_len = 12; - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - } /* switch (srb->cmnd[0]) */ - } /* if (us->flags & US_FL_MODE_XLATE) */ - - /* convert MODE_SELECT data here */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SELECT)) - usb_stor_scsiSense6to10(srb); - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); - - /* Fix the MODE_SENSE data if we translated the command */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE) - && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); -} - diff --git a/drivers/usb/class/storage/protocol.h b/drivers/usb/class/storage/protocol.h deleted file mode 100644 index 4153a6c7144b..000000000000 --- a/drivers/usb/class/storage/protocol.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Protocol Functions Header File - * - * $Id: protocol.h,v 1.4 2001/02/13 07:10:03 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -#ifndef _PROTOCOL_H_ -#define _PROTOCOL_H_ - -#include <linux/blk.h> -#include "scsi.h" -#include "usb.h" - -/* Sub Classes */ - -#define US_SC_RBC 0x01 /* Typically, flash devices */ -#define US_SC_8020 0x02 /* CD-ROM */ -#define US_SC_QIC 0x03 /* QIC-157 Tapes */ -#define US_SC_UFI 0x04 /* Floppy */ -#define US_SC_8070 0x05 /* Removable media */ -#define US_SC_SCSI 0x06 /* Transparent */ -#define US_SC_ISD200 0x07 /* ISD200 ATA */ -#define US_SC_MIN US_SC_RBC -#define US_SC_MAX US_SC_ISD200 - -extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*); - -#endif diff --git a/drivers/usb/class/storage/scsiglue.c b/drivers/usb/class/storage/scsiglue.c deleted file mode 100644 index 596aa799adf1..000000000000 --- a/drivers/usb/class/storage/scsiglue.c +++ /dev/null @@ -1,900 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * SCSI layer glue code - * - * $Id: scsiglue.c,v 1.24 2001/11/11 03:33:58 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "scsiglue.h" -#include "usb.h" -#include "debug.h" -#include "transport.h" - -#include <linux/slab.h> - -/* - * kernel thread actions - */ - -#define US_ACT_COMMAND 1 -#define US_ACT_DEVICE_RESET 2 -#define US_ACT_BUS_RESET 3 -#define US_ACT_HOST_RESET 4 -#define US_ACT_EXIT 5 - -/*********************************************************************** - * Host functions - ***********************************************************************/ - -static const char* host_info(struct Scsi_Host *host) -{ - return "SCSI emulation for USB Mass Storage devices"; -} - -/* detect a virtual adapter (always works) */ -static int detect(struct SHT *sht) -{ - struct us_data *us; - char local_name[32]; - - /* This is not nice at all, but how else are we to get the - * data here? */ - us = (struct us_data *)sht->proc_dir; - - /* set up the name of our subdirectory under /proc/scsi/ */ - sprintf(local_name, "usb-storage-%d", us->host_number); - sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); - if (!sht->proc_name) - return 0; - strcpy(sht->proc_name, local_name); - - /* we start with no /proc directory entry */ - sht->proc_dir = NULL; - - /* register the host */ - us->host = scsi_register(sht, sizeof(us)); - if (us->host) { - us->host->hostdata[0] = (unsigned long)us; - us->host_no = us->host->host_no; - return 1; - } - - /* odd... didn't register properly. Abort and free pointers */ - kfree(sht->proc_name); - sht->proc_name = NULL; - return 0; -} - -/* Release all resources used by the virtual host - * - * NOTE: There is no contention here, because we're already deregistered - * the driver and we're doing each virtual host in turn, not in parallel - */ -static int release(struct Scsi_Host *psh) -{ - struct us_data *us = (struct us_data *)psh->hostdata[0]; - - US_DEBUGP("release() called for host %s\n", us->htmplt.name); - - /* Kill the control threads - * - * Enqueue the command, wake up the thread, and wait for - * notification that it's exited. - */ - US_DEBUGP("-- sending US_ACT_EXIT command to thread\n"); - us->action = US_ACT_EXIT; - - up(&(us->sema)); - wait_for_completion(&(us->notify)); - - /* remove the pointer to the data structure we were using */ - (struct us_data*)psh->hostdata[0] = NULL; - - /* we always have a successful release */ - return 0; -} - -/* run command */ -static int command( Scsi_Cmnd *srb ) -{ - US_DEBUGP("Bad use of us_command\n"); - - return DID_BAD_TARGET << 16; -} - -/* run command */ -static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - US_DEBUGP("queuecommand() called\n"); - srb->host_scribble = (unsigned char *)us; - - /* get exclusive access to the structures we want */ - down(&(us->queue_exclusion)); - - /* enqueue the command */ - us->queue_srb = srb; - srb->scsi_done = done; - us->action = US_ACT_COMMAND; - - /* release the lock on the structure */ - up(&(us->queue_exclusion)); - - /* wake up the process task */ - up(&(us->sema)); - - return 0; -} - -/*********************************************************************** - * Error handling functions - ***********************************************************************/ - -/* Command abort */ -static int command_abort( Scsi_Cmnd *srb ) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - US_DEBUGP("command_abort() called\n"); - - /* if we're stuck waiting for an IRQ, simulate it */ - if (atomic_read(us->ip_wanted)) { - US_DEBUGP("-- simulating missing IRQ\n"); - up(&(us->ip_waitq)); - } - - /* if the device has been removed, this worked */ - if (!us->pusb_dev) { - US_DEBUGP("-- device removed already\n"); - return SUCCESS; - } - - /* if we have an urb pending, let's wake the control thread up */ - if (us->current_urb->status == -EINPROGRESS) { - /* cancel the URB -- this will automatically wake the thread */ - usb_unlink_urb(us->current_urb); - - /* wait for us to be done */ - wait_for_completion(&(us->notify)); - return SUCCESS; - } - - US_DEBUGP ("-- nothing to abort\n"); - return FAILED; -} - -/* This invokes the transport reset mechanism to reset the state of the - * device */ -static int device_reset( Scsi_Cmnd *srb ) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - US_DEBUGP("device_reset() called\n" ); - return us->transport_reset(us); -} - -/* This resets the device port, and simulates the device - * disconnect/reconnect for all drivers which have claimed other - * interfaces. */ -static int bus_reset( Scsi_Cmnd *srb ) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - int i; - int result; - - /* we use the usb_reset_device() function to handle this for us */ - US_DEBUGP("bus_reset() called\n"); - - /* if the device has been removed, this worked */ - if (!us->pusb_dev) { - US_DEBUGP("-- device removed already\n"); - return SUCCESS; - } - - /* release the IRQ, if we have one */ - down(&(us->irq_urb_sem)); - if (us->irq_urb) { - US_DEBUGP("-- releasing irq URB\n"); - result = usb_unlink_urb(us->irq_urb); - US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); - } - up(&(us->irq_urb_sem)); - - /* attempt to reset the port */ - if (usb_reset_device(us->pusb_dev) < 0) - return FAILED; - - /* FIXME: This needs to lock out driver probing while it's working - * or we can have race conditions */ - for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { - struct usb_interface *intf = - &us->pusb_dev->actconfig->interface[i]; - const struct usb_device_id *id; - - /* if this is an unclaimed interface, skip it */ - if (!intf->driver) { - continue; - } - - US_DEBUGP("Examinging driver %s...", intf->driver->name); - /* skip interfaces which we've claimed */ - if (intf->driver == &usb_storage_driver) { - US_DEBUGPX("skipping ourselves.\n"); - continue; - } - - /* simulate a disconnect and reconnect for all interfaces */ - US_DEBUGPX("simulating disconnect/reconnect.\n"); - down(&intf->driver->serialize); - intf->driver->disconnect(us->pusb_dev, intf->private_data); - id = usb_match_id(us->pusb_dev, intf, intf->driver->id_table); - intf->driver->probe(us->pusb_dev, i, id); - up(&intf->driver->serialize); - } - - /* re-allocate the IRQ URB and submit it to restore connectivity - * for CBI devices - */ - if (us->protocol == US_PR_CBI) { - down(&(us->irq_urb_sem)); - us->irq_urb->dev = us->pusb_dev; - result = usb_submit_urb(us->irq_urb, GFP_NOIO); - US_DEBUGP("usb_submit_urb() returns %d\n", result); - up(&(us->irq_urb_sem)); - } - - US_DEBUGP("bus_reset() complete\n"); - return SUCCESS; -} - -/* FIXME: This doesn't do anything right now */ -static int host_reset( Scsi_Cmnd *srb ) -{ - printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" ); - return FAILED; -} - -/*********************************************************************** - * /proc/scsi/ functions - ***********************************************************************/ - -/* we use this macro to help us write into the buffer */ -#undef SPRINTF -#define SPRINTF(args...) \ - do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) - -static int proc_info (char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ - struct us_data *us; - char *pos = buffer; - - /* if someone is sending us data, just throw it away */ - if (inout) - return length; - - /* lock the data structures */ - down(&us_list_semaphore); - - /* find our data from hostno */ - us = us_list; - while (us) { - if (us->host_no == hostno) - break; - us = us->next; - } - - /* release our lock on the data structures */ - up(&us_list_semaphore); - - /* if we couldn't find it, we return an error */ - if (!us) { - return -ESRCH; - } - - /* print the controller name */ - SPRINTF(" Host scsi%d: usb-storage\n", hostno); - - /* print product, vendor, and serial number strings */ - SPRINTF(" Vendor: %s\n", us->vendor); - SPRINTF(" Product: %s\n", us->product); - SPRINTF("Serial Number: %s\n", us->serial); - - /* show the protocol and transport */ - SPRINTF(" Protocol: %s\n", us->protocol_name); - SPRINTF(" Transport: %s\n", us->transport_name); - - /* show the GUID of the device */ - SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); - SPRINTF(" Attached: %s\n", us->pusb_dev ? "Yes" : "No"); - - /* - * Calculate start of next buffer, and return value. - */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - -/* - * this defines our 'host' - */ - -Scsi_Host_Template usb_stor_host_template = { - name: "usb-storage", - proc_info: proc_info, - info: host_info, - - detect: detect, - release: release, - command: command, - queuecommand: queuecommand, - - eh_abort_handler: command_abort, - eh_device_reset_handler:device_reset, - eh_bus_reset_handler: bus_reset, - eh_host_reset_handler: host_reset, - - can_queue: 1, - this_id: -1, - - sg_tablesize: SG_ALL, - cmd_per_lun: 1, - present: 0, - unchecked_isa_dma: FALSE, - use_clustering: TRUE, - emulated: TRUE -}; - -unsigned char usb_stor_sense_notready[18] = { - [0] = 0x70, /* current error */ - [2] = 0x02, /* not ready */ - [5] = 0x0a, /* additional length */ - [10] = 0x04, /* not ready */ - [11] = 0x03 /* manual intervention */ -}; - -#define USB_STOR_SCSI_SENSE_HDRSZ 4 -#define USB_STOR_SCSI_SENSE_10_HDRSZ 8 - -struct usb_stor_scsi_sense_hdr -{ - __u8* dataLength; - __u8* mediumType; - __u8* devSpecParms; - __u8* blkDescLength; -}; - -typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; - -union usb_stor_scsi_sense_hdr_u -{ - Usb_Stor_Scsi_Sense_Hdr hdr; - __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; -}; - -typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; - -struct usb_stor_scsi_sense_hdr_10 -{ - __u8* dataLengthMSB; - __u8* dataLengthLSB; - __u8* mediumType; - __u8* devSpecParms; - __u8* reserved1; - __u8* reserved2; - __u8* blkDescLengthMSB; - __u8* blkDescLengthLSB; -}; - -typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; - -union usb_stor_scsi_sense_hdr_10_u -{ - Usb_Stor_Scsi_Sense_Hdr_10 hdr; - __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; -}; - -typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; - -void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, - Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); - -int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) -{ - __u8 *buffer=0; - int outputBufferSize = 0; - int length=0; - struct scatterlist *sg = 0; - int i=0, j=0, element=0; - Usb_Stor_Scsi_Sense_Hdr_u the6Locations; - Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; - int sb=0,si=0,db=0,di=0; - int sgLength=0; - - US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); - the10->cmnd[0] = the10->cmnd[0] & 0xBF; - - /* Determine buffer locations */ - usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, - &length ); - - /* Work out minimum buffer to output */ - outputBufferSize = *the10Locations.hdr.dataLengthLSB; - outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; - - /* Check to see if we need to trucate the output */ - if ( outputBufferSize > length ) - { - printk( KERN_WARNING USB_STORAGE - "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); - printk( KERN_WARNING USB_STORAGE - "outputBufferSize is %d and length is %d.\n", - outputBufferSize, length ); - } - outputBufferSize = length; - - /* Data length */ - if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ - { - printk( KERN_WARNING USB_STORAGE - "Command will be truncated to fit in SENSE6 buffer.\n" ); - *the6Locations.hdr.dataLength = 0xff; - } - else - { - *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; - } - - /* Medium type and DevSpecific parms */ - *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; - *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; - - /* Block descriptor length */ - if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ - { - printk( KERN_WARNING USB_STORAGE - "Command will be truncated to fit in SENSE6 buffer.\n" ); - *the6Locations.hdr.blkDescLength = 0xff; - } - else - { - *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; - } - - if ( the10->use_sg == 0 ) - { - buffer = the10->request_buffer; - /* Copy the rest of the data */ - memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), - &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); - /* initialise last bytes left in buffer due to smaller header */ - memset( &(buffer[outputBufferSize - -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), - 0, - USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); - } - else - { - sg = (struct scatterlist *) the10->request_buffer; - /* scan through this scatterlist and figure out starting positions */ - for ( i=0; i < the10->use_sg; i++) - { - sgLength = sg[i].length; - for ( j=0; j<sgLength; j++ ) - { - /* get to end of header */ - if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) - { - db=i; - di=j; - } - if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - sb=i; - si=j; - /* we've found both sets now, exit loops */ - j=sgLength; - i=the10->use_sg; - } - element++; - } - } - - /* Now we know where to start the copy from */ - element = USB_STOR_SCSI_SENSE_HDRSZ; - while ( element < outputBufferSize - -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) - { - /* check limits */ - if ( sb >= the10->use_sg || - si >= sg[sb].length || - db >= the10->use_sg || - di >= sg[db].length ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - /* copy one byte */ - { - char *src = page_address(sg[sb].page) + sg[sb].offset + si; - char *dst = page_address(sg[db].page) + sg[db].offset + di; - - *dst = *src; - } - - /* get next destination */ - if ( sg[db].length-1 == di ) - { - db++; - di=0; - } - else - { - di++; - } - - /* get next source */ - if ( sg[sb].length-1 == si ) - { - sb++; - si=0; - } - else - { - si++; - } - - element++; - } - /* zero the remaining bytes */ - while ( element < outputBufferSize ) - { - /* check limits */ - if ( db >= the10->use_sg || - di >= sg[db].length ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - *(char *)(page_address(sg[db].page) + sg[db].offset) = 0; - - /* get next destination */ - if ( sg[db].length-1 == di ) - { - db++; - di=0; - } - else - { - di++; - } - element++; - } - } - - /* All done any everything was fine */ - return 0; -} - -int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) -{ - /* will be used to store part of buffer */ - __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], - *buffer=0; - int outputBufferSize = 0; - int length=0; - struct scatterlist *sg = 0; - int i=0, j=0, element=0; - Usb_Stor_Scsi_Sense_Hdr_u the6Locations; - Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; - int sb=0,si=0,db=0,di=0; - int lsb=0,lsi=0,ldb=0,ldi=0; - - US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); - the6->cmnd[0] = the6->cmnd[0] | 0x40; - - /* Determine buffer locations */ - usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, - &length ); - - /* Work out minimum buffer to output */ - outputBufferSize = *the6Locations.hdr.dataLength; - outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; - - /* Check to see if we need to trucate the output */ - if ( outputBufferSize > length ) - { - printk( KERN_WARNING USB_STORAGE - "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); - printk( KERN_WARNING USB_STORAGE - "outputBufferSize is %d and length is %d.\n", - outputBufferSize, length ); - } - outputBufferSize = length; - - /* Block descriptor length - save these before overwriting */ - tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; - tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; - *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; - *the10Locations.hdr.blkDescLengthMSB = 0; - - /* reserved - save these before overwriting */ - tempBuffer[0] = *the10Locations.hdr.reserved1; - tempBuffer[1] = *the10Locations.hdr.reserved2; - *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; - - /* Medium type and DevSpecific parms */ - *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; - *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; - - /* Data length */ - *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; - *the10Locations.hdr.dataLengthMSB = 0; - - if ( !the6->use_sg ) - { - buffer = the6->request_buffer; - /* Copy the rest of the data */ - memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), - outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); - /* Put the first four bytes (after header) in place */ - memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), - tempBuffer, - USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); - } - else - { - sg = (struct scatterlist *) the6->request_buffer; - /* scan through this scatterlist and figure out ending positions */ - for ( i=0; i < the6->use_sg; i++) - { - for ( j=0; j<sg[i].length; j++ ) - { - /* get to end of header */ - if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) - { - ldb=i; - ldi=j; - } - if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - lsb=i; - lsi=j; - /* we've found both sets now, exit loops */ - j=sg[i].length; - i=the6->use_sg; - break; - } - element++; - } - } - /* scan through this scatterlist and figure out starting positions */ - element = length-1; - /* destination is the last element */ - db=the6->use_sg-1; - di=sg[db].length-1; - for ( i=the6->use_sg-1; i >= 0; i--) - { - for ( j=sg[i].length-1; j>=0; j-- ) - { - /* get to end of header and find source for copy */ - if ( element == length - 1 - - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) - { - sb=i; - si=j; - /* we've found both sets now, exit loops */ - j=-1; - i=-1; - } - element--; - } - } - /* Now we know where to start the copy from */ - element = length-1 - - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); - while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* check limits */ - if ( ( sb <= lsb && si < lsi ) || - ( db <= ldb && di < ldi ) ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - /* copy one byte */ - { - char *src = page_address(sg[sb].page) + sg[sb].offset + si; - char *dst = page_address(sg[db].page) + sg[db].offset + di; - - *dst = *src; - } - - /* get next destination */ - if ( di == 0 ) - { - db--; - di=sg[db].length-1; - } - else - { - di--; - } - - /* get next source */ - if ( si == 0 ) - { - sb--; - si=sg[sb].length-1; - } - else - { - si--; - } - - element--; - } - /* copy the remaining four bytes */ - while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) - { - /* check limits */ - if ( db <= ldb && di < ldi ) - { - printk( KERN_ERR USB_STORAGE - "Buffer overrun averted, this shouldn't happen!\n" ); - break; - } - - { - char *dst = page_address(sg[db].page) + sg[db].offset + di; - - *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; - } - - /* get next destination */ - if ( di == 0 ) - { - db--; - di=sg[db].length-1; - } - else - { - di--; - } - element--; - } - } - - /* All done and everything was fine */ - return 0; -} - -void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, - Usb_Stor_Scsi_Sense_Hdr_10_u* the10, - int* length_p ) - -{ - int i = 0, j=0, element=0; - struct scatterlist *sg = 0; - int length = 0; - __u8* buffer=0; - - /* are we scatter-gathering? */ - if ( srb->use_sg != 0 ) - { - /* loop over all the scatter gather structures and - * get pointer to the data members in the headers - * (also work out the length while we're here) - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - { - length += sg[i].length; - /* We only do the inner loop for the headers */ - if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* scan through this scatterlist */ - for ( j=0; j<sg[i].length; j++ ) - { - if ( element < USB_STOR_SCSI_SENSE_HDRSZ ) - { - /* fill in the pointers for both header types */ - the6->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; - the10->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; - } - else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) - { - /* only the longer headers still cares now */ - the10->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; - } - /* increase element counter */ - element++; - } - } - } - } - else - { - length = srb->request_bufflen; - buffer = srb->request_buffer; - if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) - printk( KERN_ERR USB_STORAGE - "Buffer length smaller than header!!" ); - for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ ) - { - if ( i < USB_STOR_SCSI_SENSE_HDRSZ ) - { - the6->array[i] = &(buffer[i]); - the10->array[i] = &(buffer[i]); - } - else - { - the10->array[i] = &(buffer[i]); - } - } - } - - /* Set value of length passed in */ - *length_p = length; -} - diff --git a/drivers/usb/class/storage/scsiglue.h b/drivers/usb/class/storage/scsiglue.h deleted file mode 100644 index 13b9f3bec266..000000000000 --- a/drivers/usb/class/storage/scsiglue.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * SCSI Connecting Glue Header File - * - * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -#ifndef _SCSIGLUE_H_ -#define _SCSIGLUE_H_ - -#include <linux/blk.h> -#include "scsi.h" -#include "hosts.h" - -extern unsigned char usb_stor_sense_notready[18]; -extern Scsi_Host_Template usb_stor_host_template; -extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); -extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); - -#endif diff --git a/drivers/usb/class/storage/sddr09.c b/drivers/usb/class/storage/sddr09.c deleted file mode 100644 index bc14015ae97f..000000000000 --- a/drivers/usb/class/storage/sddr09.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* Driver for SanDisk SDDR-09 SmartMedia reader - * - * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $ - * - * SDDR09 driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000, 2001 Robert Baruch (autophile@starband.net) - * - * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. - * This chip is a programmable USB controller. In the SDDR-09, it has - * been programmed to obey a certain limited set of SCSI commands. This - * driver translates the "real" SCSI commands to the SDDR-09 SCSI - * commands. - * - * 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, 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 "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "sddr09.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> - -#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - */ - -static int sddr09_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned short value, - unsigned short index, - unsigned char *xfer_data, - unsigned int xfer_len) { - - int result; - - // If data is going to be sent or received with the URB, - // then allocate a buffer for it. If data is to be sent, - // copy the data into the buffer. -/* - if (xfer_len > 0) { - buffer = kmalloc(xfer_len, GFP_NOIO); - if (!(command[0] & USB_DIR_IN)) - memcpy(buffer, xfer_data, xfer_len); - } -*/ - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, value, index, - xfer_data, xfer_len); - - - // If data was sent or received with the URB, free the buffer we - // allocated earlier, but not before reading the data out of the - // buffer if we wanted to receive data. -/* - if (xfer_len > 0) { - if (command[0] & USB_DIR_IN) - memcpy(xfer_data, buffer, xfer_len); - kfree(buffer); - } -*/ - // Check the return code for the command. - - if (result < 0) { - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* a stall is a fatal condition from the device */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int sddr09_raw_bulk(struct us_data *us, - int direction, - unsigned char *data, - unsigned int len) { - - int result; - int act_len; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("EPIPE: clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", - pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); - } - - if (result) { - - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usbat_raw_bulk():" - " device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usbat_raw_bulk():" - " transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - if (result == -EPIPE) { - US_DEBUGP("usbat_raw_bulk():" - " output pipe stalled\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - /* the catch-all case */ - US_DEBUGP("us_transfer_partial(): unknown error\n"); - return US_BULK_TRANSFER_FAILED; - } - - if (act_len != len) { - US_DEBUGP("Warning: Transferred only %d bytes\n", - act_len); - return US_BULK_TRANSFER_SHORT; - } - - US_DEBUGP("Transferred %d of %d bytes\n", act_len, len); - - return US_BULK_TRANSFER_GOOD; -} - -/* - * Note: direction must be set if command_len == 0. - */ - -static int sddr09_bulk_transport(struct us_data *us, - int direction, - unsigned char *data, - unsigned int len, - int use_sg) { - - int result = USB_STOR_TRANSPORT_GOOD; - int transferred = 0; - int i; - struct scatterlist *sg; - char string[64]; - - if (len==0) - return USB_STOR_TRANSPORT_GOOD; - - - /* transfer the data */ - - if (direction == SCSI_DATA_WRITE) { - - /* Debug-print the first 48 bytes of the write transfer */ - - if (!use_sg) { - strcpy(string, "wr: "); - for (i=0; i<len && i<48; i++) { - sprintf(string+strlen(string), "%02X ", - data[i]); - if ((i%16)==15) { - US_DEBUGP("%s\n", string); - strcpy(string, "wr: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - } - - - US_DEBUGP("SCM data %s transfer %d sg buffers %d\n", - ( direction==SCSI_DATA_READ ? "in" : "out"), - len, use_sg); - - if (!use_sg) - result = sddr09_raw_bulk(us, direction, data, len); - else { - sg = (struct scatterlist *)data; - for (i=0; i<use_sg && transferred<len; i++) { - result = sddr09_raw_bulk(us, direction, - page_address(sg[i].page) + sg[i].offset, - len-transferred > sg[i].length ? - sg[i].length : len-transferred); - if (result!=US_BULK_TRANSFER_GOOD) - break; - transferred += sg[i].length; - } - } - - if (direction == SCSI_DATA_READ) { - - /* Debug-print the first 48 bytes of the read transfer */ - - if (!use_sg) { - strcpy(string, "rd: "); - for (i=0; i<len && i<48; i++) { - sprintf(string+strlen(string), "%02X ", - data[i]); - if ((i%16)==15) { - US_DEBUGP("%s\n", string); - strcpy(string, "rd: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - } - - return result; -} - -int sddr09_read_data(struct us_data *us, - unsigned long address, - unsigned short sectors, - unsigned char *content, - int use_sg) { - - int result; - unsigned char command[12] = { - 0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra; - unsigned int lba; - unsigned int pba; - unsigned short page; - unsigned short pages; - unsigned char *buffer = NULL; - unsigned char *ptr; - struct scatterlist *sg = NULL; - int i; - int len; - int transferred; - - // If we're using scatter-gather, we have to create a new - // buffer to read all of the data in first, since a - // scatter-gather buffer could in theory start in the middle - // of a page, which would be bad. A developer who wants a - // challenge might want to write a limited-buffer - // version of this code. - - len = sectors*info->pagesize; - - if (use_sg) { - sg = (struct scatterlist *)content; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - ptr = buffer; - } else - ptr = content; - - // Figure out the initial LBA and page - - pba = address >> (info->pageshift + info->blockshift); - lba = info->pba_to_lba[pba]; - page = (address >> info->pageshift) & info->blockmask; - - // This could be made much more efficient by checking for - // contiguous LBA's. Another exercise left to the student. - - while (sectors>0) { - - pba = info->lba_to_pba[lba]; - - // Read as many sectors as possible in this block - - pages = info->blocksize - page; - if (pages > sectors) - pages = sectors; - - US_DEBUGP("Read %02X pages, from PBA %04X" - " (LBA %04X) page %02X\n", - pages, pba, lba, page); - - address = ( (pba << info->blockshift) + page ) << - info->pageshift; - - // Unlike in the documentation, the address is in - // words of 2 bytes. - - command[2] = MSB_of(address>>17); - command[3] = LSB_of(address>>17); - command[4] = MSB_of((address>>1)&0xFFFF); - command[5] = LSB_of((address>>1)&0xFFFF); - - command[10] = MSB_of(pages); - command[11] = LSB_of(pages); - - result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - command, - 12); - - US_DEBUGP("Result for send_control in read_data %d\n", - result); - - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - result = sddr09_bulk_transport(us, - SCSI_DATA_READ, ptr, - pages<<info->pageshift, 0); - - if (result != USB_STOR_TRANSPORT_GOOD) { - if (use_sg) - kfree(buffer); - return result; - } - - page = 0; - lba++; - sectors -= pages; - ptr += (pages << info->pageshift); - } - - if (use_sg) { - transferred = 0; - for (i=0; i<use_sg && transferred<len; i++) { - memcpy(page_address(sg[i].page) + sg[i].offset, buffer+transferred, - len-transferred > sg[i].length ? - sg[i].length : len-transferred); - transferred += sg[i].length; - } - kfree(buffer); - } - - return USB_STOR_TRANSPORT_GOOD; -} - -int sddr09_read_control(struct us_data *us, - unsigned long address, - unsigned short blocks, - unsigned char *content, - int use_sg) { - - // Unlike in the documentation, the last two bytes are the - // number of blocks, not sectors. - - int result; - unsigned char command[12] = { - 0xe8, 0x21, MSB_of(address>>16), - LSB_of(address>>16), MSB_of(address&0xFFFF), - LSB_of(address&0xFFFF), 0, 0, 0, 0, - MSB_of(blocks), LSB_of(blocks) - }; - - US_DEBUGP("Read control address %08lX blocks %04X\n", - address, blocks); - - result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - command, - 12); - - US_DEBUGP("Result for send_control in read_control %d\n", - result); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = sddr09_bulk_transport(us, - SCSI_DATA_READ, content, - blocks<<6, use_sg); // 0x40 bytes per block - - US_DEBUGP("Result for bulk read in read_control %d\n", - result); - - return result; -} - -int sddr09_read_deviceID(struct us_data *us, - unsigned char *manufacturerID, - unsigned char *deviceID) { - - int result; - unsigned char command[12] = { - 0xed, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char content[64]; - - result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - command, - 12); - - US_DEBUGP("Result of send_control for device ID is %d\n", - result); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = sddr09_bulk_transport(us, - SCSI_DATA_READ, content, - 64, 0); - - *manufacturerID = content[0]; - *deviceID = content[1]; - - return result; -} - -int sddr09_read_status(struct us_data *us, - unsigned char *status) { - - int result; - unsigned char command[12] = { - 0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - command, - 12); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = sddr09_bulk_transport(us, - SCSI_DATA_READ, status, - 1, 0); - - return result; -} - -int sddr09_reset(struct us_data *us) { - - int result; - unsigned char command[12] = { - 0xeb, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - command, - 12); - - return result; -} - -unsigned long sddr09_get_capacity(struct us_data *us, - unsigned int *pagesize, unsigned int *blocksize) { - - unsigned char manufacturerID; - unsigned char deviceID; - int result; - - US_DEBUGP("Reading capacity...\n"); - - result = sddr09_read_deviceID(us, - &manufacturerID, - &deviceID); - - US_DEBUGP("Result of read_deviceID is %d\n", - result); - - if (result != USB_STOR_TRANSPORT_GOOD) - return 0; - - US_DEBUGP("Device ID = %02X\n", deviceID); - US_DEBUGP("Manuf ID = %02X\n", manufacturerID); - - *pagesize = 512; - *blocksize = 16; - - switch (deviceID) { - - case 0x6e: // 1MB - case 0xe8: - case 0xec: - *pagesize = 256; - return 0x00100000; - - case 0xea: // 2MB - case 0x5d: // 5d is a ROM card with pagesize 512. - case 0x64: - if (deviceID!=0x5D) - *pagesize = 256; - return 0x00200000; - - case 0xe3: // 4MB - case 0xe5: - case 0x6b: - case 0xd5: - return 0x00400000; - - case 0xe6: // 8MB - case 0xd6: - return 0x00800000; - - case 0x73: // 16MB - *blocksize = 32; - return 0x01000000; - - case 0x75: // 32MB - *blocksize = 32; - return 0x02000000; - - case 0x76: // 64MB - *blocksize = 32; - return 0x04000000; - - case 0x79: // 128MB - *blocksize = 32; - return 0x08000000; - - default: // unknown - return 0; - - } -} - -int sddr09_read_map(struct us_data *us) { - - struct scatterlist *sg; - struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra); - int numblocks; - int i; - unsigned char *ptr; - unsigned short lba; - unsigned char parity; - unsigned char fast_parity[16] = { - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0 - }; - int result; - int alloc_len; - int alloc_blocks; - - if (!info->capacity) - return -1; - - // read 64 (1<<6) bytes for every block - // ( 1 << ( blockshift + pageshift ) bytes) - // of capacity: - // (1<<6)*capacity/(1<<(b+p)) = - // ((1<<6)*capacity)>>(b+p) = - // capacity>>(b+p-6) - - alloc_len = info->capacity >> - (info->blockshift + info->pageshift - 6); - - // Allocate a number of scatterlist structures according to - // the number of 128k blocks in the alloc_len. Adding 128k-1 - // and then dividing by 128k gives the correct number of blocks. - // 128k = 1<<17 - - alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; - sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), - GFP_NOIO); - if (sg == NULL) - return 0; - - for (i=0; i<alloc_blocks; i++) { - if (i<alloc_blocks-1) { - char *vaddr = kmalloc(1 << 17, GFP_NOIO); - sg[i].page = virt_to_page(vaddr); - sg[i].offset = ((unsigned long)vaddr & ~PAGE_MASK); - sg[i].length = (1<<17); - } else { - char *vaddr = kmalloc(alloc_len, GFP_NOIO); - sg[i].page = virt_to_page(vaddr); - sg[i].offset = ((unsigned long)vaddr & ~PAGE_MASK); - sg[i].length = alloc_len; - } - alloc_len -= sg[i].length; - } - - for (i=0; i<alloc_blocks; i++) - if (sg[i].page == NULL) { - for (i=0; i<alloc_blocks; i++) - if (sg[i].page != NULL) - kfree(page_address(sg[i].page) + sg[i].offset); - kfree(sg); - return 0; - } - - numblocks = info->capacity >> (info->blockshift + info->pageshift); - - if ( (result = sddr09_read_control(us, 0, numblocks, - (unsigned char *)sg, alloc_blocks)) != - USB_STOR_TRANSPORT_GOOD) { - for (i=0; i<alloc_blocks; i++) - kfree(page_address(sg[i].page) + sg[i].offset); - kfree(sg); - return -1; - } - - - - if (info->lba_to_pba) - kfree(info->lba_to_pba); - if (info->pba_to_lba) - kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - - if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { - if (info->lba_to_pba != NULL) - kfree(info->lba_to_pba); - if (info->pba_to_lba != NULL) - kfree(info->pba_to_lba); - info->lba_to_pba = NULL; - info->pba_to_lba = NULL; - for (i=0; i<alloc_blocks; i++) - kfree(page_address(sg[i].page) + sg[i].offset); - kfree(sg); - return 0; - } - - memset(info->lba_to_pba, 0, numblocks*sizeof(int)); - memset(info->pba_to_lba, 0, numblocks*sizeof(int)); - - // Each block is 64 bytes of control data, so block i is located in - // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) - - for (i=0; i<numblocks; i++) { - ptr = page_address(sg[i>>11].page)+sg[i>>11].offset+((i&0x7ff)<<6); - if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF || - ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF) { - US_DEBUGP("PBA %04X has no logical mapping: reserved area = " - "%02X%02X%02X%02X data status %02X block status %02X\n", - i, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - continue; - } - if ((ptr[6]>>4)!=0x01) { - US_DEBUGP("PBA %04X has invalid address field %02X%02X/%02X%02X\n", - i, ptr[6], ptr[7], ptr[11], ptr[12]); - continue; - } - - /* ensure even parity */ - - lba = short_pack(ptr[7], ptr[6]); - parity = 1; // the parity of 0x1000 - parity ^= fast_parity[lba & 0x000F]; - parity ^= fast_parity[(lba>>4) & 0x000F]; - parity ^= fast_parity[(lba>>8) & 0x000F]; - - if (parity) { /* bad parity bit */ - US_DEBUGP("Bad parity in LBA for block %04X\n", i); - continue; - } - - lba = (lba&0x07FF)>>1; - - /* Every 1024 physical blocks ("zone"), the LBA numbers - * go back to zero, but are within a higher - * block of LBA's. Also, there is a maximum of - * 1000 LBA's per zone. In other words, in PBA - * 1024-2047 you will find LBA 0-999 which are - * really LBA 1000-1999. Yes, this wastes 24 - * physical blocks per zone. Go figure. - */ - - lba += 1000*(i/0x400); - - if (lba>=numblocks) { - US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i); - continue; - } - - if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF)) - US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); - - info->pba_to_lba[i] = lba; - info->lba_to_pba[lba] = i; - } - - for (i=0; i<alloc_blocks; i++) - kfree(page_address(sg[i].page)+sg[i].offset); - kfree(sg); - return 0; -} - -/* -static int init_sddr09(struct us_data *us) { - - int result; - unsigned char data[14]; - unsigned char command[8] = { - 0xc1, 0x01, 0, 0, 0, 0, 0, 0 - }; - unsigned char command2[8] = { - 0x41, 0, 0, 0, 0, 0, 0, 0 - }; - unsigned char tur[12] = { - 0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0 - }; - - // What the hey is all this for? Doesn't seem to - // affect the device, so we won't do device inits. - - if ( (result = sddr09_send_control(us, command, data, 2)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]); - - command[1] = 0x08; - - if ( (result = sddr09_send_control(us, command, data, 2)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]); - - if ( (result = sddr09_send_control(us, command2, tur, 12)) != - USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("SDDR09: request sense failed\n"); - return result; - } - - if ( (result = sddr09_raw_bulk( - us, SCSI_DATA_READ, data, 14)) != - USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("SDDR09: request sense bulk in failed\n"); - return result; - } - - US_DEBUGP("SDDR09: request sense worked\n"); - - return result; -} -*/ - -void sddr09_card_info_destructor(void *extra) { - struct sddr09_card_info *info = (struct sddr09_card_info *)extra; - - if (!extra) - return; - - if (info->lba_to_pba) - kfree(info->lba_to_pba); - if (info->pba_to_lba) - kfree(info->pba_to_lba); -} - -/* - * Transport for the Sandisk SDDR-09 - */ -int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int result; - int i; - char string[64]; - unsigned char inquiry_response[36] = { - 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 - }; - unsigned char mode_page_01[16] = { // write-protected for now - 0x03, 0x00, 0x80, 0x00, - 0x01, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned char *ptr; - unsigned long capacity; - unsigned int lba; - unsigned int pba; - unsigned int page; - unsigned short pages; - struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra); - - if (!us->extra) { - us->extra = kmalloc( - sizeof(struct sddr09_card_info), GFP_NOIO); - if (!us->extra) - return USB_STOR_TRANSPORT_ERROR; - memset(us->extra, 0, sizeof(struct sddr09_card_info)); - us->extra_destructor = sddr09_card_info_destructor; - } - - ptr = (unsigned char *)srb->request_buffer; - - /* Dummy up a response for INQUIRY since SDDR09 doesn't - respond to INQUIRY commands */ - - if (srb->cmnd[0] == INQUIRY) { - memset(inquiry_response+8, 0, 28); - fill_inquiry_response(us, inquiry_response, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - - capacity = sddr09_get_capacity(us, &info->pagesize, - &info->blocksize); - - if (!capacity) - return USB_STOR_TRANSPORT_FAILED; - - info->capacity = capacity; - for (info->pageshift=1; - (info->pagesize>>info->pageshift); - info->pageshift++); - info->pageshift--; - for (info->blockshift=1; - (info->blocksize>>info->blockshift); - info->blockshift++); - info->blockshift--; - info->blockmask = (1<<info->blockshift)-1; - - // Last page in the card - - capacity /= info->pagesize; - capacity--; - - ptr[0] = MSB_of(capacity>>16); - ptr[1] = LSB_of(capacity>>16); - ptr[2] = MSB_of(capacity&0xFFFF); - ptr[3] = LSB_of(capacity&0xFFFF); - - // The page size - - ptr[4] = MSB_of(info->pagesize>>16); - ptr[5] = LSB_of(info->pagesize>>16); - ptr[6] = MSB_of(info->pagesize&0xFFFF); - ptr[7] = LSB_of(info->pagesize&0xFFFF); - - sddr09_read_map(us); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE) { - - // Read-write error recovery page: there needs to - // be a check for write-protect here - - if ( (srb->cmnd[2] & 0x3F) == 0x01 ) { - - US_DEBUGP( - "SDDR09: Dummy up request for mode page 1\n"); - - if (ptr==NULL || - srb->request_bufflen<sizeof(mode_page_01)) - return USB_STOR_TRANSPORT_ERROR; - - memcpy(ptr, mode_page_01, sizeof(mode_page_01)); - return USB_STOR_TRANSPORT_GOOD; - - } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) { - - US_DEBUGP( - "SDDR09: Dummy up request for all mode pages\n"); - - if (ptr==NULL || - srb->request_bufflen<sizeof(mode_page_01)) - return USB_STOR_TRANSPORT_ERROR; - - memcpy(ptr, mode_page_01, sizeof(mode_page_01)); - return USB_STOR_TRANSPORT_GOOD; - - } - - // FIXME: sense buffer? - - return USB_STOR_TRANSPORT_ERROR; - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - - US_DEBUGP( - "SDDR09: %s medium removal. Not that I can do" - " anything about it...\n", - (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); - - return USB_STOR_TRANSPORT_GOOD; - - } - - if (srb->cmnd[0] == READ_10) { - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - // convert page to block and page-within-block - - lba = page >> info->blockshift; - page = page & info->blockmask; - - // locate physical block corresponding to logical block - - if (lba >= - (info->capacity >> - (info->pageshift + info->blockshift) ) ) { - - US_DEBUGP("Error: Requested LBA %04X exceeds maximum " - "block %04lX\n", lba, - (info->capacity >> (info->pageshift + info->blockshift))-1); - - // FIXME: sense buffer? - - return USB_STOR_TRANSPORT_ERROR; - } - - pba = info->lba_to_pba[lba]; - - // if pba is 0, either it's really 0, in which case - // the pba-to-lba map for pba 0 will be the lba, - // or that lba doesn't exist. - - if (pba==0 && info->pba_to_lba[0] != lba) { - - // FIXME: sense buffer? - - US_DEBUGP("Error: Requested LBA %04X has no physical block " - "mapping.\n", lba); - - return USB_STOR_TRANSPORT_ERROR; - } - - US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X" - " pages %d\n", - pba, lba, page, pages); - - return sddr09_read_data(us, - ( (pba << info->blockshift) + page) << info->pageshift, - pages, ptr, srb->use_sg); - } - - // Pass TEST_UNIT_READY and REQUEST_SENSE through - - if (srb->cmnd[0] != TEST_UNIT_READY && - srb->cmnd[0] != REQUEST_SENSE) - return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer? - - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - srb->cmnd[1] = 0x20; - - string[0] = 0; - for (i=0; i<12; i++) - sprintf(string+strlen(string), "%02X ", srb->cmnd[i]); - - US_DEBUGP("SDDR09: Send control for command %s\n", - string); - - if ( (result = sddr09_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0, - 0x41, - 0, - 0, - srb->cmnd, - 12)) != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("SDDR09: Control for command OK\n"); - - if (srb->request_bufflen == 0) - return USB_STOR_TRANSPORT_GOOD; - - if (srb->sc_data_direction == SCSI_DATA_WRITE || - srb->sc_data_direction == SCSI_DATA_READ) { - - US_DEBUGP("SDDR09: %s %d bytes\n", - srb->sc_data_direction==SCSI_DATA_WRITE ? - "sending" : "receiving", - srb->request_bufflen); - - result = sddr09_bulk_transport(us, - srb->sc_data_direction, - srb->request_buffer, - srb->request_bufflen, srb->use_sg); - - return result; - - } - - return USB_STOR_TRANSPORT_GOOD; -} - diff --git a/drivers/usb/class/storage/sddr09.h b/drivers/usb/class/storage/sddr09.h deleted file mode 100644 index ac984469f157..000000000000 --- a/drivers/usb/class/storage/sddr09.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Driver for SanDisk SDDR-09 SmartMedia reader - * Header File - * - * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 2000 Robert Baruch (autophile@dol.net) - * - * See sddr09.c for more explanation - * - * 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, 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. - */ - -#ifndef _USB_SHUTTLE_EUSB_SDDR09_H -#define _USB_SHUTTLE_EUSB_SDDR09_H - -/* Sandisk SDDR-09 stuff */ - -extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us); - -struct sddr09_card_info { - unsigned long capacity; /* Size of card in bytes */ - int pagesize; /* Size of page in bytes */ - int pageshift; /* log2 of pagesize */ - int blocksize; /* Size of block in pages */ - int blockshift; /* log2 of blocksize */ - int blockmask; /* 2^blockshift - 1 */ - int *lba_to_pba; /* logical to physical map */ - int *pba_to_lba; /* physical to logical map */ -}; - -#endif diff --git a/drivers/usb/class/storage/shuttle_usbat.c b/drivers/usb/class/storage/shuttle_usbat.c deleted file mode 100644 index 9770f9103210..000000000000 --- a/drivers/usb/class/storage/shuttle_usbat.c +++ /dev/null @@ -1,1083 +0,0 @@ -/* Driver for SCM Microsystems USB-ATAPI cable - * - * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 2000, 2001 Robert Baruch (autophile@starband.net) - * - * Many originally ATAPI devices were slightly modified to meet the USB - * market by using some kind of translation from ATAPI to USB on the host, - * and the peripheral would translate from USB back to ATAPI. - * - * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, - * which does the USB-to-ATAPI conversion. By obtaining the data sheet on - * their device under nondisclosure agreement, I have been able to write - * this driver for Linux. - * - * The chip used in the device can also be used for EPP and ISA translation - * as well. This driver is only guaranteed to work with the ATAPI - * translation. - * - * The only peripheral that I know of (as of 27 Mar 2001) that uses this - * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus. - * - * 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, 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 "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" -#include "shuttle_usbat.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> - -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - -#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) - -int transferred = 0; - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - */ - -static int usbat_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned short value, - unsigned short index, - unsigned char *xfer_data, - unsigned int xfer_len) { - - int result; - - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, value, index, - xfer_data, xfer_len); - - - // Check the return code for the command. - - if (result < 0) { - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* a stall is a fatal condition from the device */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int usbat_raw_bulk(struct us_data *us, - int direction, - unsigned char *data, - unsigned short len) { - - int result; - int act_len; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("EPIPE: clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", - pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); - } - - if (result) { - - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usbat_raw_bulk():" - " device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usbat_raw_bulk():" - " transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - if (result == -EPIPE) { - US_DEBUGP("usbat_raw_bulk():" - " output pipe stalled\n"); - return US_BULK_TRANSFER_SHORT; - } - - /* the catch-all case */ - US_DEBUGP("us_transfer_partial(): unknown error\n"); - return US_BULK_TRANSFER_FAILED; - } - - if (act_len != len) { - US_DEBUGP("Warning: Transferred only %d bytes\n", - act_len); - return US_BULK_TRANSFER_SHORT; - } - - US_DEBUGP("Transferred %s %d of %d bytes\n", - direction==SCSI_DATA_READ ? "in" : "out", act_len, len); - - return US_BULK_TRANSFER_GOOD; -} - -/* - * Note: direction must be set if command_len == 0. - */ - -static int usbat_bulk_transport(struct us_data *us, - unsigned char *command, - unsigned short command_len, - int direction, - unsigned char *data, - unsigned short len, - int use_sg) { - - int result = USB_STOR_TRANSPORT_GOOD; - int transferred = 0; - int i; - struct scatterlist *sg; - - if (len==0) - return USB_STOR_TRANSPORT_GOOD; - - /* transfer the data payload for the command, if there is any */ - - if (command_len != 0) - direction = (command[0]&0x80) ? SCSI_DATA_READ : - SCSI_DATA_WRITE; - - if (!use_sg) - result = usbat_raw_bulk(us, direction, data, len); - else { - sg = (struct scatterlist *)data; - for (i=0; i<use_sg && transferred<len; i++) { - result = usbat_raw_bulk(us, direction, - page_address(sg[i].page) + sg[i].offset, - len-transferred > sg[i].length ? - sg[i].length : len-transferred); - if (result!=US_BULK_TRANSFER_GOOD) - break; - transferred += sg[i].length; - } - } - - return result; -} - -int usbat_read(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char *content) { - - int result; - - result = usbat_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), - access, - 0xC0, - (u16)reg, - 0, - content, - 1); - - return result; -} - -int usbat_write(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char content) { - - int result; - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - access|0x01, - 0x40, - short_pack(reg, content), - 0, - NULL, - 0); - - return result; -} - -int usbat_set_shuttle_features(struct us_data *us, - unsigned char external_trigger, - unsigned char epp_control, - unsigned char mask_byte, - unsigned char test_pattern, - unsigned char subcountH, - unsigned char subcountL) { - - int result; - unsigned char command[8] = { - 0x40, 0x81, epp_control, external_trigger, - test_pattern, mask_byte, subcountL, subcountH - }; - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x80, - 0x40, - 0, - 0, - command, - 8); - - return result; -} - -int usbat_read_block(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char *content, - unsigned short len, - int use_sg) { - - int result; - unsigned char command[8] = { - 0xC0, access|0x02, reg, 0x00, 0x00, 0x00, - LSB_of(len), MSB_of(len) - }; - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x80, - 0x40, - 0, - 0, - command, - 8); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_READ, content, len, use_sg); - - return result; -} - -/* - * Block, waiting for an ATA device to become not busy or to report - * an error condition. - */ - -int usbat_wait_not_busy(struct us_data *us, int minutes) { - - int i; - int result; - unsigned char status; - - /* Synchronizing cache on a CDR could take a heck of a long time, - * but probably not more than 10 minutes or so. On the other hand, - * doing a full blank on a CDRW at speed 1 will take about 75 - * minutes! - */ - - for (i=0; i<1200+minutes*60; i++) { - - result = usbat_read(us, USBAT_ATA, 0x17, &status); - - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; - if (status&0x01) { // check condition - result = usbat_read(us, USBAT_ATA, 0x10, &status); - return USB_STOR_TRANSPORT_FAILED; - } - if (status&0x20) // device fault - return USB_STOR_TRANSPORT_FAILED; - - if ((status&0x80)==0x00) { // not busy - US_DEBUGP("Waited not busy for %d steps\n", i); - return USB_STOR_TRANSPORT_GOOD; - } - - if (i<500) - wait_ms(10); // 5 seconds - else if (i<700) - wait_ms(50); // 10 seconds - else if (i<1200) - wait_ms(100); // 50 seconds - else - wait_ms(1000); // X minutes - } - - US_DEBUGP("Waited not busy for %d minutes, timing out.\n", - minutes); - return USB_STOR_TRANSPORT_FAILED; -} - -int usbat_write_block(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char *content, - unsigned short len, - int use_sg, - int minutes) { - - int result; - unsigned char command[8] = { - 0x40, access|0x03, reg, 0x00, 0x00, 0x00, - LSB_of(len), MSB_of(len) - }; - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x80, - 0x40, - 0, - 0, - command, - 8); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_WRITE, content, len, use_sg); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - return usbat_wait_not_busy(us, minutes); -} - -int usbat_rw_block_test(struct us_data *us, - unsigned char access, - unsigned char *registers, - unsigned char *data_out, - unsigned short num_registers, - unsigned char data_reg, - unsigned char status_reg, - unsigned char timeout, - unsigned char qualifier, - int direction, - unsigned char *content, - unsigned short len, - int use_sg, - int minutes) { - - int result; - - // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, - // but that's what came out of the trace every single time. - - unsigned char command[16] = { - 0x40, access|0x07, 0x07, 0x17, 0xfc, 0xe7, - LSB_of(num_registers*2), MSB_of(num_registers*2), - (direction==SCSI_DATA_WRITE ? 0x40 : 0xC0), - access|(direction==SCSI_DATA_WRITE ? 0x05 : 0x04), - data_reg, status_reg, - timeout, qualifier, LSB_of(len), MSB_of(len) - }; - - int i; - unsigned char data[num_registers*2]; - unsigned char status; - - for (i=0; i<num_registers; i++) { - data[i<<1] = registers[i]; - data[1+(i<<1)] = data_out[i]; - } - - for (i=0; i<20; i++) { - - /* - * The first time we send the full command, which consists - * of downloading the SCSI command followed by downloading - * the data via a write-and-test. Any other time we only - * send the command to download the data -- the SCSI command - * is still 'active' in some sense in the device. - * - * We're only going to try sending the data 10 times. After - * that, we just return a failure. - */ - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x80, - 0x40, - 0, - 0, - (i==0 ? command : command+8), - (i==0 ? 16 : 8)); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - if (i==0) { - - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_WRITE, - data, num_registers*2, 0); - - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; - - } - - - //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == SCSI_DATA_WRITE ? "out" : "in", - // len, use_sg); - - result = usbat_bulk_transport(us, - NULL, 0, direction, content, len, use_sg); - - /* - * If we get a stall on the bulk download, we'll retry - * the bulk download -- but not the SCSI command because - * in some sense the SCSI command is still 'active' and - * waiting for the data. Don't ask me why this should be; - * I'm only following what the Windoze driver did. - * - * Note that a stall for the test-and-read/write command means - * that the test failed. In this case we're testing to make - * sure that the device is error-free - * (i.e. bit 0 -- CHK -- of status is 0). The most likely - * hypothesis is that the USBAT chip somehow knows what - * the device will accept, but doesn't give the device any - * data until all data is received. Thus, the device would - * still be waiting for the first byte of data if a stall - * occurs, even if the stall implies that some data was - * transferred. - */ - - if (result == US_BULK_TRANSFER_SHORT) { - - /* - * If we're reading and we stalled, then clear - * the bulk output pipe only the first time. - */ - - if (direction==SCSI_DATA_READ && i==0) - usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, - us->ep_out)); - /* - * Read status: is the device angry, or just busy? - */ - - result = usbat_read(us, USBAT_ATA, - direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, - &status); - - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; - if (status&0x01) // check condition - return USB_STOR_TRANSPORT_FAILED; - if (status&0x20) // device fault - return USB_STOR_TRANSPORT_FAILED; - - US_DEBUGP("Redoing %s\n", - direction==SCSI_DATA_WRITE ? "write" : "read"); - - } else if (result != US_BULK_TRANSFER_GOOD) - return result; - else - return usbat_wait_not_busy(us, minutes); - - } - - US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); - - return USB_STOR_TRANSPORT_FAILED; -} - -/* - * Write data to multiple registers at once. Not meant for large - * transfers of data! - */ - -int usbat_multiple_write(struct us_data *us, - unsigned char access, - unsigned char *registers, - unsigned char *data_out, - unsigned short num_registers) { - - int result; - unsigned char data[num_registers*2]; - int i; - unsigned char command[8] = { - 0x40, access|0x07, 0x00, 0x00, 0x00, 0x00, - LSB_of(num_registers*2), MSB_of(num_registers*2) - }; - - for (i=0; i<num_registers; i++) { - data[i<<1] = registers[i]; - data[1+(i<<1)] = data_out[i]; - } - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x80, - 0x40, - 0, - 0, - command, - 8); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0); - - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; - - return usbat_wait_not_busy(us, 0); -} - -int usbat_read_user_io(struct us_data *us, - unsigned char *data_flags) { - - int result; - - result = usbat_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), - 0x82, - 0xC0, - 0, - 0, - data_flags, - 1); - - return result; -} - -int usbat_write_user_io(struct us_data *us, - unsigned char enable_flags, - unsigned char data_flags) { - - int result; - - result = usbat_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), - 0x82, - 0x40, - short_pack(enable_flags, data_flags), - 0, - NULL, - 0); - - return result; -} - -/* - * Squeeze a potentially huge (> 65535 byte) read10 command into - * a little ( <= 65535 byte) ATAPI pipe - */ - -int usbat_handle_read10(struct us_data *us, - unsigned char *registers, - unsigned char *data, - Scsi_Cmnd *srb) { - - int result = USB_STOR_TRANSPORT_GOOD; - unsigned char *buffer; - unsigned int len; - unsigned int sector; - unsigned int amount; - struct scatterlist *sg = NULL; - int sg_segment = 0; - int sg_offset = 0; - - US_DEBUGP("handle_read10: transfersize %d\n", - srb->transfersize); - - if (srb->request_bufflen < 0x10000) { - - result = usbat_rw_block_test(us, USBAT_ATA, - registers, data, 19, - 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, - srb->request_buffer, - srb->request_bufflen, srb->use_sg, 1); - - return result; - } - - /* - * Since we're requesting more data than we can handle in - * a single read command (max is 64k-1), we will perform - * multiple reads, but each read must be in multiples of - * a sector. Luckily the sector size is in srb->transfersize - * (see linux/drivers/scsi/sr.c). - */ - - if (data[7+0] == GPCMD_READ_CD) { - len = short_pack(data[7+9], data[7+8]); - len <<= 16; - len |= data[7+7]; - srb->transfersize = srb->request_bufflen/len; - } - - - len = (65535/srb->transfersize) * srb->transfersize; - US_DEBUGP("Max read is %d bytes\n", len); - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) // bloody hell! - return USB_STOR_TRANSPORT_FAILED; - sector = short_pack(data[7+3], data[7+2]); - sector <<= 16; - sector |= short_pack(data[7+5], data[7+4]); - transferred = 0; - - if (srb->use_sg) { - sg = (struct scatterlist *)srb->request_buffer; - sg_segment = 0; // for keeping track of where we are in - sg_offset = 0; // the scatter/gather list - } - - while (transferred != srb->request_bufflen) { - - if (len > srb->request_bufflen - transferred) - len = srb->request_bufflen - transferred; - - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) - - // Fix up the SCSI command sector and num sectors - - data[7+2] = MSB_of(sector>>16); // SCSI command sector - data[7+3] = LSB_of(sector>>16); - data[7+4] = MSB_of(sector&0xFFFF); - data[7+5] = LSB_of(sector&0xFFFF); - if (data[7+0] == GPCMD_READ_CD) - data[7+6] = 0; - data[7+7] = MSB_of(len / srb->transfersize); // SCSI command - data[7+8] = LSB_of(len / srb->transfersize); // num sectors - - result = usbat_rw_block_test(us, USBAT_ATA, - registers, data, 19, - 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, - buffer, - len, 0, 1); - - if (result != USB_STOR_TRANSPORT_GOOD) - break; - - // Transfer the received data into the srb buffer - - if (!srb->use_sg) { - memcpy(srb->request_buffer+transferred, buffer, len); - } else { - amount = 0; - while (amount<len) { - if (len - amount >= - sg[sg_segment].length-sg_offset) { - memcpy(page_address(sg[sg_segment].page) + - sg[sg_segment].offset + sg_offset, - buffer + amount, - sg[sg_segment].length - sg_offset); - amount += - sg[sg_segment].length-sg_offset; - sg_segment++; - sg_offset=0; - } else { - memcpy(page_address(sg[sg_segment].page) + - sg[sg_segment].offset + sg_offset, - buffer + amount, - len - amount); - sg_offset += (len - amount); - amount = len; - } - } - } - - // Update the amount transferred and the sector number - - transferred += len; - sector += len / srb->transfersize; - - } // while transferred != srb->request_bufflen - - kfree(buffer); - return result; -} - -static int hp_8200e_select_and_test_registers(struct us_data *us) { - - int result; - int selector; - unsigned char status; - - // try device = master, then device = slave. - - for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { - - if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - } - - return result; -} - -int init_8200e(struct us_data *us) { - - int result; - unsigned char status; - - // Enable peripheral control signals - - if ( (result = usbat_write_user_io(us, - USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 1\n"); - - wait_ms(2000); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 2\n"); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 3\n"); - - // Reset peripheral, enable periph control signals - // (bring reset signal up) - - if ( (result = usbat_write_user_io(us, - USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 4\n"); - - // Enable periph control signals - // (bring reset signal down) - - if ( (result = usbat_write_user_io(us, - USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 5\n"); - - wait_ms(250); - - // Write 0x80 to ISA port 0x3F - - if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 6\n"); - - // Read ISA port 0x27 - - if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 7\n"); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 8\n"); - - if ( (result = hp_8200e_select_and_test_registers(us)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 9\n"); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 10\n"); - - // Enable periph control signals and card detect - - if ( (result = usbat_write_user_io(us, - USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 11\n"); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 12\n"); - - wait_ms(1400); - - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 13\n"); - - if ( (result = hp_8200e_select_and_test_registers(us)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 14\n"); - - if ( (result = usbat_set_shuttle_features(us, - 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("INIT 15\n"); - - return result; -} - -/* - * Transport for the HP 8200e - */ -int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int result; - unsigned char status; - unsigned char registers[32]; - unsigned char data[32]; - unsigned int len; - int i; - char string[64]; - - len = srb->request_bufflen; - - /* Send A0 (ATA PACKET COMMAND). - Note: I guess we're never going to get any of the ATA - commands... just ATA Packet Commands. - */ - - registers[0] = 0x11; - registers[1] = 0x12; - registers[2] = 0x13; - registers[3] = 0x14; - registers[4] = 0x15; - registers[5] = 0x16; - registers[6] = 0x17; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) - data[5] = 0xB0; // (device sel) = slave - data[6] = 0xA0; // (command) = ATA PACKET COMMAND - - for (i=7; i<19; i++) { - registers[i] = 0x10; - data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; - } - - result = usbat_read(us, USBAT_ATA, 0x17, &status); - US_DEBUGP("Status = %02X\n", status); - - if (srb->cmnd[0] == TEST_UNIT_READY) - transferred = 0; - - if (srb->sc_data_direction == SCSI_DATA_WRITE) { - - result = usbat_rw_block_test(us, USBAT_ATA, - registers, data, 19, - 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_WRITE, - srb->request_buffer, - len, srb->use_sg, 10); - - if (result == USB_STOR_TRANSPORT_GOOD) { - transferred += len; - US_DEBUGP("Wrote %08X bytes\n", transferred); - } - - return result; - - } else if (srb->cmnd[0] == READ_10 || - srb->cmnd[0] == GPCMD_READ_CD) { - - return usbat_handle_read10(us, registers, data, srb); - - } - - if (len > 0xFFFF) { - US_DEBUGP("Error: len = %08X... what do I do now?\n", - len); - return USB_STOR_TRANSPORT_ERROR; - } - - if ( (result = usbat_multiple_write(us, - USBAT_ATA, - registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) { - return result; - } - - // Write the 12-byte command header. - - // If the command is BLANK then set the timer for 75 minutes. - // Otherwise set it for 10 minutes. - - // NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW - // AT SPEED 4 IS UNRELIABLE!!! - - if ( (result = usbat_write_block(us, - USBAT_ATA, 0x10, srb->cmnd, 12, 0, - srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) != - USB_STOR_TRANSPORT_GOOD) { - return result; - } - - // If there is response data to be read in - // then do it here. - - if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) { - - // How many bytes to read in? Check cylL register - - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; - } - - if (len>0xFF) { // need to read cylH also - len = status; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, - &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; - } - len += ((unsigned int)status)<<8; - } - else - len = status; - - - result = usbat_read_block(us, USBAT_ATA, 0x10, - srb->request_buffer, len, srb->use_sg); - - /* Debug-print the first 32 bytes of the transfer */ - - if (!srb->use_sg) { - string[0] = 0; - for (i=0; i<len && i<32; i++) { - sprintf(string+strlen(string), "%02X ", - ((unsigned char *)srb->request_buffer)[i]); - if ((i%16)==15) { - US_DEBUGP("%s\n", string); - string[0] = 0; - } - } - if (string[0]!=0) - US_DEBUGP("%s\n", string); - } - } - - return result; -} - - diff --git a/drivers/usb/class/storage/shuttle_usbat.h b/drivers/usb/class/storage/shuttle_usbat.h deleted file mode 100644 index ad5078f16aa7..000000000000 --- a/drivers/usb/class/storage/shuttle_usbat.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Driver for SCM Microsystems USB-ATAPI cable - * Header File - * - * $Id: shuttle_usbat.h,v 1.5 2000/09/17 14:44:52 groovyjava Exp $ - * - * Current development and maintenance by: - * (c) 2000 Robert Baruch (autophile@dol.net) - * - * See scm.c for more explanation - * - * 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, 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. - */ - -#ifndef _USB_SHUTTLE_USBAT_H -#define _USB_SHUTTLE_USBAT_H - -#define USBAT_EPP_PORT 0x10 -#define USBAT_EPP_REGISTER 0x30 -#define USBAT_ATA 0x40 -#define USBAT_ISA 0x50 - -/* SCM User I/O Data registers */ - -#define USBAT_UIO_EPAD 0x80 // Enable Peripheral Control Signals -#define USBAT_UIO_CDT 0x40 // Card Detect (Read Only) - // CDT = ACKD & !UI1 & !UI0 -#define USBAT_UIO_1 0x20 // I/O 1 -#define USBAT_UIO_0 0x10 // I/O 0 -#define USBAT_UIO_EPP_ATA 0x08 // 1=EPP mode, 0=ATA mode -#define USBAT_UIO_UI1 0x04 // Input 1 -#define USBAT_UIO_UI0 0x02 // Input 0 -#define USBAT_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP) - -/* SCM User I/O Enable registers */ - -#define USBAT_UIO_DRVRST 0x80 // Reset Peripheral -#define USBAT_UIO_ACKD 0x40 // Enable Card Detect -#define USBAT_UIO_OE1 0x20 // I/O 1 set=output/clr=input - // If ACKD=1, set OE1 to 1 also. -#define USBAT_UIO_OE0 0x10 // I/O 0 set=output/clr=input -#define USBAT_UIO_ADPRST 0x01 // Reset SCM chip - -/* USBAT-specific commands */ - -extern int usbat_read(struct us_data *us, unsigned char access, - unsigned char reg, unsigned char *content); -extern int usbat_write(struct us_data *us, unsigned char access, - unsigned char reg, unsigned char content); -extern int usbat_read_block(struct us_data *us, unsigned char access, - unsigned char reg, unsigned char *content, unsigned short len, - int use_sg); -extern int usbat_write_block(struct us_data *us, unsigned char access, - unsigned char reg, unsigned char *content, unsigned short len, - int use_sg, int minutes); -extern int usbat_multiple_write(struct us_data *us, unsigned char access, - unsigned char *registers, unsigned char *data_out, - unsigned short num_registers); -extern int usbat_read_user_io(struct us_data *us, unsigned char *data_flags); -extern int usbat_write_user_io(struct us_data *us, - unsigned char enable_flags, unsigned char data_flags); - -/* HP 8200e stuff */ - -extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us); -extern int init_8200e(struct us_data *us); - -#endif diff --git a/drivers/usb/class/storage/transport.c b/drivers/usb/class/storage/transport.c deleted file mode 100644 index 04ba81c47102..000000000000 --- a/drivers/usb/class/storage/transport.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "transport.h" -#include "protocol.h" -#include "usb.h" -#include "debug.h" - -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/slab.h> - -/*********************************************************************** - * Helper routines - ***********************************************************************/ - -/* Calculate the length of the data transfer (not the command) for any - * given SCSI command - */ -unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) -{ - int i; - int doDefault = 0; - unsigned int len = 0; - unsigned int total = 0; - struct scatterlist *sg; - - /* This table tells us: - X = command not supported - L = return length in cmnd[4] (8 bits). - M = return length in cmnd[8] (8 bits). - G = return length in cmnd[3] and cmnd[4] (16 bits) - H = return length in cmnd[7] and cmnd[8] (16 bits) - I = return length in cmnd[8] and cmnd[9] (16 bits) - C = return length in cmnd[2] to cmnd[5] (32 bits) - D = return length in cmnd[6] to cmnd[9] (32 bits) - B = return length in blocksize so we use buff_len - R = return length in cmnd[2] to cmnd[4] (24 bits) - S = return length in cmnd[3] to cmnd[5] (24 bits) - T = return length in cmnd[6] to cmnd[8] (24 bits) - U = return length in cmnd[7] to cmnd[9] (24 bits) - 0-9 = fixed return length - V = 20 bytes - W = 24 bytes - Z = return length is mode dependant or not in command, use buff_len - */ - - static char *lengths = - - /* 0123456789ABCDEF 0123456789ABCDEF */ - - "00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */ - "XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */ - "M0HHB0X000H0HH0X" "XHH0HHXX0TH0H0XX" /* 40-5F */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */ - "X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ - "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ - - /* Commands checked in table: - - CHANGE_DEFINITION 40 - COMPARE 39 - COPY 18 - COPY_AND_VERIFY 3a - ERASE 19 - ERASE_10 2c - ERASE_12 ac - EXCHANGE_MEDIUM a6 - FORMAT_UNIT 04 - GET_DATA_BUFFER_STATUS 34 - GET_MESSAGE_10 28 - GET_MESSAGE_12 a8 - GET_WINDOW 25 !!! Has more data than READ_CAPACITY, need to fix table - INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len - INQUIRY 12 - LOAD_UNLOAD 1b - LOCATE 2b - LOCK_UNLOCK_CACHE 36 - LOG_SELECT 4c - LOG_SENSE 4d - MEDIUM_SCAN 38 !!! This was M - MODE_SELECT6 15 - MODE_SELECT_10 55 - MODE_SENSE_6 1a - MODE_SENSE_10 5a - MOVE_MEDIUM a5 - OBJECT_POSITION 31 !!! Same as SEARCH_DATA_EQUAL - PAUSE_RESUME 4b - PLAY_AUDIO_10 45 - PLAY_AUDIO_12 a5 - PLAY_AUDIO_MSF 47 - PLAY_AUDIO_TRACK_INDEX 48 - PLAY_AUDIO_TRACK_RELATIVE_10 49 - PLAY_AUDIO_TRACK_RELATIVE_12 a9 - POSITION_TO_ELEMENT 2b - PRE-FETCH 34 - PREVENT_ALLOW_MEDIUM_REMOVAL 1e - PRINT 0a !!! Same as WRITE_6 but is always in bytes - READ_6 08 - READ_10 28 - READ_12 a8 - READ_BLOCK_LIMITS 05 - READ_BUFFER 3c - READ_CAPACITY 25 - READ_CDROM_CAPACITY 25 - READ_DEFECT_DATA 37 - READ_DEFECT_DATA_12 b7 - READ_ELEMENT_STATUS b8 !!! Think this is in bytes - READ_GENERATION 29 !!! Could also be M? - READ_HEADER 44 !!! This was L - READ_LONG 3e - READ_POSITION 34 !!! This should be V but conflicts with PRE-FETCH - READ_REVERSE 0f - READ_SUB-CHANNEL 42 !!! Is this in bytes? - READ_TOC 43 !!! Is this in bytes? - READ_UPDATED_BLOCK 2d - REASSIGN_BLOCKS 07 - RECEIVE 08 !!! Same as READ_6 probably in bytes though - RECEIVE_DIAGNOSTIC_RESULTS 1c - RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes - RELEASE_UNIT 17 - REQUEST_SENSE 03 - REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes - RESERVE_UNIT 16 - REWIND 01 - REZERO_UNIT 01 - SCAN 1b !!! Conflicts with various commands, should be L - SEARCH_DATA_EQUAL 31 - SEARCH_DATA_EQUAL_12 b1 - SEARCH_DATA_LOW 30 - SEARCH_DATA_LOW_12 b0 - SEARCH_DATA_HIGH 32 - SEARCH_DATA_HIGH_12 b2 - SEEK_6 0b !!! Conflicts with SLEW_AND_PRINT - SEEK_10 2b - SEND 0a !!! Same as WRITE_6, probably in bytes though - SEND 2a !!! Similar to WRITE_10 but for scanners - SEND_DIAGNOSTIC 1d - SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes - SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes - SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes - SEND_OPC 54 - SEND_VOLUME_TAG b6 !!! Think this is in bytes - SET_LIMITS 33 - SET_LIMITS_12 b3 - SET_WINDOW 24 - SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6 - SPACE 11 - START_STOP_UNIT 1b - STOP_PRINT 1b - SYNCHRONIZE_BUFFER 10 - SYNCHRONIZE_CACHE 35 - TEST_UNIT_READY 00 - UPDATE_BLOCK 3d - VERIFY 13 - VERIFY 2f - VERIFY_12 af - WRITE_6 0a - WRITE_10 2a - WRITE_12 aa - WRITE_AND_VERIFY 2e - WRITE_AND_VERIFY_12 ae - WRITE_BUFFER 3b - WRITE_FILEMARKS 10 - WRITE_LONG 3f - WRITE_SAME 41 - */ - - if (srb->sc_data_direction == SCSI_DATA_WRITE) { - doDefault = 1; - } - else - switch (lengths[srb->cmnd[0]]) { - case 'L': - len = srb->cmnd[4]; - break; - - case 'M': - len = srb->cmnd[8]; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - len = lengths[srb->cmnd[0]]-'0'; - break; - - case 'G': - len = (((unsigned int)srb->cmnd[3])<<8) | - srb->cmnd[4]; - break; - - case 'H': - len = (((unsigned int)srb->cmnd[7])<<8) | - srb->cmnd[8]; - break; - - case 'I': - len = (((unsigned int)srb->cmnd[8])<<8) | - srb->cmnd[9]; - break; - - case 'R': - len = (((unsigned int)srb->cmnd[2])<<16) | - (((unsigned int)srb->cmnd[3])<<8) | - srb->cmnd[4]; - break; - - case 'S': - len = (((unsigned int)srb->cmnd[3])<<16) | - (((unsigned int)srb->cmnd[4])<<8) | - srb->cmnd[5]; - break; - - case 'T': - len = (((unsigned int)srb->cmnd[6])<<16) | - (((unsigned int)srb->cmnd[7])<<8) | - srb->cmnd[8]; - break; - - case 'U': - len = (((unsigned int)srb->cmnd[7])<<16) | - (((unsigned int)srb->cmnd[8])<<8) | - srb->cmnd[9]; - break; - - case 'C': - len = (((unsigned int)srb->cmnd[2])<<24) | - (((unsigned int)srb->cmnd[3])<<16) | - (((unsigned int)srb->cmnd[4])<<8) | - srb->cmnd[5]; - break; - - case 'D': - len = (((unsigned int)srb->cmnd[6])<<24) | - (((unsigned int)srb->cmnd[7])<<16) | - (((unsigned int)srb->cmnd[8])<<8) | - srb->cmnd[9]; - break; - - case 'V': - len = 20; - break; - - case 'W': - len = 24; - break; - - case 'B': - /* Use buffer size due to different block sizes */ - doDefault = 1; - break; - - case 'X': - US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n", - srb->cmnd[0]); - doDefault = 1; - break; - - case 'Z': - /* Use buffer size due to mode dependence */ - doDefault = 1; - break; - - default: - US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n", - srb->cmnd[0], lengths[srb->cmnd[0]] ); - doDefault = 1; - } - - if ( doDefault == 1 ) { - /* Are we going to scatter gather? */ - if (srb->use_sg) { - /* Add up the sizes of all the sg segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - len = total; - } - else - /* Just return the length of the buffer */ - len = srb->request_bufflen; - } - -return len; -} - -/* This is a version of usb_clear_halt() that doesn't read the status from - * the device -- this is because some devices crash their internal firmware - * when the status is requested after a halt - */ -int usb_stor_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, HZ * 3); - - /* this is a failure case */ - if (result < 0) - return result; - - /* reset the toggles and endpoint flags */ - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - - return 0; -} - -/*********************************************************************** - * Data transfer routines - ***********************************************************************/ - -/* This is the completion handler which will wake us up when an URB - * completes. - */ -static void usb_stor_blocking_completion(struct urb *urb) -{ - struct completion *urb_done_ptr = (struct completion *)urb->context; - - complete(urb_done_ptr); -} - -/* This is our function to emulate usb_control_msg() but give us enough - * access to make aborts/resets work - */ -int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size) -{ - struct completion urb_done; - int status; - struct usb_ctrlrequest *dr; - - /* allocate the device request structure */ - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); - if (!dr) - return -ENOMEM; - - /* fill in the structure */ - dr->bRequestType = requesttype; - dr->bRequest = request; - dr->wValue = cpu_to_le16(value); - dr->wIndex = cpu_to_le16(index); - dr->wLength = cpu_to_le16(size); - - /* set up data structures for the wakeup system */ - init_completion(&urb_done); - - /* lock the URB */ - down(&(us->current_urb_sem)); - - /* fill the URB */ - FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, - (unsigned char*) dr, data, size, - usb_stor_blocking_completion, &urb_done); - us->current_urb->actual_length = 0; - us->current_urb->error_count = 0; - us->current_urb->transfer_flags = USB_ASYNC_UNLINK; - - /* submit the URB */ - status = usb_submit_urb(us->current_urb, GFP_NOIO); - if (status) { - /* something went wrong */ - up(&(us->current_urb_sem)); - kfree(dr); - return status; - } - - /* wait for the completion of the URB */ - up(&(us->current_urb_sem)); - wait_for_completion(&urb_done); - down(&(us->current_urb_sem)); - - /* return the actual length of the data transferred if no error*/ - status = us->current_urb->status; - if (status >= 0) - status = us->current_urb->actual_length; - - /* release the lock and return status */ - up(&(us->current_urb_sem)); - kfree(dr); - return status; -} - -/* This is our function to emulate usb_bulk_msg() but give us enough - * access to make aborts/resets work - */ -int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len) -{ - struct completion urb_done; - int status; - - /* set up data structures for the wakeup system */ - init_completion(&urb_done); - - /* lock the URB */ - down(&(us->current_urb_sem)); - - /* fill the URB */ - FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, - usb_stor_blocking_completion, &urb_done); - us->current_urb->actual_length = 0; - us->current_urb->error_count = 0; - us->current_urb->transfer_flags = USB_ASYNC_UNLINK; - - /* submit the URB */ - status = usb_submit_urb(us->current_urb, GFP_NOIO); - if (status) { - /* something went wrong */ - up(&(us->current_urb_sem)); - return status; - } - - /* wait for the completion of the URB */ - up(&(us->current_urb_sem)); - wait_for_completion(&urb_done); - down(&(us->current_urb_sem)); - - /* return the actual length of the data transferred */ - *act_len = us->current_urb->actual_length; - - /* release the lock and return status */ - up(&(us->current_urb_sem)); - return us->current_urb->status; -} - -/* - * Transfer one SCSI scatter-gather buffer via bulk transfer - * - * Note that this function is necessary because we want the ability to - * use scatter-gather memory. Good performance is achieved by a combination - * of scatter-gather and clustering (which makes each chunk bigger). - * - * Note that the lower layer will always retry when a NAK occurs, up to the - * timeout limit. Thus we don't have to worry about it for individual - * packets. - */ -int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) -{ - int result; - int partial; - int pipe; - - /* calculate the appropriate pipe information */ - if (us->srb->sc_data_direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* transfer the data */ - US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); - result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); - US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", - result, partial, length); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - } - - /* did we send all the data? */ - if (partial == length) { - US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); - return US_BULK_TRANSFER_GOOD; - } - - /* uh oh... we have an error code, so something went wrong. */ - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } - - /* the catch-all case */ - US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* no error code, so we must have transferred some data, - * just not all of it */ - return US_BULK_TRANSFER_SHORT; -} - -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - page_address(sg[i].page) + sg[i].offset, sg[i].length); - total_transferred += sg[i].length; - } else - result = usb_stor_transfer_partial(us, - page_address(sg[i].page) + sg[i].offset, - transfer_amount - total_transferred); - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - -/* Invoke the transport and basic error-handling/recovery methods - * - * This is used by the protocol layers to actually send the message to - * the device and receive the response. - */ -void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int need_auto_sense; - int result; - - /* send the command to the transport layer */ - result = us->transport(srb, us); - - /* if the command gets aborted by the higher layers, we need to - * short-circuit all other processing - */ - if (result == USB_STOR_TRANSPORT_ABORTED) { - US_DEBUGP("-- transport indicates command was aborted\n"); - srb->result = DID_ABORT << 16; - return; - } - - /* Determine if we need to auto-sense - * - * I normally don't use a flag like this, but it's almost impossible - * to understand what's going on here if I don't. - */ - need_auto_sense = 0; - - /* - * If we're running the CB transport, which is incapable - * of determining status on it's own, we need to auto-sense almost - * every time. - */ - if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) { - US_DEBUGP("-- CB transport device requiring auto-sense\n"); - need_auto_sense = 1; - - /* There are some exceptions to this. Notably, if this is - * a UFI device and the command is REQUEST_SENSE or INQUIRY, - * then it is impossible to truly determine status. - */ - if (us->subclass == US_SC_UFI && - ((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY))) { - US_DEBUGP("** no auto-sense for a special command\n"); - need_auto_sense = 0; - } - } - - /* - * If we have an error, we're going to do a REQUEST_SENSE - * automatically. Note that we differentiate between a command - * "failure" and an "error" in the transport mechanism. - */ - if (result == USB_STOR_TRANSPORT_FAILED) { - US_DEBUGP("-- transport indicates command failure\n"); - need_auto_sense = 1; - } - if (result == USB_STOR_TRANSPORT_ERROR) { - us->transport_reset(us); - US_DEBUGP("-- transport indicates transport failure\n"); - need_auto_sense = 0; - srb->result = DID_ERROR << 16; - return; - } - - /* - * Also, if we have a short transfer on a command that can't have - * a short transfer, we're going to do this. - */ - if ((srb->result == US_BULK_TRANSFER_SHORT) && - !((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY) || - (srb->cmnd[0] == MODE_SENSE) || - (srb->cmnd[0] == LOG_SENSE) || - (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); - need_auto_sense = 1; - } - - /* Now, if we need to do the auto-sense, let's do it */ - if (need_auto_sense) { - int temp_result; - void* old_request_buffer; - unsigned short old_sg; - unsigned old_request_bufflen; - unsigned char old_sc_data_direction; - unsigned char old_cmnd[MAX_COMMAND_SIZE]; - - US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); - - /* save the old command */ - memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); - - /* set the command and the LUN */ - srb->cmnd[0] = REQUEST_SENSE; - srb->cmnd[1] = old_cmnd[1] & 0xE0; - srb->cmnd[2] = 0; - srb->cmnd[3] = 0; - srb->cmnd[4] = 18; - srb->cmnd[5] = 0; - - /* set the transfer direction */ - old_sc_data_direction = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_READ; - - /* use the new buffer we have */ - old_request_buffer = srb->request_buffer; - srb->request_buffer = srb->sense_buffer; - - /* set the buffer length for transfer */ - old_request_bufflen = srb->request_bufflen; - srb->request_bufflen = 18; - - /* set up for no scatter-gather use */ - old_sg = srb->use_sg; - srb->use_sg = 0; - - /* issue the auto-sense command */ - temp_result = us->transport(us->srb, us); - if (temp_result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("-- auto-sense failure\n"); - - /* we skip the reset if this happens to be a - * multi-target device, since failure of an - * auto-sense is perfectly valid - */ - if (!(us->flags & US_FL_SCM_MULT_TARG)) { - us->transport_reset(us); - } - srb->result = DID_ERROR << 16; - return; - } - - US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - srb->sense_buffer[0], - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); -#ifdef CONFIG_USB_STORAGE_DEBUG - usb_stor_show_sense( - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); -#endif - - /* set the result so the higher layers expect this data */ - srb->result = CHECK_CONDITION << 1; - - /* we're done here, let's clean up */ - srb->request_buffer = old_request_buffer; - srb->request_bufflen = old_request_bufflen; - srb->use_sg = old_sg; - srb->sc_data_direction = old_sc_data_direction; - memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - - /* If things are really okay, then let's show that */ - if ((srb->sense_buffer[2] & 0xf) == 0x0) - srb->result = GOOD << 1; - } else /* if (need_auto_sense) */ - srb->result = GOOD << 1; - - /* Regardless of auto-sense, if we _know_ we have an error - * condition, show that in the result code - */ - if (result == USB_STOR_TRANSPORT_FAILED) - srb->result = CHECK_CONDITION << 1; - - /* If we think we're good, then make sure the sense data shows it. - * This is necessary because the auto-sense for some devices always - * sets byte 0 == 0x70, even if there is no error - */ - if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && - (result == USB_STOR_TRANSPORT_GOOD) && - ((srb->sense_buffer[2] & 0xf) == 0x0)) - srb->sense_buffer[0] = 0x0; -} - -/* - * Control/Bulk/Interrupt transport - */ - -/* The interrupt handler for CBI devices */ -void usb_stor_CBI_irq(struct urb *urb) -{ - struct us_data *us = (struct us_data *)urb->context; - - US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no); - US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); - US_DEBUGP("-- IRQ state is %d\n", urb->status); - US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", - us->irqbuf[0], us->irqbuf[1]); - - /* reject improper IRQs */ - if (urb->actual_length != 2) { - US_DEBUGP("-- IRQ too short\n"); - return; - } - - /* is the device removed? */ - if (urb->status == -ENOENT) { - US_DEBUGP("-- device has been removed\n"); - return; - } - - /* was this a command-completion interrupt? */ - if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) { - US_DEBUGP("-- not a command-completion IRQ\n"); - return; - } - - /* was this a wanted interrupt? */ - if (!atomic_read(us->ip_wanted)) { - US_DEBUGP("ERROR: Unwanted interrupt received!\n"); - return; - } - - /* adjust the flag */ - atomic_set(us->ip_wanted, 0); - - /* copy the valid data */ - us->irqdata[0] = us->irqbuf[0]; - us->irqdata[1] = us->irqbuf[1]; - - /* wake up the command thread */ - US_DEBUGP("-- Current value of ip_waitq is: %d\n", - atomic_read(&us->ip_waitq.count)); - up(&(us->ip_waitq)); -} - -int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int result; - - /* Set up for status notification */ - atomic_set(us->ip_wanted, 1); - - /* re-initialize the mutex so that we avoid any races with - * early/late IRQs from previous commands */ - init_MUTEX_LOCKED(&(us->ip_waitq)); - - /* COMMAND STAGE */ - /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - us->ifnum, srb->cmnd, srb->cmd_len); - - /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* Reset flag for status notification */ - atomic_set(us->ip_wanted, 0); - - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* DATA STAGE */ - /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); - - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) { - return USB_STOR_TRANSPORT_ABORTED; - } - } - - /* STATUS STAGE */ - - /* go to sleep until we get this interrupt */ - US_DEBUGP("Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count)); - down(&(us->ip_waitq)); - - /* if we were woken up by an abort instead of the actual interrupt */ - if (atomic_read(us->ip_wanted)) { - US_DEBUGP("Did not get interrupt on CBI\n"); - atomic_set(us->ip_wanted, 0); - return USB_STOR_TRANSPORT_ABORTED; - } - - US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", - us->irqdata[0], us->irqdata[1]); - - /* UFI gives us ASC and ASCQ, like a request sense - * - * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI - * devices, so we ignore the information for those commands. Note - * that this means we could be ignoring a real error on these - * commands, but that can't be helped. - */ - if (us->subclass == US_SC_UFI) { - if (srb->cmnd[0] == REQUEST_SENSE || - srb->cmnd[0] == INQUIRY) - return USB_STOR_TRANSPORT_GOOD; - else - if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) - return USB_STOR_TRANSPORT_FAILED; - else - return USB_STOR_TRANSPORT_GOOD; - } - - /* If not UFI, we interpret the data as a result code - * The first byte should always be a 0x0 - * The second byte & 0x0F should be 0x0 for good, otherwise error - */ - if (us->irqdata[0]) { - US_DEBUGP("CBI IRQ data showed reserved bType %d\n", - us->irqdata[0]); - return USB_STOR_TRANSPORT_ERROR; - } - - switch (us->irqdata[1] & 0x0F) { - case 0x00: - return USB_STOR_TRANSPORT_GOOD; - case 0x01: - return USB_STOR_TRANSPORT_FAILED; - default: - return USB_STOR_TRANSPORT_ERROR; - } - - /* we should never get here, but if we do, we're in trouble */ - return USB_STOR_TRANSPORT_ERROR; -} - -/* - * Control/Bulk transport - */ -int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int result; - - /* COMMAND STAGE */ - /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - us->ifnum, srb->cmnd, srb->cmd_len); - - /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* a stall is a fatal condition from the device */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* DATA STAGE */ - /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - US_DEBUGP("CB data stage result is 0x%x\n", srb->result); - - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; - } - - /* STATUS STAGE */ - /* NOTE: CB does not have a status stage. Silly, I know. So - * we have to catch this at a higher level. - */ - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Bulk only transport - */ - -/* Determine what the maximum LUN supported is */ -int usb_stor_Bulk_max_lun(struct us_data *us) -{ - unsigned char data; - int result; - int pipe; - - /* issue the command */ - pipe = usb_rcvctrlpipe(us->pusb_dev, 0); - result = usb_control_msg(us->pusb_dev, pipe, - US_BULK_GET_MAX_LUN, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, - 0, us->ifnum, &data, sizeof(data), HZ); - - US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, data); - - /* if we have a successful request, return the result */ - if (result == 1) - return data; - - /* if we get a STALL, clear the stall */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - } - - /* return the default -- no LUNs */ - return 0; -} - -int usb_stor_Bulk_reset(struct us_data *us); - -int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - struct bulk_cb_wrap bcb; - struct bulk_cs_wrap bcs; - int result; - int pipe; - int partial; - - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - - /* set up the command wrapper */ - bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); - bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; - bcb.Tag = srb->serial_number; - bcb.Lun = srb->cmnd[1] >> 5; - if (us->flags & US_FL_SCM_MULT_TARG) - bcb.Lun |= srb->target << 4; - bcb.Length = srb->cmd_len; - - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* copy the command payload */ - memset(bcb.CDB, 0, sizeof(bcb.CDB)); - memcpy(bcb.CDB, srb->cmnd, bcb.Length); - - /* send it to out endpoint */ - US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", - le32_to_cpu(bcb.Signature), bcb.Tag, - (bcb.Lun >> 4), (bcb.Lun & 0x0F), - bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); - US_DEBUGP("Bulk command transfer result=%d\n", result); - - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - } else if (result) { - /* unknown error -- we've got a problem */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* if the command transfered well, then we go to the data stage */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - usb_stor_transfer(srb, us); - US_DEBUGP("Bulk data transfer result 0x%x\n", - srb->result); - - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; - } - } - - /* See flow chart on pg 15 of the Bulk Only Transport spec for - * an explanation of how this code works. - */ - - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - - /* get CSW for device status */ - US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); - - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* did the attempt to read the CSW fail? */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - - /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, - US_BULK_CS_WRAP_LEN, &partial); - - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - - /* if it fails again, we need a reset and return an error*/ - if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - return USB_STOR_TRANSPORT_ERROR; - } - } - - /* if we still have a failure at this point, we're in trouble */ - US_DEBUGP("Bulk status result = %d\n", result); - if (result) { - return USB_STOR_TRANSPORT_ERROR; - } - - /* check bulk status */ - US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", - le32_to_cpu(bcs.Signature), bcs.Tag, - bcs.Residue, bcs.Status); - if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || - bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { - US_DEBUGP("Bulk logical error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* based on the status code, we report good or bad */ - switch (bcs.Status) { - case US_BULK_STAT_OK: - /* command good -- note that data could be short */ - return USB_STOR_TRANSPORT_GOOD; - - case US_BULK_STAT_FAIL: - /* command failed */ - return USB_STOR_TRANSPORT_FAILED; - - case US_BULK_STAT_PHASE: - /* phase error -- note that a transport reset will be - * invoked by the invoke_transport() function - */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* we should never get here, but if we do, we're in trouble */ - return USB_STOR_TRANSPORT_ERROR; -} - -/*********************************************************************** - * Reset routines - ***********************************************************************/ - -/* This issues a CB[I] Reset to the device in question - */ -int usb_stor_CB_reset(struct us_data *us) -{ - unsigned char cmd[12]; - int result; - - US_DEBUGP("CB_reset() called\n"); - - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - - memset(cmd, 0xFF, sizeof(cmd)); - cmd[0] = SEND_DIAGNOSTIC; - cmd[1] = 4; - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, cmd, sizeof(cmd), HZ*5); - - if (result < 0) { - US_DEBUGP("CB[I] soft reset failed %d\n", result); - return FAILED; - } - - /* long wait for reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ*6); - set_current_state(TASK_RUNNING); - - US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); - - US_DEBUGP("CB_reset done\n"); - /* return a result code based on the result of the control message */ - return SUCCESS; -} - -/* This issues a Bulk-only Reset to the device in question, including - * clearing the subsequent endpoint halts that may occur. - */ -int usb_stor_Bulk_reset(struct us_data *us) -{ - int result; - - US_DEBUGP("Bulk reset requested\n"); - - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev,0), - US_BULK_RESET_REQUEST, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, NULL, 0, HZ*5); - - if (result < 0) { - US_DEBUGP("Bulk soft reset failed %d\n", result); - return FAILED; - } - - /* long wait for reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ*6); - set_current_state(TASK_RUNNING); - - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); - US_DEBUGP("Bulk soft reset completed\n"); - return SUCCESS; -} diff --git a/drivers/usb/class/storage/transport.h b/drivers/usb/class/storage/transport.h deleted file mode 100644 index 2dc2ac1a3e0a..000000000000 --- a/drivers/usb/class/storage/transport.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Transport Functions Header File - * - * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -#ifndef _TRANSPORT_H_ -#define _TRANSPORT_H_ - -#include <linux/config.h> -#include <linux/blk.h> -#include "usb.h" -#include "scsi.h" - -/* Protocols */ - -#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */ -#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */ -#define US_PR_BULK 0x50 /* bulk only */ -#ifdef CONFIG_USB_STORAGE_HP8200e -#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */ -#endif -#ifdef CONFIG_USB_STORAGE_SDDR09 -#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for - SDDR-09 */ -#endif -#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ - -#ifdef CONFIG_USB_STORAGE_FREECOM -#define US_PR_FREECOM 0xf1 /* Freecom */ -#endif - -#ifdef CONFIG_USB_STORAGE_DATAFAB -#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ -#endif - -#ifdef CONFIG_USB_STORAGE_JUMPSHOT -#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ -#endif - -/* - * Bulk only data structures - */ - -/* command block wrapper */ -struct bulk_cb_wrap { - __u32 Signature; /* contains 'USBC' */ - __u32 Tag; /* unique per command id */ - __u32 DataTransferLength; /* size of data */ - __u8 Flags; /* direction in bit 0 */ - __u8 Lun; /* LUN normally 0 */ - __u8 Length; /* of of the CDB */ - __u8 CDB[16]; /* max command */ -}; - -#define US_BULK_CB_WRAP_LEN 31 -#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */ -#define US_BULK_FLAG_IN 1 -#define US_BULK_FLAG_OUT 0 - -/* command status wrapper */ -struct bulk_cs_wrap { - __u32 Signature; /* should = 'USBS' */ - __u32 Tag; /* same as original command */ - __u32 Residue; /* amount not transferred */ - __u8 Status; /* see below */ - __u8 Filler[18]; -}; - -#define US_BULK_CS_WRAP_LEN 13 -#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ -#define US_BULK_STAT_OK 0 -#define US_BULK_STAT_FAIL 1 -#define US_BULK_STAT_PHASE 2 - -/* bulk-only class specific requests */ -#define US_BULK_RESET_REQUEST 0xff -#define US_BULK_GET_MAX_LUN 0xfe - -/* - * usb_stor_transfer() return codes - */ -#define US_BULK_TRANSFER_GOOD 0 /* good transfer */ -#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */ -#define US_BULK_TRANSFER_FAILED 2 /* transfer died in the middle */ -#define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */ - -/* - * Transport return codes - */ - -#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ -#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ -#define USB_STOR_TRANSPORT_ABORTED 3 /* Transport aborted */ - -/* - * CBI accept device specific command - */ - -#define US_CBI_ADSC 0 - -extern void usb_stor_CBI_irq(struct urb*); -extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*); - -extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_CB_reset(struct us_data*); - -extern int usb_stor_Bulk_transport(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_Bulk_max_lun(struct us_data*); -extern int usb_stor_Bulk_reset(struct us_data*); - -extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); -extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_transfer_partial(struct us_data*, char*, int); -extern int usb_stor_bulk_msg(struct us_data*, void*, int, unsigned int, - unsigned int*); -extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8, - u16, u16, void*, u16); -extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_clear_halt(struct usb_device*, int ); -#endif diff --git a/drivers/usb/class/storage/unusual_devs.h b/drivers/usb/class/storage/unusual_devs.h deleted file mode 100644 index 87ba0ccb0d30..000000000000 --- a/drivers/usb/class/storage/unusual_devs.h +++ /dev/null @@ -1,477 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Ununsual Devices File - * - * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -/* IMPORTANT NOTE: This file must be included in another file which does - * the following thing for it to work: - * The macro UNUSUAL_DEV() must be defined before this file is included - */ -#include <linux/config.h> - -/* If you edit this file, please try to keep it sorted first by VendorID, - * then by ProductID. - */ - -UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0), - -UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, - "Mitsumi", - "USB FDD", - US_SC_UFI, US_PR_CBI, NULL, - US_FL_SINGLE_LUN ), - -UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, - "HP", - "CD-Writer+", - US_SC_8070, US_PR_CB, NULL, 0), - -#ifdef CONFIG_USB_STORAGE_HP8200e -UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, - "HP", - "CD-Writer+ 8200e", - US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), - -UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, - "HP", - "CD-Writer+ CD-4e", - US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), -#endif - -#ifdef CONFIG_USB_STORAGE_DPCM -UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), -#endif - -/* Made with the help of Edd Dumbill <edd@usefulinc.com> */ -UNUSUAL_DEV( 0x0451, 0x5409, 0x0001, 0x0001, - "Frontier Labs", - "Nex II Digital", - US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), - -/* Reported by Paul Stewart <stewart@wetlogic.net> - * This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, - "Hitachi", - "DVD-CAM DZ-MV100A Camcorder", - US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, - "Fujifilm", - "FinePix 1400Zoom", - US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY), - -/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de> - * The device needs the flags only. - */ -UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, - "ScanLogic", - "SL11R-IDE", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY), - -/* Reported by Kriston Fincher <kriston@airmail.net> - * Patch submitted by Sean Millichamp <sean@bruenor.org> - * This is to support the Panasonic PalmCam PV-SD4090 - * This entry is needed because the device reports Sub=ff - */ -UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, - "Panasonic", - "LS-120 Camera", - US_SC_UFI, US_PR_CBI, NULL, 0), - -/* Most of the following entries were developed with the help of - * Shuttle/SCM directly. - */ -UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, - "Matshita", - "LS-120", - US_SC_8020, US_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -#ifdef CONFIG_USB_STORAGE_SDDR09 -UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR09", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), -#endif - -/* This entry is from Andries.Brouwer@cwi.nl */ -UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, - "SCM Microsystems", - "eUSB SmartMedia / CompactFlash Adapter", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP), - -UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0205, - "Shuttle", - "eUSB MMC Adapter", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200, - "Sony", - "Hifd", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200, - "Shuttle", - "eUSB ATA/ATAPI Adapter", - US_SC_8020, US_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200, - "Shuttle", - "eUSB CompactFlash Adapter", - US_SC_8020, US_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200, - "Shuttle", - "CD-RW Device", - US_SC_8020, US_PR_CB, NULL, 0), - -/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */ -UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, - "Belkin", - "USB SCSI Adaptor", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -/* Iomega Clik! Drive - * Reported by David Chatenay <dchatenay@hotmail.com> - * The reason this is needed is not fully known. - */ -UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, - "Iomega", - "USB Clik! 40", - US_SC_8070, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY | US_FL_START_STOP ), - -/* This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, - "Sony", - "DSC-S30/S70/S75/505V/F505", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), - -/* Reported by wim@geeks.nl */ -UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, - "Sony", - "Memorystick NW-MS7", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), - -UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, - "Sony", - "Memorystick MSAC-US1", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), - -/* Submitted by Klaus Mueller <k.mueller@intershop.de> */ -UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310, - "Sony", - "Handycam", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE), - -UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, - "Sony", - "Memorystick MSC-U01N", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), - -/* Submitted by Nathan Babb <nathan@lexi.com> */ -UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, - "Sony", - "PEG Mass Storage", - US_SC_8070, US_PR_CBI, NULL, - US_FL_FIX_INQUIRY ), - -UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, - "Y-E Data", - "Flashbuster-U", - US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999, - "Y-E Data", - "Flashbuster-U", - US_SC_UFI, US_PR_CBI, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, - "LaCie", - "USB Hard Disk", - US_SC_RBC, US_PR_CB, NULL, 0 ), - -#ifdef CONFIG_USB_STORAGE_ISD200 -UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, - "In-System", - "USB/IDE Bridge (ATA/ATAPI)", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), - -UNUSUAL_DEV( 0x05ab, 0x0301, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), - -UNUSUAL_DEV( 0x05ab, 0x0351, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), - -UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, - "In-System", - "USB Storage Adapter V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), - -UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110, - "Sony", - "Portable USB Harddrive V2", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), -#endif - -#ifdef CONFIG_USB_STORAGE_JUMPSHOT -UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, - "Lexar", - "Jumpshot USB CF Reader", - US_SC_SCSI, US_PR_JUMPSHOT, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), -#endif - -UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, - "TEAC", - "Floppy Drive", - US_SC_UFI, US_PR_CB, NULL, 0 ), - -#ifdef CONFIG_USB_STORAGE_SDDR09 -UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, - "Olympus", - "Camedia MAUSB-2", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), -#endif - -/* Submitted by f.brugmans@hccnet.nl - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - -UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, - "Hagiwara", - "FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), - -UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100, - "Hagiwara", - "Flashgate", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), - -UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, - "Sandisk", - "ImageMate SDDR-05a", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP), - -UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, - "Sandisk", - "ImageMate SDDR-31", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_IGNORE_SER), - -UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, - "Sandisk", - "ImageMate SDDR-12", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN ), - -#ifdef CONFIG_USB_STORAGE_SDDR09 -UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR-09", - US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), -#endif - -#ifdef CONFIG_USB_STORAGE_FREECOM -UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, - "Freecom", - "USB-IDE", - US_SC_QIC, US_PR_FREECOM, freecom_init, 0), -#endif - -UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, - "Microtech", - "USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, - "Microtech", - "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -#ifdef CONFIG_USB_STORAGE_DPCM -UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), -#endif - -#ifdef CONFIG_USB_STORAGE_DATAFAB -UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015, - "Datafab", - "MDCFE-B USB CF Reader", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - - /* - * The following Datafab-based devices may or may not work - * using the current driver...the 0xffff is arbitrary since I - * don't know what device versions exist for these guys. - * - * The 0xa003 and 0xa004 devices in particular I'm curious about. - * I'm told they exist but so far nobody has come forward to say that - * they work with this driver. Given the success we've had getting - * other Datafab-based cards operational with this driver, I've decided - * to leave these two devices in the list. - */ -UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff, - "SIIG/Datafab", - "SIIG/Datafab Memory Stick+CF Reader/Writer", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - -UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff, - "Datafab/Unknown", - "Datafab-based Reader", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - -UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff, - "Datafab/Unknown", - "Datafab-based Reader", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - -UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff, - "PNY/Datafab", - "PNY/Datafab CF+SM Reader", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - -UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff, - "Simple Tech/Datafab", - "Simple Tech/Datafab CF+SM Reader", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), - -/* Submitted by Olaf Hering <olh@suse.de> */ -UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, - "Datafab Systems, Inc.", - "USB to CF + SM Combo (LC1)", - US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), -#endif - -/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant - * to the USB storage specification in two ways: - * - They tell us they are using transport protocol CBI. In reality they - * are using transport protocol CB. - * - They don't like the INQUIRY command. So we must handle this command - * of the SCSI layer ourselves. - */ -UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, - "Casio", - "QV DigitalCamera", - US_SC_8070, US_PR_CB, NULL, - US_FL_FIX_INQUIRY ), - -UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001, - "Minds@Work", - "Digital Wallet", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_MODE_XLATE ), - -#ifdef CONFIG_USB_STORAGE_ISD200 -UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, - "ATI", - "USB Cable 205", - US_SC_ISD200, US_PR_BULK, isd200_Initialization, - 0 ), -#endif - -/* Submitted by Brian Hall <brihall@bigfoot.com> - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, - "JMTek", - "USBDrive", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - -/* Reported by Dan Pilone <pilone@slac.com> - * The device needs the flags only. - */ -UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, - "CCYU TECHNOLOGY", - "EasyDisk Portable Device", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP), diff --git a/drivers/usb/class/storage/usb.c b/drivers/usb/class/storage/usb.c deleted file mode 100644 index 277a322bc869..000000000000 --- a/drivers/usb/class/storage/usb.c +++ /dev/null @@ -1,1149 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * usb_device_id support by Adam J. Richter (adam@yggdrasil.com): - * (c) 2000 Yggdrasil Computing, Inc. - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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 "usb.h" -#include "scsiglue.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" -#include "initializers.h" - -#ifdef CONFIG_USB_STORAGE_HP8200e -#include "shuttle_usbat.h" -#endif -#ifdef CONFIG_USB_STORAGE_SDDR09 -#include "sddr09.h" -#endif -#ifdef CONFIG_USB_STORAGE_DPCM -#include "dpcm.h" -#endif -#ifdef CONFIG_USB_STORAGE_FREECOM -#include "freecom.h" -#endif -#ifdef CONFIG_USB_STORAGE_ISD200 -#include "isd200.h" -#endif -#ifdef CONFIG_USB_STORAGE_DATAFAB -#include "datafab.h" -#endif -#ifdef CONFIG_USB_STORAGE_JUMPSHOT -#include "jumpshot.h" -#endif - - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> - -/* Some informational data */ -MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); -MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); -MODULE_LICENSE("GPL"); - -/* - * Per device data - */ - -static int my_host_number; - -/* - * kernel thread actions - */ - -#define US_ACT_COMMAND 1 -#define US_ACT_DEVICE_RESET 2 -#define US_ACT_BUS_RESET 3 -#define US_ACT_HOST_RESET 4 -#define US_ACT_EXIT 5 - -/* The list of structures and the protective lock for them */ -struct us_data *us_list; -struct semaphore us_list_semaphore; - -static void * storage_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id); - -static void storage_disconnect(struct usb_device *dev, void *ptr); - -/* The entries in this table, except for final ones here - * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, - * line for line with the entries of us_unsuaul_dev_list[]. - * For now, we duplicate idVendor and idProduct in us_unsual_dev_list, - * just to avoid alignment bugs. - */ - -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName,useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) } - -static struct usb_device_id storage_usb_ids [] = { - -# include "unusual_devs.h" -#undef UNUSUAL_DEV - /* Control/Bulk transport for all SubClass values */ - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) }, - - /* Control/Bulk/Interrupt transport for all SubClass values */ - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) }, - - /* Bulk-only transport for all SubClass values */ - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, - - /* Terminating entry */ - { } -}; - -MODULE_DEVICE_TABLE (usb, storage_usb_ids); - -/* This is the list of devices we recognize, along with their flag data */ - -/* The vendor name should be kept at eight characters or less, and - * the product name should be kept at 16 characters or less. If a device - * has the US_FL_FIX_INQUIRY flag, then the vendor and product names - * normally generated by a device thorugh the INQUIRY response will be - * taken from this list, and this is the reason for the above size - * restriction. However, if the flag is not present, then you - * are free to use as many characters as you like. - */ - -#undef UNUSUAL_DEV -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - vendorName: vendor_name, \ - productName: product_name, \ - useProtocol: use_protocol, \ - useTransport: use_transport, \ - initFunction : init_function, \ - flags: Flags, \ -} - -static struct us_unusual_dev us_unusual_dev_list[] = { -# include "unusual_devs.h" -# undef UNUSUAL_DEV - /* Control/Bulk transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_CB}, - { useProtocol: US_SC_8020, - useTransport: US_PR_CB}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_CB}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_CB}, - { useProtocol: US_SC_8070, - useTransport: US_PR_CB}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_CB}, - - /* Control/Bulk/Interrupt transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_8020, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_8070, - useTransport: US_PR_CBI}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_CBI}, - - /* Bulk-only transport for all SubClass values */ - { useProtocol: US_SC_RBC, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_8020, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_QIC, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_UFI, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_8070, - useTransport: US_PR_BULK}, - { useProtocol: US_SC_SCSI, - useTransport: US_PR_BULK}, - - /* Terminating entry */ - { 0 } -}; - -struct usb_driver usb_storage_driver = { - name: "usb-storage", - probe: storage_probe, - disconnect: storage_disconnect, - id_table: storage_usb_ids, -}; - -/* - * fill_inquiry_response takes an unsigned char array (which must - * be at least 36 characters) and populates the vendor name, - * product name, and revision fields. Then the array is copied - * into the SCSI command's response buffer (oddly enough - * called request_buffer). data_len contains the length of the - * data array, which again must be at least 36. - */ - -void fill_inquiry_response(struct us_data *us, unsigned char *data, - unsigned int data_len) { - - int i; - struct scatterlist *sg; - int len = - us->srb->request_bufflen > data_len ? data_len : - us->srb->request_bufflen; - int transferred; - int amt; - - if (data_len<36) // You lose. - return; - - if(data[0]&0x20) { /* USB device currently not connected. Return - peripheral qualifier 001b ("...however, the - physical device is not currently connected - to this logical unit") and leave vendor and - product identification empty. ("If the target - does store some of the INQUIRY data on the - device, it may return zeros or ASCII spaces - (20h) in those fields until the data is - available from the device."). */ - memset(data+8,0,28); - } else { - memcpy(data+8, us->unusual_dev->vendorName, - strlen(us->unusual_dev->vendorName) > 8 ? 8 : - strlen(us->unusual_dev->vendorName)); - memcpy(data+16, us->unusual_dev->productName, - strlen(us->unusual_dev->productName) > 16 ? 16 : - strlen(us->unusual_dev->productName)); - data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F); - data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F); - data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F); - data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F); - } - - if (us->srb->use_sg) { - sg = (struct scatterlist *)us->srb->request_buffer; - for (i=0; i<us->srb->use_sg; i++) - memset(page_address(sg[i].page) + sg[i].offset, 0, sg[i].length); - for (i=0, transferred=0; - i<us->srb->use_sg && transferred < len; - i++) { - amt = sg[i].length > len-transferred ? - len-transferred : sg[i].length; - memcpy(page_address(sg[i].page) + sg[i].offset, data+transferred, amt); - transferred -= amt; - } - } else { - memset(us->srb->request_buffer, 0, us->srb->request_bufflen); - memcpy(us->srb->request_buffer, data, len); - } -} - -static int usb_stor_control_thread(void * __us) -{ - struct us_data *us = (struct us_data *)__us; - int action; - - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources.. - */ - daemonize(); - - /* avoid getting signals */ - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - sigfillset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); - - /* set our name for identification purposes */ - sprintf(current->comm, "usb-storage-%d", us->host_number); - - unlock_kernel(); - - /* set up for wakeups by new commands */ - init_MUTEX_LOCKED(&us->sema); - - /* signal that we've started the thread */ - complete(&(us->notify)); - set_current_state(TASK_INTERRUPTIBLE); - - for(;;) { - US_DEBUGP("*** thread sleeping.\n"); - if(down_interruptible(&us->sema)) - break; - - US_DEBUGP("*** thread awakened.\n"); - - /* lock access to the queue element */ - down(&(us->queue_exclusion)); - - /* take the command off the queue */ - action = us->action; - us->action = 0; - us->srb = us->queue_srb; - - /* release the queue lock as fast as possible */ - up(&(us->queue_exclusion)); - - switch (action) { - case US_ACT_COMMAND: - /* reject the command if the direction indicator - * is UNKNOWN - */ - if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { - US_DEBUGP("UNKNOWN data direction\n"); - us->srb->result = DID_ERROR << 16; - set_current_state(TASK_INTERRUPTIBLE); - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* reject if target != 0 or if LUN is higher than - * the maximum known LUN - */ - if (us->srb->target && - !(us->flags & US_FL_SCM_MULT_TARG)) { - US_DEBUGP("Bad target number (%d/%d)\n", - us->srb->target, us->srb->lun); - us->srb->result = DID_BAD_TARGET << 16; - - set_current_state(TASK_INTERRUPTIBLE); - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - if (us->srb->lun > us->max_lun) { - US_DEBUGP("Bad LUN (%d/%d)\n", - us->srb->target, us->srb->lun); - us->srb->result = DID_BAD_TARGET << 16; - - set_current_state(TASK_INTERRUPTIBLE); - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* handle those devices which can't do a START_STOP */ - if ((us->srb->cmnd[0] == START_STOP) && - (us->flags & US_FL_START_STOP)) { - US_DEBUGP("Skipping START_STOP command\n"); - us->srb->result = GOOD << 1; - - set_current_state(TASK_INTERRUPTIBLE); - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* lock the device pointers */ - down(&(us->dev_semaphore)); - - /* our device has gone - pretend not ready */ - if (!us->pusb_dev) { - US_DEBUGP("Request is for removed device\n"); - /* For REQUEST_SENSE, it's the data. But - * for anything else, it should look like - * we auto-sensed for it. - */ - if (us->srb->cmnd[0] == REQUEST_SENSE) { - memcpy(us->srb->request_buffer, - usb_stor_sense_notready, - sizeof(usb_stor_sense_notready)); - us->srb->result = GOOD << 1; - } else if(us->srb->cmnd[0] == INQUIRY) { - unsigned char data_ptr[36] = { - 0x20, 0x80, 0x02, 0x02, - 0x1F, 0x00, 0x00, 0x00}; - US_DEBUGP("Faking INQUIRY command for disconnected device\n"); - fill_inquiry_response(us, data_ptr, 36); - us->srb->result = GOOD << 1; - } else { - memcpy(us->srb->sense_buffer, - usb_stor_sense_notready, - sizeof(usb_stor_sense_notready)); - us->srb->result = CHECK_CONDITION << 1; - } - } else { /* !us->pusb_dev */ - - /* Handle those devices which need us to fake - * their inquiry data */ - if ((us->srb->cmnd[0] == INQUIRY) && - (us->flags & US_FL_FIX_INQUIRY)) { - unsigned char data_ptr[36] = { - 0x00, 0x80, 0x02, 0x02, - 0x1F, 0x00, 0x00, 0x00}; - - US_DEBUGP("Faking INQUIRY command\n"); - fill_inquiry_response(us, data_ptr, 36); - us->srb->result = GOOD << 1; - } else { - /* we've got a command, let's do it! */ - US_DEBUG(usb_stor_show_command(us->srb)); - us->proto_handler(us->srb, us); - } - } - - /* unlock the device pointers */ - up(&(us->dev_semaphore)); - - /* indicate that the command is done */ - if (us->srb->result != DID_ABORT << 16) { - US_DEBUGP("scsi cmd done, result=0x%x\n", - us->srb->result); - set_current_state(TASK_INTERRUPTIBLE); - us->srb->scsi_done(us->srb); - } else { - US_DEBUGP("scsi command aborted\n"); - set_current_state(TASK_INTERRUPTIBLE); - complete(&(us->notify)); - } - us->srb = NULL; - break; - - case US_ACT_DEVICE_RESET: - break; - - case US_ACT_BUS_RESET: - break; - - case US_ACT_HOST_RESET: - break; - - } /* end switch on action */ - - /* exit if we get a signal to exit */ - if (action == US_ACT_EXIT) { - US_DEBUGP("-- US_ACT_EXIT command received\n"); - break; - } - } /* for (;;) */ - - /* clean up after ourselves */ - set_current_state(TASK_INTERRUPTIBLE); - - /* notify the exit routine that we're actually exiting now */ - complete(&(us->notify)); - - return 0; -} - -/* Set up the IRQ pipe and handler - * Note that this function assumes that all the data in the us_data - * strucuture is current. This includes the ep_int field, which gives us - * the endpoint for the interrupt. - * Returns non-zero on failure, zero on success - */ -static int usb_stor_allocate_irq(struct us_data *ss) -{ - unsigned int pipe; - int maxp; - int result; - - US_DEBUGP("Allocating IRQ for CBI transport\n"); - - /* lock access to the data structure */ - down(&(ss->irq_urb_sem)); - - /* allocate the URB */ - ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ss->irq_urb) { - up(&(ss->irq_urb_sem)); - US_DEBUGP("couldn't allocate interrupt URB"); - return 1; - } - - /* calculate the pipe and max packet size */ - pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK); - maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe)); - if (maxp > sizeof(ss->irqbuf)) - maxp = sizeof(ss->irqbuf); - - /* fill in the URB with our data */ - FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp, - usb_stor_CBI_irq, ss, ss->ep_int->bInterval); - - /* submit the URB for processing */ - result = usb_submit_urb(ss->irq_urb, GFP_KERNEL); - US_DEBUGP("usb_submit_urb() returns %d\n", result); - if (result) { - usb_free_urb(ss->irq_urb); - up(&(ss->irq_urb_sem)); - return 2; - } - - /* unlock the data structure and return success */ - up(&(ss->irq_urb_sem)); - return 0; -} - -/* Probe to see if a new device is actually a SCSI device */ -static void * storage_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - int i; - const int id_index = id - storage_usb_ids; - char mf[USB_STOR_STRING_LEN]; /* manufacturer */ - char prod[USB_STOR_STRING_LEN]; /* product */ - char serial[USB_STOR_STRING_LEN]; /* serial number */ - GUID(guid); /* Global Unique Identifier */ - unsigned int flags; - struct us_unusual_dev *unusual_dev; - struct us_data *ss = NULL; -#ifdef CONFIG_USB_STORAGE_SDDR09 - int result; -#endif - - /* these are temporary copies -- we test on these, then put them - * in the us-data structure - */ - struct usb_endpoint_descriptor *ep_in = NULL; - struct usb_endpoint_descriptor *ep_out = NULL; - struct usb_endpoint_descriptor *ep_int = NULL; - u8 subclass = 0; - u8 protocol = 0; - - /* the altsettting on the interface we're probing that matched our - * usb_match_id table - */ - struct usb_interface *intf = dev->actconfig->interface; - struct usb_interface_descriptor *altsetting = - intf[ifnum].altsetting + intf[ifnum].act_altsetting; - US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting); - - /* clear the temporary strings */ - memset(mf, 0, sizeof(mf)); - memset(prod, 0, sizeof(prod)); - memset(serial, 0, sizeof(serial)); - - /* - * Can we support this device, either because we know about it - * from our unusual device list, or because it advertises that it's - * compliant to the specification? - * - * id_index is calculated in the declaration to be the index number - * of the match from the usb_device_id table, so we can find the - * corresponding entry in the private table. - */ - US_DEBUGP("id_index calculated to be: %d\n", id_index); - US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])); - if (id_index < - sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) { - unusual_dev = &us_unusual_dev_list[id_index]; - if (unusual_dev->vendorName) - US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); - if (unusual_dev->productName) - US_DEBUGP("Product: %s\n", unusual_dev->productName); - } else - /* no, we can't support it */ - return NULL; - - /* At this point, we know we've got a live one */ - US_DEBUGP("USB Mass Storage device detected\n"); - - /* Determine subclass and protocol, or copy from the interface */ - subclass = unusual_dev->useProtocol; - protocol = unusual_dev->useTransport; - flags = unusual_dev->flags; - - /* - * Find the endpoints we need - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). - * We will ignore any others. - */ - for (i = 0; i < altsetting->bNumEndpoints; i++) { - /* is it an BULK endpoint? */ - if ((altsetting->endpoint[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { - /* BULK in or out? */ - if (altsetting->endpoint[i].bEndpointAddress & - USB_DIR_IN) - ep_in = &altsetting->endpoint[i]; - else - ep_out = &altsetting->endpoint[i]; - } - - /* is it an interrupt endpoint? */ - if ((altsetting->endpoint[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { - ep_int = &altsetting->endpoint[i]; - } - } - US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", - ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); - -#ifdef CONFIG_USB_STORAGE_SDDR09 - if (protocol == US_PR_EUSB_SDDR09 || protocol == US_PR_DPCM_USB) { - /* set the configuration -- STALL is an acceptable response here */ - result = usb_set_configuration(dev, 1); - - US_DEBUGP("Result from usb_set_configuration is %d\n", result); - if (result == -EPIPE) { - US_DEBUGP("-- clearing stall on control interface\n"); - usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); - } else if (result != 0) { - /* it's not a stall, but another error -- time to bail */ - US_DEBUGP("-- Unknown error. Rejecting device\n"); - return NULL; - } - } -#endif - - /* Do some basic sanity checks, and bail if we find a problem */ - if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { - US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); - return NULL; - } - - /* At this point, we're committed to using the device */ - usb_inc_dev_use(dev); - - /* clear the GUID and fetch the strings */ - GUID_CLEAR(guid); - if (dev->descriptor.iManufacturer) - usb_string(dev, dev->descriptor.iManufacturer, - mf, sizeof(mf)); - if (dev->descriptor.iProduct) - usb_string(dev, dev->descriptor.iProduct, - prod, sizeof(prod)); - if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER)) - usb_string(dev, dev->descriptor.iSerialNumber, - serial, sizeof(serial)); - - /* Create a GUID for this device */ - if (dev->descriptor.iSerialNumber && serial[0]) { - /* If we have a serial number, and it's a non-NULL string */ - make_guid(guid, dev->descriptor.idVendor, - dev->descriptor.idProduct, serial); - } else { - /* We don't have a serial number, so we use 0 */ - make_guid(guid, dev->descriptor.idVendor, - dev->descriptor.idProduct, "0"); - } - - /* - * Now check if we have seen this GUID before - * We're looking for a device with a matching GUID that isn't - * already on the system - */ - ss = us_list; - while ((ss != NULL) && - ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid))) - ss = ss->next; - - if (ss != NULL) { - /* Existing device -- re-connect */ - US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", - GUID_ARGS(guid)); - - /* lock the device pointers */ - down(&(ss->dev_semaphore)); - - /* establish the connection to the new device upon reconnect */ - ss->ifnum = ifnum; - ss->pusb_dev = dev; - - /* copy over the endpoint data */ - if (ep_in) - ss->ep_in = ep_in->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - if (ep_out) - ss->ep_out = ep_out->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - ss->ep_int = ep_int; - - /* allocate an IRQ callback if one is needed */ - if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { - usb_dec_dev_use(dev); - return NULL; - } - - /* allocate the URB we're going to use */ - ss->current_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ss->current_urb) { - usb_dec_dev_use(dev); - return NULL; - } - - /* Re-Initialize the device if it needs it */ - if (unusual_dev && unusual_dev->initFunction) - (unusual_dev->initFunction)(ss); - - /* unlock the device pointers */ - up(&(ss->dev_semaphore)); - - } else { - /* New device -- allocate memory and initialize */ - US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); - - if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), - GFP_KERNEL)) == NULL) { - printk(KERN_WARNING USB_STORAGE "Out of memory\n"); - usb_dec_dev_use(dev); - return NULL; - } - memset(ss, 0, sizeof(struct us_data)); - - /* allocate the URB we're going to use */ - ss->current_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ss->current_urb) { - kfree(ss); - usb_dec_dev_use(dev); - return NULL; - } - - /* Initialize the mutexes only when the struct is new */ - init_completion(&(ss->notify)); - init_MUTEX_LOCKED(&(ss->ip_waitq)); - init_MUTEX(&(ss->queue_exclusion)); - init_MUTEX(&(ss->irq_urb_sem)); - init_MUTEX(&(ss->current_urb_sem)); - init_MUTEX(&(ss->dev_semaphore)); - - /* copy over the subclass and protocol data */ - ss->subclass = subclass; - ss->protocol = protocol; - ss->flags = flags; - ss->unusual_dev = unusual_dev; - - /* copy over the endpoint data */ - if (ep_in) - ss->ep_in = ep_in->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - if (ep_out) - ss->ep_out = ep_out->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - ss->ep_int = ep_int; - - /* establish the connection to the new device */ - ss->ifnum = ifnum; - ss->pusb_dev = dev; - - /* copy over the identifiying strings */ - strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); - strncpy(ss->product, prod, USB_STOR_STRING_LEN); - strncpy(ss->serial, serial, USB_STOR_STRING_LEN); - if (strlen(ss->vendor) == 0) { - if (unusual_dev->vendorName) - strncpy(ss->vendor, unusual_dev->vendorName, - USB_STOR_STRING_LEN); - else - strncpy(ss->vendor, "Unknown", - USB_STOR_STRING_LEN); - } - if (strlen(ss->product) == 0) { - if (unusual_dev->productName) - strncpy(ss->product, unusual_dev->productName, - USB_STOR_STRING_LEN); - else - strncpy(ss->product, "Unknown", - USB_STOR_STRING_LEN); - } - if (strlen(ss->serial) == 0) - strncpy(ss->serial, "None", USB_STOR_STRING_LEN); - - /* copy the GUID we created before */ - memcpy(ss->guid, guid, sizeof(guid)); - - /* - * Set the handler pointers based on the protocol - * Again, this data is persistant across reattachments - */ - switch (ss->protocol) { - case US_PR_CB: - ss->transport_name = "Control/Bulk"; - ss->transport = usb_stor_CB_transport; - ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 7; - break; - - case US_PR_CBI: - ss->transport_name = "Control/Bulk/Interrupt"; - ss->transport = usb_stor_CBI_transport; - ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 7; - break; - - case US_PR_BULK: - ss->transport_name = "Bulk"; - ss->transport = usb_stor_Bulk_transport; - ss->transport_reset = usb_stor_Bulk_reset; - ss->max_lun = usb_stor_Bulk_max_lun(ss); - break; - -#ifdef CONFIG_USB_STORAGE_HP8200e - case US_PR_SCM_ATAPI: - ss->transport_name = "SCM/ATAPI"; - ss->transport = hp8200e_transport; - ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 1; - break; -#endif - -#ifdef CONFIG_USB_STORAGE_SDDR09 - case US_PR_EUSB_SDDR09: - ss->transport_name = "EUSB/SDDR09"; - ss->transport = sddr09_transport; - ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 0; - break; -#endif - -#ifdef CONFIG_USB_STORAGE_DPCM - case US_PR_DPCM_USB: - ss->transport_name = "Control/Bulk-EUSB/SDDR09"; - ss->transport = dpcm_transport; - ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 1; - break; -#endif - -#ifdef CONFIG_USB_STORAGE_FREECOM - case US_PR_FREECOM: - ss->transport_name = "Freecom"; - ss->transport = freecom_transport; - ss->transport_reset = usb_stor_freecom_reset; - ss->max_lun = 0; - break; -#endif - -#ifdef CONFIG_USB_STORAGE_DATAFAB - case US_PR_DATAFAB: - ss->transport_name = "Datafab Bulk-Only"; - ss->transport = datafab_transport; - ss->transport_reset = usb_stor_Bulk_reset; - ss->max_lun = 1; - break; -#endif - -#ifdef CONFIG_USB_STORAGE_JUMPSHOT - case US_PR_JUMPSHOT: - ss->transport_name = "Lexar Jumpshot Control/Bulk"; - ss->transport = jumpshot_transport; - ss->transport_reset = usb_stor_Bulk_reset; - ss->max_lun = 1; - break; -#endif - - default: - ss->transport_name = "Unknown"; - kfree(ss->current_urb); - kfree(ss); - usb_dec_dev_use(dev); - return NULL; - break; - } - US_DEBUGP("Transport: %s\n", ss->transport_name); - - /* fix for single-lun devices */ - if (ss->flags & US_FL_SINGLE_LUN) - ss->max_lun = 0; - - switch (ss->subclass) { - case US_SC_RBC: - ss->protocol_name = "Reduced Block Commands (RBC)"; - ss->proto_handler = usb_stor_transparent_scsi_command; - break; - - case US_SC_8020: - ss->protocol_name = "8020i"; - ss->proto_handler = usb_stor_ATAPI_command; - ss->max_lun = 0; - break; - - case US_SC_QIC: - ss->protocol_name = "QIC-157"; - ss->proto_handler = usb_stor_qic157_command; - ss->max_lun = 0; - break; - - case US_SC_8070: - ss->protocol_name = "8070i"; - ss->proto_handler = usb_stor_ATAPI_command; - ss->max_lun = 0; - break; - - case US_SC_SCSI: - ss->protocol_name = "Transparent SCSI"; - ss->proto_handler = usb_stor_transparent_scsi_command; - break; - - case US_SC_UFI: - ss->protocol_name = "Uniform Floppy Interface (UFI)"; - ss->proto_handler = usb_stor_ufi_command; - break; - -#ifdef CONFIG_USB_STORAGE_ISD200 - case US_SC_ISD200: - ss->protocol_name = "ISD200 ATA/ATAPI"; - ss->proto_handler = isd200_ata_command; - break; -#endif - - default: - ss->protocol_name = "Unknown"; - kfree(ss->current_urb); - kfree(ss); - return NULL; - break; - } - US_DEBUGP("Protocol: %s\n", ss->protocol_name); - - /* allocate an IRQ callback if one is needed */ - if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { - usb_dec_dev_use(dev); - return NULL; - } - - /* - * Since this is a new device, we need to generate a scsi - * host definition, and register with the higher SCSI layers - */ - - /* Initialize the host template based on the default one */ - memcpy(&(ss->htmplt), &usb_stor_host_template, - sizeof(usb_stor_host_template)); - - /* Grab the next host number */ - ss->host_number = my_host_number++; - - /* We abuse this pointer so we can pass the ss pointer to - * the host controller thread in us_detect. But how else are - * we to do it? - */ - (struct us_data *)ss->htmplt.proc_dir = ss; - - /* Just before we start our control thread, initialize - * the device if it needs initialization */ - if (unusual_dev && unusual_dev->initFunction) - unusual_dev->initFunction(ss); - - /* start up our control thread */ - ss->pid = kernel_thread(usb_stor_control_thread, ss, - CLONE_VM); - if (ss->pid < 0) { - printk(KERN_WARNING USB_STORAGE - "Unable to start control thread\n"); - kfree(ss->current_urb); - kfree(ss); - usb_dec_dev_use(dev); - return NULL; - } - - /* wait for the thread to start */ - wait_for_completion(&(ss->notify)); - - /* now register - our detect function will be called */ - ss->htmplt.module = THIS_MODULE; - scsi_register_host(&ss->htmplt); - - /* lock access to the data structures */ - down(&us_list_semaphore); - - /* put us in the list */ - ss->next = us_list; - us_list = ss; - - /* release the data structure lock */ - up(&us_list_semaphore); - } - - printk(KERN_DEBUG - "WARNING: USB Mass Storage data integrity not assured\n"); - printk(KERN_DEBUG - "USB Mass Storage device found at %d\n", dev->devnum); - - /* return a pointer for the disconnect function */ - return ss; -} - -/* Handle a disconnect event from the USB core */ -static void storage_disconnect(struct usb_device *dev, void *ptr) -{ - struct us_data *ss = ptr; - int result; - - US_DEBUGP("storage_disconnect() called\n"); - - /* this is the odd case -- we disconnected but weren't using it */ - if (!ss) { - US_DEBUGP("-- device was not in use\n"); - return; - } - - /* lock access to the device data structure */ - down(&(ss->dev_semaphore)); - - /* release the IRQ, if we have one */ - down(&(ss->irq_urb_sem)); - if (ss->irq_urb) { - US_DEBUGP("-- releasing irq URB\n"); - result = usb_unlink_urb(ss->irq_urb); - US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); - usb_free_urb(ss->irq_urb); - ss->irq_urb = NULL; - } - up(&(ss->irq_urb_sem)); - - /* free up the main URB for this device */ - US_DEBUGP("-- releasing main URB\n"); - result = usb_unlink_urb(ss->current_urb); - US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); - usb_free_urb(ss->current_urb); - ss->current_urb = NULL; - - /* mark the device as gone */ - usb_dec_dev_use(ss->pusb_dev); - ss->pusb_dev = NULL; - - /* unlock access to the device data structure */ - up(&(ss->dev_semaphore)); -} - -/*********************************************************************** - * Initialization and registration - ***********************************************************************/ - -int __init usb_stor_init(void) -{ - printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); - - /* initialize internal global data elements */ - us_list = NULL; - init_MUTEX(&us_list_semaphore); - my_host_number = 0; - - /* register the driver, return -1 if error */ - if (usb_register(&usb_storage_driver) < 0) - return -1; - - /* we're all set */ - printk(KERN_INFO "USB Mass Storage support registered.\n"); - return 0; -} - -void __exit usb_stor_exit(void) -{ - struct us_data *next; - - US_DEBUGP("usb_stor_exit() called\n"); - - /* Deregister the driver - * This eliminates races with probes and disconnects - */ - US_DEBUGP("-- calling usb_deregister()\n"); - usb_deregister(&usb_storage_driver) ; - - /* While there are still virtual hosts, unregister them - * Note that it's important to do this completely before removing - * the structures because of possible races with the /proc - * interface - */ - for (next = us_list; next; next = next->next) { - US_DEBUGP("-- calling scsi_unregister_host()\n"); - scsi_unregister_host(&next->htmplt); - } - - /* While there are still structures, free them. Note that we are - * now race-free, since these structures can no longer be accessed - * from either the SCSI command layer or the /proc interface - */ - while (us_list) { - /* keep track of where the next one is */ - next = us_list->next; - - /* If there's extra data in the us_data structure then - * free that first */ - if (us_list->extra) { - /* call the destructor routine, if it exists */ - if (us_list->extra_destructor) { - US_DEBUGP("-- calling extra_destructor()\n"); - us_list->extra_destructor(us_list->extra); - } - - /* destroy the extra data */ - US_DEBUGP("-- freeing the data structure\n"); - kfree(us_list->extra); - } - - /* free the structure itself */ - kfree (us_list); - - /* advance the list pointer */ - us_list = next; - } -} - -module_init(usb_stor_init); -module_exit(usb_stor_exit); diff --git a/drivers/usb/class/storage/usb.h b/drivers/usb/class/storage/usb.h deleted file mode 100644 index 5fd910ec70a7..000000000000 --- a/drivers/usb/class/storage/usb.h +++ /dev/null @@ -1,191 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Main Header File - * - * $Id: usb.h,v 1.18 2001/07/30 00:27:59 mdharm Exp $ - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * 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, 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. - */ - -#ifndef _USB_H_ -#define _USB_H_ - -#include <linux/usb.h> -#include <linux/blk.h> -#include <linux/smp_lock.h> -#include <linux/completion.h> -#include "scsi.h" -#include "hosts.h" - -/* - * GUID definitions - */ - -#define GUID(x) __u32 x[3] -#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) -#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0; -#define GUID_NONE(x) (!x[0] && !x[1] && !x[2]) -#define GUID_FORMAT "%08x%08x%08x" -#define GUID_ARGS(x) x[0], x[1], x[2] - -static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial) -{ - pg[0] = (vendor << 16) | product; - pg[1] = pg[2] = 0; - while (*serial) { - pg[1] <<= 4; - pg[1] |= pg[2] >> 28; - pg[2] <<= 4; - if (*serial >= 'a') - *serial -= 'a' - 'A'; - pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0' - : *serial - 'A' + 10; - serial++; - } -} - -struct us_data; - -/* - * Unusual device list definitions - */ - -struct us_unusual_dev { - const char* vendorName; - const char* productName; - __u8 useProtocol; - __u8 useTransport; - int (*initFunction)(struct us_data *); - unsigned int flags; -}; - -/* Flag definitions */ -#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ -#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for - Win/MacOS compatibility */ -#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ -#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ -#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ - -#define USB_STOR_STRING_LEN 32 - -typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); -typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); -typedef void (*extra_data_destructor)(void *); /* extra data destructor */ - -/* we allocate one of these for every device that we remember */ -struct us_data { - struct us_data *next; /* next device */ - - /* the device we're working with */ - struct semaphore dev_semaphore; /* protect pusb_dev */ - struct usb_device *pusb_dev; /* this usb_device */ - - unsigned int flags; /* from filter initially */ - - /* information about the device -- always good */ - char vendor[USB_STOR_STRING_LEN]; - char product[USB_STOR_STRING_LEN]; - char serial[USB_STOR_STRING_LEN]; - char *transport_name; - char *protocol_name; - u8 subclass; - u8 protocol; - u8 max_lun; - - /* information about the device -- only good if device is attached */ - u8 ifnum; /* interface number */ - u8 ep_in; /* bulk in endpoint */ - u8 ep_out; /* bulk out endpoint */ - struct usb_endpoint_descriptor *ep_int; /* interrupt endpoint */ - - /* function pointers for this device */ - trans_cmnd transport; /* transport function */ - trans_reset transport_reset; /* transport device reset */ - proto_cmnd proto_handler; /* protocol handler */ - - /* SCSI interfaces */ - GUID(guid); /* unique dev id */ - struct Scsi_Host *host; /* our dummy host data */ - Scsi_Host_Template htmplt; /* own host template */ - int host_number; /* to find us */ - int host_no; /* allocated by scsi */ - Scsi_Cmnd *srb; /* current srb */ - - /* thread information */ - Scsi_Cmnd *queue_srb; /* the single queue slot */ - int action; /* what to do */ - int pid; /* control thread */ - - /* interrupt info for CBI devices -- only good if attached */ - struct semaphore ip_waitq; /* for CBI interrupts */ - atomic_t ip_wanted[1]; /* is an IRQ expected? */ - - /* interrupt communications data */ - struct semaphore irq_urb_sem; /* to protect irq_urb */ - struct urb *irq_urb; /* for USB int requests */ - unsigned char irqbuf[2]; /* buffer for USB IRQ */ - unsigned char irqdata[2]; /* data from USB IRQ */ - - /* control and bulk communications data */ - struct semaphore current_urb_sem; /* to protect irq_urb */ - struct urb *current_urb; /* non-int USB requests */ - - /* the semaphore for sleeping the control thread */ - struct semaphore sema; /* to sleep thread on */ - - /* mutual exclusion structures */ - struct completion notify; /* thread begin/end */ - struct semaphore queue_exclusion; /* to protect data structs */ - struct us_unusual_dev *unusual_dev; /* If unusual device */ - void *extra; /* Any extra data */ - extra_data_destructor extra_destructor;/* extra data destructor */ -}; - -/* The list of structures and the protective lock for them */ -extern struct us_data *us_list; -extern struct semaphore us_list_semaphore; - -/* The structure which defines our driver */ -extern struct usb_driver usb_storage_driver; - -/* Function to fill an inquiry response. See usb.c for details */ -extern void fill_inquiry_response(struct us_data *us, - unsigned char *data, unsigned int data_len); -#endif diff --git a/drivers/usb/class/usbkbd.c b/drivers/usb/class/usbkbd.c deleted file mode 100644 index 31edd4e7b52b..000000000000 --- a/drivers/usb/class/usbkbd.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - * - * USB HIDBP Keyboard support - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/input.h> -#include <linux/init.h> -#include <linux/usb.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "" -#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" -#define DRIVER_DESC "USB HID Boot Protocol keyboard driver" -#define DRIVER_LICENSE "GPL" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); - -static unsigned char usb_kbd_keycode[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, - 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, - 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140 -}; - -struct usb_kbd { - struct input_dev dev; - struct usb_device *usbdev; - unsigned char new[8]; - unsigned char old[8]; - struct urb *irq, *led; - struct usb_ctrlrequest cr; - unsigned char leds, newleds; - char name[128]; - char phys[64]; - int open; -}; - -static void usb_kbd_irq(struct urb *urb) -{ - struct usb_kbd *kbd = urb->context; - int i; - - if (urb->status) return; - - for (i = 0; i < 8; i++) - input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); - - for (i = 2; i < 8; i++) { - - if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { - if (usb_kbd_keycode[kbd->old[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); - else - info("Unknown key (scancode %#x) released.", kbd->old[i]); - } - - if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { - if (usb_kbd_keycode[kbd->new[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); - else - info("Unknown key (scancode %#x) pressed.", kbd->new[i]); - } - } - - memcpy(kbd->old, kbd->new, 8); -} - -int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct usb_kbd *kbd = dev->private; - - if (type != EV_LED) return -1; - - - kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | - (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | - (!!test_bit(LED_NUML, dev->led)); - - if (kbd->led->status == -EINPROGRESS) - return 0; - - if (kbd->leds == kbd->newleds) - return 0; - - kbd->leds = kbd->newleds; - kbd->led->dev = kbd->usbdev; - if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err("usb_submit_urb(leds) failed"); - - return 0; -} - -static void usb_kbd_led(struct urb *urb) -{ - struct usb_kbd *kbd = urb->context; - - if (urb->status) - warn("led urb status %d received", urb->status); - - if (kbd->leds == kbd->newleds) - return; - - kbd->leds = kbd->newleds; - kbd->led->dev = kbd->usbdev; - if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err("usb_submit_urb(leds) failed"); -} - -static int usb_kbd_open(struct input_dev *dev) -{ - struct usb_kbd *kbd = dev->private; - - if (kbd->open++) - return 0; - - kbd->irq->dev = kbd->usbdev; - if (usb_submit_urb(kbd->irq, GFP_KERNEL)) - return -EIO; - - return 0; -} - -static void usb_kbd_close(struct input_dev *dev) -{ - struct usb_kbd *kbd = dev->private; - - if (!--kbd->open) - usb_unlink_urb(kbd->irq); -} - -static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct usb_interface *iface; - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_kbd *kbd; - int i, pipe, maxp; - char path[64]; - char *buf; - - iface = &dev->actconfig->interface[ifnum]; - interface = &iface->altsetting[iface->act_altsetting]; - - if (interface->bNumEndpoints != 1) return NULL; - - endpoint = interface->endpoint + 0; - if (!(endpoint->bEndpointAddress & 0x80)) return NULL; - if ((endpoint->bmAttributes & 3) != 3) return NULL; - - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL; - memset(kbd, 0, sizeof(struct usb_kbd)); - - kbd->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!kbd->irq) { - kfree(kbd); - return NULL; - } - kbd->led = usb_alloc_urb(0, GFP_KERNEL); - if (!kbd->led) { - usb_free_urb(kbd->irq); - kfree(kbd); - return NULL; - } - - kbd->usbdev = dev; - - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); - - for (i = 0; i < 255; i++) - set_bit(usb_kbd_keycode[i], kbd->dev.keybit); - clear_bit(0, kbd->dev.keybit); - - kbd->dev.private = kbd; - kbd->dev.event = usb_kbd_event; - kbd->dev.open = usb_kbd_open; - kbd->dev.close = usb_kbd_close; - - FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, - usb_kbd_irq, kbd, endpoint->bInterval); - - kbd->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kbd->cr.bRequest = 0x09; - kbd->cr.wValue = 0x200; - kbd->cr.wIndex = interface->bInterfaceNumber; - kbd->cr.wLength = 1; - - usb_make_path(dev, path, 64); - sprintf(kbd->phys, "%s/input0", path); - - kbd->dev.name = kbd->name; - kbd->dev.phys = kbd->phys; - kbd->dev.idbus = BUS_USB; - kbd->dev.idvendor = dev->descriptor.idVendor; - kbd->dev.idproduct = dev->descriptor.idProduct; - kbd->dev.idversion = dev->descriptor.bcdDevice; - - if (!(buf = kmalloc(63, GFP_KERNEL))) { - kfree(kbd); - return NULL; - } - - if (dev->descriptor.iManufacturer && - usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) - strcat(kbd->name, buf); - if (dev->descriptor.iProduct && - usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) - sprintf(kbd->name, "%s %s", kbd->name, buf); - - if (!strlen(kbd->name)) - sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x", - kbd->dev.idvendor, kbd->dev.idproduct); - - kfree(buf); - - FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0), - (void*) &kbd->cr, &kbd->leds, 1, usb_kbd_led, kbd); - - input_register_device(&kbd->dev); - - printk(KERN_INFO "input: %s on %s\n", kbd->name, path); - - return kbd; -} - -static void usb_kbd_disconnect(struct usb_device *dev, void *ptr) -{ - struct usb_kbd *kbd = ptr; - usb_unlink_urb(kbd->irq); - input_unregister_device(&kbd->dev); - usb_free_urb(kbd->irq); - usb_free_urb(kbd->led); - kfree(kbd); -} - -static struct usb_device_id usb_kbd_id_table [] = { - { USB_INTERFACE_INFO(3, 1, 1) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); - -static struct usb_driver usb_kbd_driver = { - name: "keyboard", - probe: usb_kbd_probe, - disconnect: usb_kbd_disconnect, - id_table: usb_kbd_id_table, -}; - -static int __init usb_kbd_init(void) -{ - usb_register(&usb_kbd_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; -} - -static void __exit usb_kbd_exit(void) -{ - usb_deregister(&usb_kbd_driver); -} - -module_init(usb_kbd_init); -module_exit(usb_kbd_exit); diff --git a/drivers/usb/class/usbmouse.c b/drivers/usb/class/usbmouse.c deleted file mode 100644 index 22673b42d60a..000000000000 --- a/drivers/usb/class/usbmouse.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - * - * USB HIDBP Mouse support - */ - -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/input.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/usb.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.6" -#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" -#define DRIVER_DESC "USB HID Boot Protocol mouse driver" -#define DRIVER_LICENSE "GPL" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); - -struct usb_mouse { - signed char data[8]; - char name[128]; - char phys[64]; - struct usb_device *usbdev; - struct input_dev dev; - struct urb *irq; - int open; -}; - -static void usb_mouse_irq(struct urb *urb) -{ - struct usb_mouse *mouse = urb->context; - signed char *data = mouse->data; - struct input_dev *dev = &mouse->dev; - - if (urb->status) return; - - input_report_key(dev, BTN_LEFT, data[0] & 0x01); - input_report_key(dev, BTN_RIGHT, data[0] & 0x02); - input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); - input_report_key(dev, BTN_SIDE, data[0] & 0x08); - input_report_key(dev, BTN_EXTRA, data[0] & 0x10); - - input_report_rel(dev, REL_X, data[1]); - input_report_rel(dev, REL_Y, data[2]); - input_report_rel(dev, REL_WHEEL, data[3]); -} - -static int usb_mouse_open(struct input_dev *dev) -{ - struct usb_mouse *mouse = dev->private; - - if (mouse->open++) - return 0; - - mouse->irq->dev = mouse->usbdev; - if (usb_submit_urb(mouse->irq, GFP_KERNEL)) - return -EIO; - - return 0; -} - -static void usb_mouse_close(struct input_dev *dev) -{ - struct usb_mouse *mouse = dev->private; - - if (!--mouse->open) - usb_unlink_urb(mouse->irq); -} - -static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct usb_interface *iface; - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_mouse *mouse; - int pipe, maxp; - char path[64]; - char *buf; - - iface = &dev->actconfig->interface[ifnum]; - interface = &iface->altsetting[iface->act_altsetting]; - - if (interface->bNumEndpoints != 1) return NULL; - - endpoint = interface->endpoint + 0; - if (!(endpoint->bEndpointAddress & 0x80)) return NULL; - if ((endpoint->bmAttributes & 3) != 3) return NULL; - - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; - memset(mouse, 0, sizeof(struct usb_mouse)); - - mouse->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!mouse->irq) { - kfree(mouse); - return NULL; - } - - mouse->usbdev = dev; - - mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); - mouse->dev.relbit[0] |= BIT(REL_WHEEL); - - mouse->dev.private = mouse; - mouse->dev.open = usb_mouse_open; - mouse->dev.close = usb_mouse_close; - - usb_make_path(dev, path, 64); - sprintf(mouse->phys, "%s/input0", path); - - mouse->dev.name = mouse->name; - mouse->dev.phys = mouse->phys; - mouse->dev.idbus = BUS_USB; - mouse->dev.idvendor = dev->descriptor.idVendor; - mouse->dev.idproduct = dev->descriptor.idProduct; - mouse->dev.idversion = dev->descriptor.bcdDevice; - - if (!(buf = kmalloc(63, GFP_KERNEL))) { - kfree(mouse); - return NULL; - } - - if (dev->descriptor.iManufacturer && - usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) - strcat(mouse->name, buf); - if (dev->descriptor.iProduct && - usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) - sprintf(mouse->name, "%s %s", mouse->name, buf); - - if (!strlen(mouse->name)) - sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x", - mouse->dev.idvendor, mouse->dev.idproduct); - - kfree(buf); - - FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, - usb_mouse_irq, mouse, endpoint->bInterval); - - input_register_device(&mouse->dev); - - printk(KERN_INFO "input: %s on %s\n", mouse->name, path); - - return mouse; -} - -static void usb_mouse_disconnect(struct usb_device *dev, void *ptr) -{ - struct usb_mouse *mouse = ptr; - usb_unlink_urb(mouse->irq); - input_unregister_device(&mouse->dev); - usb_free_urb(mouse->irq); - kfree(mouse); -} - -static struct usb_device_id usb_mouse_id_table [] = { - { USB_INTERFACE_INFO(3, 1, 2) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); - -static struct usb_driver usb_mouse_driver = { - name: "usb_mouse", - probe: usb_mouse_probe, - disconnect: usb_mouse_disconnect, - id_table: usb_mouse_id_table, -}; - -static int __init usb_mouse_init(void) -{ - usb_register(&usb_mouse_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; -} - -static void __exit usb_mouse_exit(void) -{ - usb_deregister(&usb_mouse_driver); -} - -module_init(usb_mouse_init); -module_exit(usb_mouse_exit); |
