summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in1
-rw-r--r--drivers/usb/acm.c7
-rw-r--r--drivers/usb/audio.c1
-rw-r--r--drivers/usb/dc2xx.c4
-rw-r--r--drivers/usb/devices.c8
-rw-r--r--drivers/usb/devio.c3
-rw-r--r--drivers/usb/drivers.c2
-rw-r--r--drivers/usb/dsbr100.c24
-rw-r--r--drivers/usb/evdev.c1
-rw-r--r--drivers/usb/joydev.c1
-rw-r--r--drivers/usb/keybdev.c4
-rw-r--r--drivers/usb/mdc800.c107
-rw-r--r--drivers/usb/mousedev.c13
-rw-r--r--drivers/usb/printer.c1
-rw-r--r--drivers/usb/rio500.c21
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/ftdi_sio.c10
-rw-r--r--drivers/usb/serial/keyspan_pda.c198
-rw-r--r--drivers/usb/serial/omninet.c339
-rw-r--r--drivers/usb/serial/usb-serial.h21
-rw-r--r--drivers/usb/serial/usbserial.c468
-rw-r--r--drivers/usb/uhci-debug.h58
-rw-r--r--drivers/usb/uhci.c276
-rw-r--r--drivers/usb/uhci.h9
-rw-r--r--drivers/usb/usb-core.c4
-rw-r--r--drivers/usb/usb-ohci.c2
-rw-r--r--drivers/usb/usb-storage.c550
-rw-r--r--drivers/usb/usb-storage.h29
28 files changed, 1391 insertions, 773 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 460a44105..cba82175a 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -33,6 +33,7 @@ comment 'USB Devices'
bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT
bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
+ bool ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
fi
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 453c4af19..9dbd51973 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -52,10 +52,6 @@
#define DEBUG
#include <linux/usb.h>
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
- unsigned minor);
-void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
/*
* CMSPAR, some architectures can't have space and mark parity.
*/
@@ -261,7 +257,8 @@ static void acm_write_bulk(struct urb *urb)
if (urb->status)
dbg("nonzero write bulk status received: %d", urb->status);
- queue_task(&acm->tqueue, &tq_scheduler);
+ queue_task(&acm->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
static void acm_softint(void *private)
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 6772889b0..c8f187280 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -2108,6 +2108,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
return ret;
}
+/* Called without the kernel lock - fine */
static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
{
struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index 9dff6bda1..b440a82af 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -109,8 +109,8 @@ static const struct camera {
struct camera_state {
struct usb_device *dev; /* USB device handle */
- char inEP; /* read endpoint */
- char outEP; /* write endpoint */
+ int inEP; /* read endpoint */
+ int outEP; /* write endpoint */
const struct camera *info; /* DC-240, etc */
int subminor; /* which minor dev #? */
int isActive; /* I/O taking place? */
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index 874887a63..c99f86973 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -54,6 +54,7 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/usb.h>
+#include <linux/smp_lock.h>
#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
@@ -452,11 +453,13 @@ static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff
return ret;
}
+/* Kernel lock for "lastev" protection */
static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
{
struct usb_device_status *st = (struct usb_device_status *)file->private_data;
unsigned int mask = 0;
-
+
+ lock_kernel();
if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
if (!st)
@@ -475,6 +478,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
if (st->lastev != conndiscevcnt)
mask |= POLLIN;
st->lastev = conndiscevcnt;
+ unlock_kernel();
return mask;
}
@@ -494,7 +498,7 @@ static int usb_device_release(struct inode *inode, struct file *file)
return 0;
}
-static long long usb_device_lseek(struct file * file, long long offset, int orig)
+static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
{
switch (orig) {
case 0:
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 933895934..c5d24ec4f 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -162,7 +162,7 @@ static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
return ret;
}
-static long long usbdev_lseek(struct file *file, long long offset, int orig)
+static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
switch (orig) {
case 0:
@@ -989,6 +989,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return ret;
}
+/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
index 11e16b784..28589b1e6 100644
--- a/drivers/usb/drivers.c
+++ b/drivers/usb/drivers.c
@@ -94,7 +94,7 @@ static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff
return ret;
}
-static long long usb_driver_lseek(struct file * file, long long offset, int orig)
+static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig)
{
switch (orig) {
case 0:
diff --git a/drivers/usb/dsbr100.c b/drivers/usb/dsbr100.c
index 22c21bb33..50bbafb31 100644
--- a/drivers/usb/dsbr100.c
+++ b/drivers/usb/dsbr100.c
@@ -15,7 +15,7 @@
You might find some interesting stuff about this module at
http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
- Copyright (c) 2000 Markus Demleitner
+ Copyright (c) 2000 Markus Demleitner <msdemlei@tucana.harvard.edu>
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
@@ -33,9 +33,12 @@
History:
+ Version 0.22:
+ Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
+ thanks to Mike Cox for pointing the problem out.
+
Version 0.21:
- Markus Demleitner <msdemlei@tucana.harvard.edu>:
- Minor cleanup, warnings if something goes wrong, lame attempt
+ Markus: Minor cleanup, warnings if something goes wrong, lame attempt
to adhere to Documentation/CodingStyle
Version 0.2:
@@ -212,13 +215,14 @@ static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
return -EFAULT;
if(v.tuner) /* Only 1 tuner */
return -EINVAL;
- v.rangelow=(87*16000);
- v.rangehigh=(108*16000);
- /*v.flags=VIDEO_TUNER_LOW;*/
- v.mode=VIDEO_MODE_AUTO;
- v.signal=radio->stereo;
- v.flags|=VIDEO_TUNER_STEREO_ON;
- strcpy(v.name, "FM");
+ v.rangelow = 87*16;
+ v.rangehigh = 108*16;
+ v.flags = VIDEO_TUNER_LOW;
+ v.mode = VIDEO_MODE_AUTO;
+ v.signal = radio->stereo*0x7000;
+ /* Don't know how to get signal strength */
+ v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+ strcpy(v.name, "DSB R-100");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
return 0;
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 1d42f7df0..ad3a8ffac 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -192,6 +192,7 @@ static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_
return retval;
}
+/* No kernel lock - fine */
static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct evdev_list *list = file->private_data;
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 585740db9..73ebc4e41 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -308,6 +308,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
return retval;
}
+/* No kernel lock - fine */
static unsigned int joydev_poll(struct file *file, poll_table *wait)
{
struct joydev_list *list = file->private_data;
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 4723ba11b..233f7943b 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -36,7 +36,7 @@
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__)
static int x86_sysrq_alt = 0;
@@ -102,7 +102,7 @@ static unsigned char mac_keycodes[128] =
76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
-static int emulate_raw(unsigned int code, unsigned char upflag)
+static int emulate_raw(unsigned int keycode, int down)
{
if (keycode > 127 || !mac_keycodes[keycode])
return -1;
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
index a45f8c798..96fa3a151 100644
--- a/drivers/usb/mdc800.c
+++ b/drivers/usb/mdc800.c
@@ -30,6 +30,12 @@
*
* The driver supports only one camera.
*
+ * version 0.7.3
+ * bugfix : The mdc800->state field gets set to READY after the
+ * the diconnect function sets it to NOT_CONNECTED. This makes the
+ * driver running like the camera is connected and causes some
+ * hang ups.
+ *
* version 0.7.1
* MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
* problems when compiled as Module.
@@ -73,20 +79,20 @@
#include <linux/usb.h>
-#define VERSION "0.7.1"
-#define RELEASE_DATE "(26/03/2000)"
+#define VERSION "0.7.3"
+#define RELEASE_DATE "(24/04/2000)"
/* Vendor and Product Information */
#define MDC800_VENDOR_ID 0x055f
#define MDC800_PRODUCT_ID 0xa800
/* Timeouts (msec) */
-#define TO_READ_FROM_IRQ 4000
-#define TO_GET_READY 2000
-#define TO_DOWNLOAD_GET_READY 1500
-#define TO_DOWNLOAD_GET_BUSY 1500
-#define TO_WRITE_GET_READY 3000
+#define TO_DOWNLOAD_GET_READY 1500
+#define TO_DOWNLOAD_GET_BUSY 1500
+#define TO_WRITE_GET_READY 1000
#define TO_DEFAULT_COMMAND 5000
+#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND
+#define TO_GET_READY TO_DEFAULT_COMMAND
/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
#define MDC800_DEVICE_MINOR_BASE 32
@@ -114,7 +120,7 @@ struct mdc800_data
wait_queue_head_t irq_wait;
char* irq_urb_buffer;
- int camera_busy; // is camera busy ?
+ int camera_busy; // is camera busy ?
int camera_request_ready; // Status to synchronize with irq
char camera_response [8]; // last Bytes send after busy
@@ -130,9 +136,9 @@ struct mdc800_data
/* Device Data */
- char out [64]; // Answer Buffer
+ char out [64]; // Answer Buffer
int out_ptr; // Index to the first not readen byte
- int out_count; // Bytes in the buffer
+ int out_count; // Bytes in the buffer
int open; // Camera device open ?
int rw_lock; // Block read <-> write
@@ -284,9 +290,17 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
{
mdc800->camera_request_ready=0;
err ("timeout waiting for camera.");
- return 0;
+ return -1;
}
- return 1;
+
+ if (mdc800->state == NOT_CONNECTED)
+ {
+ warn ("Camera gets disconnected during waiting for irq.");
+ mdc800->camera_request_ready=0;
+ return -2;
+ }
+
+ return 0;
}
@@ -301,7 +315,10 @@ static void mdc800_usb_write_notify (struct urb *urb)
{
err ("writing command fails (status=%i)", urb->status);
}
- mdc800->state=READY;
+ else
+ {
+ mdc800->state=READY;
+ }
wake_up_interruptible (&mdc800->write_wait);
}
@@ -328,7 +345,6 @@ static void mdc800_usb_download_notify (struct urb *urb)
else
{
err ("request bytes fails (status:%i)", urb->status);
- mdc800->state=READY;
}
wake_up_interruptible (&mdc800->download_wait);
}
@@ -351,17 +367,18 @@ static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
dbg ("(mdc800_usb_probe) called.");
- if (mdc800->dev != 0)
- {
- warn ("only one Mustek MDC800 is supported.");
- return 0;
- }
if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
return 0;
if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
return 0;
+ if (mdc800->dev != 0)
+ {
+ warn ("only one Mustek MDC800 is supported.");
+ return 0;
+ }
+
if (dev->descriptor.bNumConfigurations != 1)
{
err ("probe fails -> wrong Number of Configuration");
@@ -416,6 +433,8 @@ static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
mdc800->dev=dev;
mdc800->state=READY;
+ mdc800->open=0;
+ mdc800->rw_lock=0;
/* Setup URB Structs */
FILL_INT_URB (
@@ -464,10 +483,8 @@ static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
if (mdc800->state == NOT_CONNECTED)
return;
-
+
mdc800->state=NOT_CONNECTED;
- mdc800->open=0;
- mdc800->rw_lock=0;
usb_unlink_urb (mdc800->irq_urb);
usb_unlink_urb (mdc800->write_urb);
@@ -599,6 +616,12 @@ static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, lof
if (mdc800->state == NOT_CONNECTED)
return -EBUSY;
+ if (mdc800->state == WORKING)
+ {
+ warn ("Illegal State \"working\" reached during read ?!");
+ return -EBUSY;
+ }
+
if (!mdc800->open || mdc800->rw_lock)
return -EBUSY;
mdc800->rw_lock=1;
@@ -624,15 +647,13 @@ static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, lof
if (usb_submit_urb (mdc800->download_urb))
{
err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
- mdc800->state=READY;
mdc800->rw_lock=0;
return len-left;
}
interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
if (mdc800->download_urb->status != 0)
{
- err ("requesting bytes fails (status=%i)",mdc800->download_urb->status);
- mdc800->state=READY;
+ err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
mdc800->rw_lock=0;
return len-left;
}
@@ -710,7 +731,12 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
{
int answersize;
- mdc800_usb_waitForIRQ (0,TO_GET_READY);
+ if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
+ {
+ err ("Camera didn't get ready.\n");
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
answersize=mdc800_getAnswerSize (mdc800->in[1]);
@@ -720,14 +746,12 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
{
err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
mdc800->rw_lock=0;
- mdc800->state=READY;
return -EIO;
}
- interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000);
+ interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
if (mdc800->state == WORKING)
{
usb_unlink_urb (mdc800->write_urb);
- mdc800->state=READY;
mdc800->rw_lock=0;
return -EIO;
}
@@ -756,10 +780,9 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
if (answersize)
{
- if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+ if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
{
err ("requesting answer from irq fails");
- mdc800->state=READY;
mdc800->rw_lock=0;
return -EIO;
}
@@ -785,11 +808,10 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
}
else
{
- if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+ if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
{
err ("Command Timeout.");
mdc800->rw_lock=0;
- mdc800->state=READY;
return -EIO;
}
}
@@ -811,21 +833,10 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
/* File Operations of this drivers */
static struct file_operations mdc800_device_ops =
{
- 0, /* llseek */
- mdc800_device_read,
- mdc800_device_write,
- 0, /* readdir */
- 0, /* poll */
- 0, /* ioctl, this can be used to detect USB ! */
- 0, /* mmap */
- mdc800_device_open,
- 0, /* flush */
- mdc800_device_release,
- 0, /* async */
- 0, /* fasync */
- 0, /* check_media_change */
-// 0, /* revalidate */
-// 0 /* lock */
+ read: mdc800_device_read,
+ write: mdc800_device_write,
+ open: mdc800_device_open,
+ release: mdc800_device_release,
};
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 765f61556..26db93b4f 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -39,11 +39,11 @@
#include <linux/input.h>
#include <linux/config.h>
-#ifndef CONFIG_MOUSEDEV_SCREEN_X
-#define CONFIG_MOUSEDEV_SCREEN_X 1024
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
#endif
-#ifndef CONFIG_MOUSEDEV_SCREEN_Y
-#define CONFIG_MOUSEDEV_SCREEN_Y 768
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
#endif
struct mousedev {
@@ -93,12 +93,12 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
switch (code) {
case ABS_X:
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
- list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
+ list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
list->oldx += list->dx * size;
break;
case ABS_Y:
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+ list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
list->oldy -= list->dy * size;
break;
}
@@ -365,6 +365,7 @@ static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, lo
return count;
}
+/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct mousedev_list *list = file->private_data;
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index c1a7ddb67..d64258e8e 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -198,6 +198,7 @@ static int usblp_release(struct inode *inode, struct file *file)
return 0;
}
+/* No kernel lock - fine */
static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
struct usblp *usblp = file->private_data;
diff --git a/drivers/usb/rio500.c b/drivers/usb/rio500.c
index 7529c7fc0..011f853f6 100644
--- a/drivers/usb/rio500.c
+++ b/drivers/usb/rio500.c
@@ -44,7 +44,7 @@
/* stall/wait timeout for rio */
#define NAK_TIMEOUT (HZ)
-#define IBUF_SIZE 128
+#define IBUF_SIZE 0x1000
/* Size of the rio buffer */
#define OBUF_SIZE 0x10000
@@ -317,7 +317,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
result = usb_bulk_msg(rio->rio_dev,
usb_rcvbulkpipe(rio->rio_dev, 1),
ibuf, this_read, &partial,
- (int) (HZ * .1));
+ (int) (HZ * 8));
dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
result, this_read, partial);
@@ -405,18 +405,11 @@ static void disconnect_rio(struct usb_device *dev, void *ptr)
static struct
file_operations usb_rio_fops = {
- NULL, /* seek */
- read_rio,
- write_rio,
- NULL, /* readdir */
- NULL, /* poll */
- ioctl_rio, /* ioctl */
- NULL, /* mmap */
- open_rio,
- NULL, /* flush */
- close_rio,
- NULL,
- NULL, /* fasync */
+ read: read_rio,
+ write: write_rio,
+ ioctl: ioctl_rio,
+ open: open_rio,
+ release: close_rio,
};
static struct
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 95a686e7a..bd4d51a6a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -4,7 +4,7 @@
O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
+O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o
MOD_LIST_NAME := USB_SERIAL_MODULES
include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 151c4bfe7..a305283bb 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -153,7 +153,7 @@ struct usb_serial_device_type ftdi_sio_device = {
/* do some startup allocations not currently performed by usb_serial_probe() */
static int ftdi_sio_startup (struct usb_serial *serial)
{
- init_waitqueue_head(&serial->write_wait);
+ init_waitqueue_head(&serial->port[0].write_wait);
return (0);
}
@@ -291,7 +291,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
/* Was seeing a race here, got a read callback, then write callback before
hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */
- add_wait_queue(&serial->write_wait, &wait);
+ add_wait_queue(&port->write_wait, &wait);
set_current_state (TASK_INTERRUPTIBLE);
while (port->write_urb->status == -EINPROGRESS) {
dbg("ftdi_sio - write in progress - retrying");
@@ -301,13 +301,13 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
}
if (signal_pending(current)) {
current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
rc = -ERESTARTSYS;
goto err;
}
schedule();
}
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_RUNNING);
count += data_offset;
@@ -388,7 +388,7 @@ static void ftdi_sio_write_bulk_callback (struct urb *urb)
return;
}
- wake_up_interruptible(&serial->write_wait);
+ wake_up_interruptible(&port->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 9fb22e4a8..c63f1b856 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -52,78 +52,20 @@ struct ezusb_hex_record {
#include "usb-serial.h"
+struct keyspan_pda_private {
+ int tx_room;
+ int tx_throttled;
+};
+
#define KEYSPAN_VENDOR_ID 0x06cd
#define KEYSPAN_PDA_FAKE_ID 0x0103
#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_open (struct usb_serial_port *port,
- struct file *filp);
-static void keyspan_pda_close (struct usb_serial_port *port,
- struct file *filp);
-static int keyspan_pda_startup (struct usb_serial *serial);
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
-static int keyspan_pda_write_room (struct usb_serial_port *port);
-static int keyspan_pda_write (struct usb_serial_port *port,
- int from_user,
- const unsigned char *buf,
- int count);
-static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
-static int keyspan_pda_ioctl (struct usb_serial_port *port,
- struct file *file,
- unsigned int cmd,
- unsigned long arg);
-static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old);
-static void keyspan_pda_break_ctl (struct usb_serial_port *port,
- int break_state);
-static int keyspan_pda_fake_startup (struct usb_serial *serial);
-
-
/* All of the device info needed for the Keyspan PDA serial converter */
static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
-struct usb_serial_device_type keyspan_pda_fake_device = {
- name: "Keyspan PDA - (prerenumeration)",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_pda_fake_startup
-};
-struct usb_serial_device_type keyspan_pda_device = {
- name: "Keyspan PDA",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
- needs_interrupt_in: MUST_HAVE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: 1,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- open: keyspan_pda_open,
- close: keyspan_pda_close,
- write: keyspan_pda_write,
- write_room: keyspan_pda_write_room,
- write_bulk_callback: keyspan_pda_write_bulk_callback,
- chars_in_buffer: keyspan_pda_chars_in_buffer,
- throttle: keyspan_pda_rx_throttle,
- unthrottle: keyspan_pda_rx_unthrottle,
- startup: keyspan_pda_startup,
- ioctl: keyspan_pda_ioctl,
- set_termios: keyspan_pda_set_termios,
- break_ctl: keyspan_pda_break_ctl,
-};
+
static void keyspan_pda_rx_interrupt (struct urb *urb)
@@ -133,6 +75,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* the urb might have been killed. */
if (urb->status)
@@ -167,8 +111,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
break;
case 2: /* tx unthrottle interrupt */
tty = serial->port[0].tty;
- serial->tx_throttled = 0;
- wake_up(&serial->write_wait); /* wake up writer */
+ priv->tx_throttled = 0;
+ wake_up(&port->write_wait); /* wake up writer */
wake_up(&tty->write_wait); /* them too */
break;
default:
@@ -193,7 +137,7 @@ static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
upon the device too. */
dbg("keyspan_pda_rx_throttle port %d", port->number);
- usb_unlink_urb(port->read_urb);
+ usb_unlink_urb(port->interrupt_in_urb);
}
@@ -201,7 +145,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
{
/* just restart the receive interrupt URB */
dbg("keyspan_pda_rx_unthrottle port %d", port->number);
- if (usb_submit_urb(port->read_urb))
+ if (usb_submit_urb(port->interrupt_in_urb))
dbg(" usb_submit_urb(read urb) failed");
return;
}
@@ -409,8 +353,10 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
struct usb_serial *serial = port->serial;
int request_unthrottle = 0;
int rc = 0;
+ struct keyspan_pda_private *priv;
DECLARE_WAITQUEUE(wait, current);
+ priv = (struct keyspan_pda_private *)(port->private);
/* guess how much room is left in the device's ring buffer, and if we
want to send more than that, check first, updating our notion of
what is left. If our write will result in no room left, ask the
@@ -419,7 +365,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
select() or poll() too) until we receive that unthrottle interrupt.
Block if we can't write anything at all, otherwise write as much as
we can. */
-
+ dbg("keyspan_pda_write(%d)",count);
if (count == 0) {
dbg(" write request of 0 bytes");
return (0);
@@ -434,7 +380,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
rc = -EAGAIN;
goto err;
}
- interruptible_sleep_on(&serial->write_wait);
+ interruptible_sleep_on(&port->write_wait);
if (signal_pending(current)) {
rc = -ERESTARTSYS;
goto err;
@@ -451,16 +397,16 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
have to be careful to avoid a race that would cause us to sleep
forever. */
- add_wait_queue(&serial->write_wait, &wait);
+ add_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- while (serial->tx_throttled) {
+ while (priv->tx_throttled) {
/* device can't accomodate any more characters. Sleep until it
can. Woken up by an Rx interrupt message, which clears
tx_throttled first. */
dbg(" tx_throttled, going to sleep");
if (signal_pending(current)) {
current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
dbg(" woke up because of signal");
rc = -ERESTARTSYS;
goto err;
@@ -468,11 +414,11 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
schedule();
dbg(" woke up");
}
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_RUNNING);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count > serial->tx_room) {
+ if (count > priv->tx_room) {
unsigned char room;
/* Looks like we might overrun the Tx buffer. Ask the device
how much room it really has */
@@ -495,15 +441,15 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
return -EIO; /* device didn't return any data */
}
dbg(" roomquery says %d", room);
- serial->tx_room = room;
- if (count > serial->tx_room) {
+ priv->tx_room = room;
+ if (count > priv->tx_room) {
/* we're about to completely fill the Tx buffer, so
we'll be throttled afterwards. */
- count = serial->tx_room;
+ count = priv->tx_room;
request_unthrottle = 1;
}
}
- serial->tx_room -= count;
+ priv->tx_room -= count;
if (count) {
/* now transfer data */
@@ -529,7 +475,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
dbg(" request_unthrottle");
/* ask the device to tell us when the tx buffer becomes
sufficiently empty */
- serial->tx_throttled = 1; /* block writers */
+ priv->tx_throttled = 1; /* block writers */
rc = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
7, /* request_unthrottle */
@@ -563,7 +509,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
return;
}
- wake_up_interruptible(&serial->write_wait);
+ wake_up_interruptible(&port->write_wait);
tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -576,23 +522,25 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
static int keyspan_pda_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* used by n_tty.c for processing of tabs and such. Giving it our
conservative guess is probably good enough, but needs testing by
running a console through the device. */
- return (serial->tx_room);
+ return (priv->tx_room);
}
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if (serial->tx_throttled)
+ if (priv->tx_throttled)
return 256;
return 0;
}
@@ -603,6 +551,8 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
unsigned char room;
int rc;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
if (port->active) {
return -EINVAL;
@@ -627,8 +577,8 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
dbg(" roomquery returned 0 bytes");
return -EIO; /* device didn't return any data */
}
- serial->tx_room = room;
- serial->tx_throttled = room ? 0 : 1;
+ priv->tx_room = room;
+ priv->tx_throttled = room ? 0 : 1;
/* the normal serial device seems to always turn on DTR and RTS here,
so do the same */
@@ -638,7 +588,7 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
keyspan_pda_set_modem_info(serial, 0);
/*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
+ if (usb_submit_urb(port->interrupt_in_urb))
dbg(" usb_submit_urb(read int) failed");
return (0);
@@ -655,7 +605,7 @@ static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
/* shutdown our bulk reads and writes */
usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
port->active = 0;
}
@@ -691,27 +641,63 @@ static int keyspan_pda_fake_startup (struct usb_serial *serial)
return (1);
}
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
static int keyspan_pda_startup (struct usb_serial *serial)
{
- struct usb_endpoint_descriptor *intin;
- intin = serial->port[0].interrupt_in_endpoint;
-
- /* set up the receive interrupt urb */
- FILL_INT_URB(serial->port[0].read_urb, serial->dev,
- usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
- serial->port[0].interrupt_in_buffer,
- intin->wMaxPacketSize,
- keyspan_pda_rx_interrupt,
- serial,
- intin->bInterval);
-
- init_waitqueue_head(&serial->write_wait);
-
+ /* allocate the private data structures for all ports. Well, for all
+ one ports. */
+
+ serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private),
+ GFP_KERNEL);
+ if (!serial->port[0].private)
+ return (1); /* error */
+ init_waitqueue_head(&serial->port[0].write_wait);
return (0);
}
-#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+static void keyspan_pda_shutdown (struct usb_serial *serial)
+{
+ kfree(serial->port[0].private);
+}
+struct usb_serial_device_type keyspan_pda_fake_device = {
+ name: "Keyspan PDA - (prerenumeration)",
+ idVendor: &keyspan_vendor_id,
+ idProduct: &keyspan_pda_fake_product_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: DONT_CARE,
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: keyspan_pda_fake_startup,
+};
+struct usb_serial_device_type keyspan_pda_device = {
+ name: "Keyspan PDA",
+ idVendor: &keyspan_vendor_id,
+ idProduct: &keyspan_pda_product_id,
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 0,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: keyspan_pda_open,
+ close: keyspan_pda_close,
+ write: keyspan_pda_write,
+ write_room: keyspan_pda_write_room,
+ write_bulk_callback: keyspan_pda_write_bulk_callback,
+ read_int_callback: keyspan_pda_rx_interrupt,
+ chars_in_buffer: keyspan_pda_chars_in_buffer,
+ throttle: keyspan_pda_rx_throttle,
+ unthrottle: keyspan_pda_rx_unthrottle,
+ ioctl: keyspan_pda_ioctl,
+ set_termios: keyspan_pda_set_termios,
+ break_ctl: keyspan_pda_break_ctl,
+ startup: keyspan_pda_startup,
+ shutdown: keyspan_pda_shutdown,
+};
+
+#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
new file mode 100644
index 000000000..2edcb6e86
--- /dev/null
+++ b/drivers/usb/serial/omninet.c
@@ -0,0 +1,339 @@
+/*
+ * USB ZyXEL omni.net LCD PLUS 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 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_OMNINET
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) )
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+
+#define ZYXEL_VENDOR_ID 0x0586
+#define ZYXEL_OMNINET_ID 0x1000
+
+/* function prototypes */
+static int omninet_open (struct usb_serial_port *port, struct file *filp);
+static void omninet_close (struct usb_serial_port *port, struct file *filp);
+static void omninet_read_bulk_callback (struct urb *urb);
+static void omninet_write_bulk_callback (struct urb *urb);
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int omninet_write_room (struct usb_serial_port *port);
+
+/* All of the device info needed for the omni.net */
+static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID;
+static __u16 zyxel_omninet_product_id = ZYXEL_OMNINET_ID;
+
+struct usb_serial_device_type zyxel_omninet_device = {
+ name: "ZyXEL - omni.net lcd plus usb",
+ idVendor: &zyxel_vendor_id,
+ idProduct: &zyxel_omninet_product_id,
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 2,
+ num_ports: 1,
+ open: omninet_open,
+ close: omninet_close,
+ write: omninet_write,
+ write_room: omninet_write_room,
+ read_bulk_callback: omninet_read_bulk_callback,
+ write_bulk_callback: omninet_write_bulk_callback,
+};
+
+
+/* The protocol.
+ *
+ * The omni.net always exchange 64 bytes of data with the host. The first
+ * four bytes are the control header, you can see it in the above structure.
+ *
+ * oh_seq is a sequence number. Don't know if/how it's used.
+ * oh_len is the length of the data bytes in the packet.
+ * oh_xxx Bit-mapped, related to handshaking and status info.
+ * I normally set it to 0x03 in trasmitted frames.
+ * 7: Active when the TA is in a CONNECTed state.
+ * 6: unknown
+ * 5: handshaking, unknown
+ * 4: handshaking, unknown
+ * 3: unknown, usually 0
+ * 2: unknown, usually 0
+ * 1: handshaking, unknown, usually set to 1 in trasmitted frames
+ * 0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * oh_pad Probably a pad byte.
+ *
+ * After the header you will find data bytes if oh_len was greater than zero.
+ *
+ */
+
+struct omninet_header
+{
+ __u8 oh_seq;
+ __u8 oh_len;
+ __u8 oh_xxx;
+ __u8 oh_pad;
+};
+
+struct omninet_data
+{
+ __u8 od_outseq; // Sequence number for bulk_out URBs
+};
+
+static int omninet_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+ struct omninet_data *od;
+
+ dbg("omninet_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+
+ if( !od )
+ {
+ err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data));
+ return -ENOMEM;
+ }
+
+ port->private = od;
+
+ /* Start reading from the device */
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb);
+
+ wport->tty = port->tty;
+
+ return (0);
+}
+
+static void omninet_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+ struct omninet_data *od = (struct omninet_data *) port->private;
+
+ port->active = 0;
+
+
+ dbg("zyxel_close port %d", port->number);
+
+ usb_unlink_urb (wport->write_urb);
+ usb_unlink_urb (port->read_urb);
+
+ if(od) kfree(od);
+}
+
+
+#define OMNINET_DATAOFFSET 0x04
+#define OMNINET_HEADERLEN sizeof(struct omninet_header)
+#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
+
+static void omninet_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+
+ unsigned char *data = urb->transfer_buffer;
+ struct omninet_header *header = (struct omninet_header *) &data[0];
+
+ int i;
+
+// dbg("omninet_read_bulk_callback");
+
+ if (port_paranoia_check (port, "omninet_read_bulk_callback")) {
+ return;
+ }
+
+ if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if(header->oh_xxx != 0x30)
+ {
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
+ for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+ }
+#endif
+
+ if (urb->actual_length && header->oh_len)
+ {
+ for (i = 0; i < header->oh_len; i++) {
+ tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
+ }
+ tty_flip_buffer_push(port->tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+}
+
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+
+ struct omninet_data *od = (struct omninet_data *) port->private;
+ struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer;
+/*
+#ifdef DEBUG
+ int i;
+#endif
+*/
+
+// dbg("omninet_write port %d", port->number);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+/*
+#ifdef DEBUG
+ printk (KERN_DEBUG __FILE__ ": omninet_write %d: ", count);
+ for (i = 0; i < count; i++) {
+ if( isalpha(buf[i]) )
+ printk ("%c ", buf[i]);
+ else
+ printk ("%.2x ", buf[i]);
+ }
+ printk ("\n");
+#endif
+*/
+ if (wport->write_urb->status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+
+ if (from_user) {
+ copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+ }
+ else {
+ memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+ }
+
+
+ header->oh_seq = od->od_outseq++;
+ header->oh_len = count;
+ header->oh_xxx = 0x03;
+ header->oh_pad = 0x00;
+
+ /* send the data out the bulk port, always 64 bytes */
+ wport->write_urb->transfer_buffer_length = 64;
+
+ if (usb_submit_urb(wport->write_urb))
+ dbg("usb_submit_urb(write bulk) failed");
+
+// dbg("omninet_write returns %d", count);
+
+ return (count);
+}
+
+
+static int omninet_write_room (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+
+ int room = 0; // Default: no room
+
+ if (wport->write_urb->status != -EINPROGRESS)
+ room = wport->bulk_out_size - OMNINET_HEADERLEN;
+
+// dbg("omninet_write_room returns %d", room);
+
+ return (room);
+}
+
+static void omninet_write_bulk_callback (struct urb *urb)
+{
+/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+
+// dbg("omninet_write_bulk_callback, port %0x\n", port);
+
+
+ if (port_paranoia_check (port, "omninet_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ tty = port->tty;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+// dbg("omninet_write_bulk_callback, tty %0x\n", tty);
+
+ return;
+}
+
+#endif /* CONFIG_USB_SERIAL_OMNINET */
+
+
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 6211a6309..8991f4be9 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -39,10 +39,8 @@ struct usb_serial_port {
unsigned char number;
char active; /* someone has this device open */
- struct usb_endpoint_descriptor * interrupt_in_endpoint;
- __u8 interrupt_in_interval;
unsigned char * interrupt_in_buffer;
- struct urb * control_urb;
+ struct urb * interrupt_in_urb;
unsigned char * bulk_in_buffer;
struct urb * read_urb;
@@ -50,7 +48,10 @@ struct usb_serial_port {
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
- void * private; /* data private to the specific driver */
+
+ wait_queue_head_t write_wait;
+
+ void * private; /* data private to the specific port */
};
struct usb_serial {
@@ -65,11 +66,6 @@ struct usb_serial {
char num_bulk_out; /* number of bulk out endpoints we have */
struct usb_serial_port port[MAX_NUM_PORTS];
- /* FIXME! These should move to the private area of the keyspan driver */
- int tx_room;
- int tx_throttled;
- wait_queue_head_t write_wait;
-
void * private; /* data private to the specific driver */
};
@@ -99,7 +95,8 @@ struct usb_serial_device_type {
/* function call to make before accepting driver */
int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
-
+ void (*shutdown) (struct usb_serial *serial);
+
/* serial function calls */
int (*open) (struct usb_serial_port *port, struct file * filp);
void (*close) (struct usb_serial_port *port, struct file * filp);
@@ -111,7 +108,8 @@ struct usb_serial_device_type {
int (*chars_in_buffer) (struct usb_serial_port *port);
void (*throttle) (struct usb_serial_port *port);
void (*unthrottle) (struct usb_serial_port *port);
-
+
+ void (*read_int_callback)(struct urb *urb);
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
};
@@ -124,6 +122,7 @@ extern struct usb_serial_device_type whiteheat_device;
extern struct usb_serial_device_type ftdi_sio_device;
extern struct usb_serial_device_type keyspan_pda_fake_device;
extern struct usb_serial_device_type keyspan_pda_device;
+extern struct usb_serial_device_type zyxel_omninet_device;
/* determine if we should include the EzUSB loader functions */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 0c1972675..588fed5d1 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,14 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (04/23/2000) gkh
+ * Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+ * Moved when the startup code printed out the devices that are supported.
+ *
+ * (04/19/2000) gkh
+ * Added driver for ZyXEL omni.net lcd plus ISDN TA
+ * Made startup info message specify which drivers were compiled in.
+ *
* (04/03/2000) gkh
* Changed the probe process to remove the module unload races.
* Changed where the tty layer gets initialized to have devfs work nicer.
@@ -211,6 +219,7 @@ MODULE_DESCRIPTION("USB Serial Driver");
#include "usb-serial.h"
+#define MAX(a,b) (((a)>(b))?(a):(b))
/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
/* need to always compile these in, as some of the other devices use these functions as their own. */
@@ -270,6 +279,9 @@ static struct usb_serial_device_type *usb_serial_devices[] = {
&keyspan_pda_fake_device,
&keyspan_pda_device,
#endif
+#ifdef CONFIG_USB_SERIAL_OMNINET
+ &zyxel_omninet_device,
+#endif
NULL
};
@@ -424,14 +436,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
return -ENODEV;
}
- /* set up our port structure */
+ /* set up our port structure making the tty driver remember our port object, and us it */
portNumber = MINOR(tty->device) - serial->minor;
port = &serial->port[portNumber];
- port->number = portNumber;
- port->serial = serial;
- port->magic = USB_SERIAL_PORT_MAGIC;
-
- /* make the tty driver remember our port object, and us it */
tty->driver_data = port;
port->tty = tty;
@@ -996,236 +1003,248 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
int num_bulk_in = 0;
int num_bulk_out = 0;
int num_ports;
+ int max_endpoints;
- /* loop through our list of known serial converters, and see if this device matches */
- device_num = 0;
- while (usb_serial_devices[device_num] != NULL) {
+ /* loop through our list of known serial converters, and see if this
+ device matches. */
+ for (device_num = 0; usb_serial_devices[device_num]; device_num++) {
type = usb_serial_devices[device_num];
- dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+ dbg ("Looking at %s Vendor id=%.4x Product id=%.4x",
+ type->name, *(type->idVendor), *(type->idProduct));
/* look at the device descriptor */
if ((dev->descriptor.idVendor == *(type->idVendor)) &&
(dev->descriptor.idProduct == *(type->idProduct))) {
+ dbg("descriptor matches");
+ break;
+ }
+ }
+ if (!usb_serial_devices[device_num]) {
+ /* no match */
+ dbg("none matched");
+ return(NULL);
+ }
- dbg("descriptor matches...looking at the endpoints");
-
- /* descriptor matches, let's try to find the endpoints needed */
- interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+ /* descriptor matches, let's find the endpoints needed */
+ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
- /* check out the endpoints */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- for (i = 0; i < interface->bNumEndpoints; ++i) {
- endpoint = &interface->endpoint[i];
+ /* check out the endpoints */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ for (i = 0; i < interface->bNumEndpoints; ++i) {
+ endpoint = &interface->endpoint[i];
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in");
- bulk_in_pipe = HAS;
- bulk_in_endpoint[num_bulk_in] = endpoint;
- ++num_bulk_in;
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out");
- bulk_out_pipe = HAS;
- bulk_out_endpoint[num_bulk_out] = endpoint;
- ++num_bulk_out;
- }
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
- /* we found a interrupt in endpoint */
- dbg("found interrupt in");
- interrupt_pipe = HAS;
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
- ++num_interrupt_in;
- }
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+ bulk_in_pipe = HAS;
+ bulk_in_endpoint[num_bulk_in] = endpoint;
+ ++num_bulk_in;
+ }
- }
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ bulk_out_pipe = HAS;
+ bulk_out_endpoint[num_bulk_out] = endpoint;
+ ++num_bulk_out;
+ }
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x03)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+ interrupt_pipe = HAS;
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+ ++num_interrupt_in;
+ }
+ }
- /* verify that we found all of the endpoints that we need */
- if ((interrupt_pipe & type->needs_interrupt_in) &&
- (bulk_in_pipe & type->needs_bulk_in) &&
- (bulk_out_pipe & type->needs_bulk_out)) {
- /* found all that we need */
- MOD_INC_USE_COUNT;
- info("%s converter detected", type->name);
+ /* verify that we found all of the endpoints that we need */
+ if (!((interrupt_pipe & type->needs_interrupt_in) &&
+ (bulk_in_pipe & type->needs_bulk_in) &&
+ (bulk_out_pipe & type->needs_bulk_out))) {
+ /* nope, they don't match what we expected */
+ info("descriptors matched, but endpoints did not");
+ return NULL;
+ }
+
+ /* found all that we need */
+ MOD_INC_USE_COUNT;
+ info("%s converter detected", type->name);
#ifdef CONFIG_USB_SERIAL_GENERIC
- if (type == &generic_device)
- num_ports = num_bulk_out;
- else
-#endif
- num_ports = type->num_ports;
-
- serial = get_free_serial (num_ports, &minor);
- if (serial == NULL) {
- err("No more free serial devices");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- serial->dev = dev;
- serial->type = type;
- serial->minor = minor;
- serial->num_ports = num_ports;
- serial->num_bulk_in = num_bulk_in;
- serial->num_bulk_out = num_bulk_out;
- serial->num_interrupt_in = num_interrupt_in;
-
- /* initialize a tty_driver for this device */
- serial->tty_driver = usb_serial_tty_driver_init (serial);
- if (serial->tty_driver == NULL) {
- err("Can't create a tty_serial_driver");
- goto probe_error;
- }
-
- if (tty_register_driver (serial->tty_driver)) {
- err("failed to register tty driver");
- goto probe_error;
- }
-
- /* collect interrupt_in endpoints now, because
- the keyspan_pda startup function needs
- to know about them */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- port->interrupt_in_endpoint = interrupt_in_endpoint[i];
- }
-
- /* if this device type has a startup function, call it */
- if (type->startup) {
- if (type->startup (serial)) {
- goto probe_error;
- }
- }
-
- /* set up the endpoint information */
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- port->read_urb = usb_alloc_urb (0);
- if (!port->read_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
- port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->bulk_in_buffer) {
- err("Couldn't allocate bulk_in_buffer");
- goto probe_error;
- }
- if (serial->type->read_bulk_callback) {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
- }
- }
-
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- port->write_urb = usb_alloc_urb(0);
- if (!port->write_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
- port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
- if (!port->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- goto probe_error;
- }
- if (serial->type->write_bulk_callback) {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
- }
- }
-
-#if 0 /* use this code when WhiteHEAT is up and running */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- port->control_urb = usb_alloc_urb(0);
- if (!port->control_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
- port->interrupt_in_buffer, buffer_size, serial_control_irq,
- port, interrupt_in_endpoint[i]->bInterval);
- }
+ if (type == &generic_device) {
+ num_ports = num_bulk_out;
+ if (num_ports == 0) {
+ err("Generic device with no bulk out, not allowed.");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ } else
#endif
+ num_ports = type->num_ports;
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
- }
+ serial = get_free_serial (num_ports, &minor);
+ if (serial == NULL) {
+ err("No more free serial devices");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ serial->dev = dev;
+ serial->type = type;
+ serial->minor = minor;
+ serial->num_ports = num_ports;
+ serial->num_bulk_in = num_bulk_in;
+ serial->num_bulk_out = num_bulk_out;
+ serial->num_interrupt_in = num_interrupt_in;
+
+ /* initialize a tty_driver for this device */
+ serial->tty_driver = usb_serial_tty_driver_init (serial);
+ if (serial->tty_driver == NULL) {
+ err("Can't create a tty_serial_driver");
+ goto probe_error;
+ }
- return serial;
- } else {
- info("descriptors matched, but endpoints did not");
- }
+ if (tty_register_driver (serial->tty_driver)) {
+ err("failed to register tty driver");
+ goto probe_error;
+ }
+
+ /* if this device type has a startup function, call it */
+ if (type->startup) {
+ if (type->startup (serial)) {
+ goto probe_error;
}
-
- /* look at the next type in our list */
- ++device_num;
}
-probe_error:
- if (serial) {
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- if (port->read_urb)
- usb_free_urb (port->read_urb);
- if (serial->port[i].bulk_in_buffer[i])
- kfree (serial->port[i].bulk_in_buffer);
+ /* set up the endpoint information */
+ for (i = 0; i < num_bulk_in; ++i) {
+ endpoint = bulk_in_endpoint[i];
+ port = &serial->port[i];
+ port->read_urb = usb_alloc_urb (0);
+ if (!port->read_urb) {
+ err("No free urbs available");
+ goto probe_error;
}
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- if (port->write_urb)
- usb_free_urb (port->write_urb);
- if (serial->port[i].bulk_out_buffer)
- kfree (serial->port[i].bulk_out_buffer);
+ buffer_size = endpoint->wMaxPacketSize;
+ port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->bulk_in_buffer) {
+ err("Couldn't allocate bulk_in_buffer");
+ goto probe_error;
}
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- if (port->control_urb)
- usb_free_urb (port->control_urb);
- if (serial->port[i].interrupt_in_buffer)
- kfree (serial->port[i].interrupt_in_buffer);
+ FILL_BULK_URB(port->read_urb, dev,
+ usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size,
+ ((serial->type->read_bulk_callback) ?
+ serial->type->read_bulk_callback :
+ generic_read_bulk_callback),
+ port);
+ }
+
+ for (i = 0; i < num_bulk_out; ++i) {
+ endpoint = bulk_out_endpoint[i];
+ port = &serial->port[i];
+ port->write_urb = usb_alloc_urb(0);
+ if (!port->write_urb) {
+ err("No free urbs available");
+ goto probe_error;
}
-
- /* return the minor range that this device had */
- return_serial (serial);
+ buffer_size = endpoint->wMaxPacketSize;
+ port->bulk_out_size = buffer_size;
+ port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->bulk_out_buffer) {
+ err("Couldn't allocate bulk_out_buffer");
+ goto probe_error;
+ }
+ FILL_BULK_URB(port->write_urb, dev,
+ usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
+ port->bulk_out_buffer, buffer_size,
+ ((serial->type->write_bulk_callback) ?
+ serial->type->write_bulk_callback :
+ generic_write_bulk_callback),
+ port);
+ }
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
+ for (i = 0; i < num_interrupt_in; ++i) {
+ endpoint = interrupt_in_endpoint[i];
+ port = &serial->port[i];
+ port->interrupt_in_urb = usb_alloc_urb(0);
+ if (!port->interrupt_in_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ buffer_size = endpoint->wMaxPacketSize;
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
+ err("Couldn't allocate interrupt_in_buffer");
+ goto probe_error;
}
+ FILL_INT_URB(port->interrupt_in_urb, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ port->interrupt_in_buffer, buffer_size,
+ serial->type->read_int_callback,
+ port,
+ endpoint->bInterval);
+ }
- /* free up any memory that we allocated */
- kfree (serial);
- MOD_DEC_USE_COUNT;
+ /* initialize some parts of the port structures */
+ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
+ max_endpoints = MAX(num_bulk_in, num_bulk_out);
+ max_endpoints = MAX(max_endpoints, num_interrupt_in);
+ for (i = 0; i < max_endpoints; ++i) {
+ port = &serial->port[i];
+ port->number = i;
+ port->serial = serial;
+ port->magic = USB_SERIAL_PORT_MAGIC;
+ }
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now attached to ttyUSB%d",
+ type->name, serial->minor + i);
+ }
+
+ return serial; /* success */
+
+
+probe_error:
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb)
+ usb_free_urb (port->read_urb);
+ if (port->bulk_in_buffer)
+ kfree (port->bulk_in_buffer);
+ }
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb)
+ usb_free_urb (port->write_urb);
+ if (port->bulk_out_buffer)
+ kfree (port->bulk_out_buffer);
+ }
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->interrupt_in_urb)
+ usb_free_urb (port->interrupt_in_urb);
+ if (port->interrupt_in_buffer)
+ kfree (port->interrupt_in_buffer);
+ }
+
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
}
+
+ /* free up any memory that we allocated */
+ kfree (serial);
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -1237,6 +1256,9 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int i;
if (serial) {
+ if (serial->type->shutdown)
+ serial->type->shutdown(serial);
+
for (i = 0; i < serial->num_ports; ++i)
serial->port[i].active = 0;
@@ -1260,9 +1282,9 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
- if (port->control_urb) {
- usb_unlink_urb (port->control_urb);
- usb_free_urb (port->control_urb);
+ if (port->interrupt_in_urb) {
+ usb_unlink_urb (port->interrupt_in_urb);
+ usb_free_urb (port->interrupt_in_urb);
}
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
@@ -1295,18 +1317,32 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int usb_serial_init(void)
{
int i;
+ int something;
+ int result;
/* Initalize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
+ /* tell the world what devices this driver currently supports */
+ something = 0;
+ for (i = 0; usb_serial_devices[i]; ++i) {
+ if (!strstr (usb_serial_devices[i]->name, "prerenumeration")) {
+ info ("USB Serial support registered for %s", usb_serial_devices[i]->name);
+ something = 1;
+ }
+ }
+ if (!something)
+ info ("USB Serial driver is not configured for any devices!");
+
/* register the USB driver */
- if (usb_register(&usb_serial_driver) < 0) {
+ result = usb_register(&usb_serial_driver);
+ if (result < 0) {
+ err("usb_register failed for the usb-serial driver. Error number %d", result);
return -1;
}
-
- info("support registered");
+
return 0;
}
diff --git a/drivers/usb/uhci-debug.h b/drivers/usb/uhci-debug.h
index 61b14ba40..12ebbb844 100644
--- a/drivers/usb/uhci-debug.h
+++ b/drivers/usb/uhci-debug.h
@@ -14,7 +14,7 @@
#include "uhci.h"
-void uhci_show_td(struct uhci_td * td)
+void uhci_show_td(struct uhci_td *td)
{
char *spid;
@@ -129,6 +129,62 @@ struct uhci_td *uhci_link_to_td(unsigned int link)
return bus_to_virt(link & ~UHCI_PTR_BITS);
}
+void uhci_show_urb_queue(struct urb *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct list_head *head, *tmp;
+ int i, checked = 0, prevactive = 0;
+
+ printk(" URB [%p] urbp [%p]\n", urb, urbp);
+
+ if (urbp->qh)
+ printk(" QH [%p]\n", urbp->qh);
+ else
+ printk(" QH [%p] element (%08x) link (%08x)\n", urbp->qh,
+ urbp->qh->element, urbp->qh->link);
+
+ i = 0;
+
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
+ printk(" td %d: [%p]\n", i++, td);
+ printk(" ");
+ uhci_show_td(td);
+
+ if (i > 10 && !checked && prevactive && tmp != head) {
+ struct list_head *ntmp = tmp;
+ struct uhci_td *ntd = td;
+ int active = 1, ni = i;
+
+ checked = 1;
+
+ while (ntmp != head && ntmp->next != head && active) {
+ ntd = list_entry(ntmp, struct uhci_td, list);
+
+ ntmp = ntmp->next;
+
+ active = ntd->status & TD_CTRL_ACTIVE;
+
+ ni++;
+ }
+
+ if (active && ni > i) {
+ printk(" [skipped %d active TD's]\n", ni - i);
+ tmp = ntmp;
+ td = ntd;
+ i = ni;
+ }
+ }
+
+ prevactive = td->status & TD_CTRL_ACTIVE;
+ }
+}
+
void uhci_show_queue(struct uhci_qh *qh)
{
struct uhci_td *td, *first;
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 2fa4e30b6..d64672049 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -284,42 +284,6 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
prevtd->link = UHCI_PTR_TERM;
}
-/* This function will append one URB's QH to another URB's QH. This is for */
-/* USB_QUEUE_BULK support */
-static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb)
-{
- struct urb *nurb;
- struct urb_priv *eurbp, *urbp, *nurbp;
- struct list_head *tmp;
- struct uhci_td *td, *ntd;
- unsigned long flags;
-
- eurbp = eurb->hcpriv;
- urbp = urb->hcpriv;
-
- spin_lock_irqsave(&eurb->lock, flags);
-
- /* Grab the last URB in the queue */
- tmp = eurbp->urb_queue_list.prev;
-
- /* Add this one to the end */
- list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list);
-
- spin_unlock_irqrestore(&eurb->lock, flags);
-
- nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
- nurb = nurbp->urb;
-
- tmp = nurbp->list.prev;
- td = list_entry(tmp, struct uhci_td, list);
-
- tmp = urbp->list.next;
- ntd = list_entry(tmp, struct uhci_td, list);
-
- /* No breadth since this will only be called for bulk transfers */
- td->link = virt_to_bus(ntd);
-}
-
static void uhci_free_td(struct uhci_td *td)
{
if (!list_empty(&td->list))
@@ -395,6 +359,7 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
if (qh->nextqh)
qh->nextqh->prevqh = qh->prevqh;
qh->prevqh = qh->nextqh = NULL;
+ qh->element = qh->link = UHCI_PTR_TERM;
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
if (delayed) {
@@ -413,6 +378,101 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
uhci_free_qh(qh);
}
+static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* USB_QUEUE_BULK support */
+static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+ struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+ struct list_head *tmp;
+ struct uhci_td *td, *ltd;
+ unsigned long flags;
+
+ eurbp = eurb->hcpriv;
+ urbp = urb->hcpriv;
+
+ spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+ /* Find the beginning URB in the queue */
+ if (eurbp->queued) {
+ struct list_head *head = &eurbp->urb_queue_list;
+
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb_priv *turbp =
+ list_entry(tmp, struct urb_priv, urb_queue_list);
+
+ tmp = tmp->next;
+
+ if (!turbp->queued)
+ break;
+ }
+ } else
+ tmp = &eurbp->urb_queue_list;
+
+ furbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+ tmp = furbp->urb_queue_list.prev;
+ lurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+ /* Add this one to the end */
+ list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list);
+
+ /* Grab the last TD from the last URB */
+ ltd = list_entry(lurbp->list.prev, struct uhci_td, list);
+
+ /* Grab the first TD from the first URB */
+ td = list_entry(urbp->list.next, struct uhci_td, list);
+
+ /* No breadth since this will only be called for bulk transfers */
+ ltd->link = virt_to_bus(td);
+
+ spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+}
+
+static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp, *nurbp;
+ unsigned long flags;
+
+ urbp = urb->hcpriv;
+
+ spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+ nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv,
+ urb_queue_list);
+
+ if (!urbp->queued) {
+ /* We're the head, so just insert the QH for the next URB */
+ uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+ nurbp->queued = 0;
+ } else {
+ struct urb_priv *purbp;
+ struct uhci_td *ptd;
+
+ /* We're somewhere in the middle (or end). A bit trickier */
+ /* than the head scenario */
+ purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv,
+ urb_queue_list);
+
+ ptd = list_entry(purbp->list.prev, struct uhci_td, list);
+ if (nurbp->queued)
+ /* Close the gap between the two */
+ ptd->link = virt_to_bus(list_entry(nurbp->list.next,
+ struct uhci_td, list));
+ else
+ /* The next URB happens to be the beggining, so */
+ /* we're the last, end the chain */
+ ptd->link = UHCI_PTR_TERM;
+
+ }
+
+ list_del(&urbp->urb_queue_list);
+
+ spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
+}
+
struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
{
struct urb_priv *urbp;
@@ -491,11 +551,6 @@ static void uhci_destroy_urb_priv(struct urb *urb)
uhci_free_td(td);
}
- if (!list_empty(&urbp->urb_queue_list)) {
- list_del(&urbp->urb_queue_list);
- INIT_LIST_HEAD(&urbp->urb_queue_list);
- }
-
urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
@@ -672,12 +727,10 @@ static int uhci_submit_control(struct urb *urb)
if (urb->pipe & TD_CTRL_LS) {
uhci_insert_tds_in_qh(qh, urb, 0);
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
- urbp->queued = 0;
} else {
uhci_insert_tds_in_qh(qh, urb, 1);
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
uhci_inc_fsbr(uhci, urb);
- urbp->queued = 0;
}
urbp->qh = qh;
@@ -697,18 +750,21 @@ static int uhci_result_control(struct urb *urb)
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
unsigned int status;
+ int ret = 0;
if (!urbp)
return -EINVAL;
head = &urbp->list;
- tmp = head->next;
- if (head == tmp)
+ if (head->next == head)
return -EINVAL;
- if (urbp->short_control_packet)
+ if (urbp->short_control_packet) {
+ tmp = head->prev;
goto status_phase;
+ }
+ tmp = head->next;
td = list_entry(tmp, struct uhci_td, list);
/* The first TD is the SETUP phase, check the status, but skip */
@@ -729,20 +785,34 @@ static int uhci_result_control(struct urb *urb)
tmp = tmp->next;
+ if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+ !(td->status & TD_CTRL_ACTIVE)) {
+ uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+ urbp->fsbr_timeout = 0;
+ td->status &= ~TD_CTRL_IOC;
+ }
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
urb->actual_length += uhci_actual_length(td->status);
- /* If SPD is set then we received a short packet */
- /* There will be no status phase at the end */
- if ((td->status & TD_CTRL_SPD) &&
- (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
- return usb_control_retrigger_status(urb);
-
if (status)
goto td_error;
+
+ /* Check to see if we received a short packet */
+ if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+ if (urb->transfer_flags & USB_DISABLE_SPD) {
+ ret = -EREMOTEIO;
+ goto err;
+ }
+
+ if (uhci_packetid(td->info) == USB_PID_IN)
+ return usb_control_retrigger_status(urb);
+ else
+ return 0;
+ }
}
status_phase:
@@ -768,19 +838,22 @@ status_phase:
return 0;
td_error:
- if (status & TD_CTRL_STALLED)
+ ret = uhci_map_status(status, uhci_packetout(td->info));
+ if (ret == -EPIPE)
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info));
- else if (debug) {
+
+err:
+ if (debug && ret != -EPIPE) {
/* Some debugging code */
dbg("uhci_result_control() failed with status %x", status);
/* Print the chain for debugging purposes */
- uhci_show_queue(urbp->qh);
+ uhci_show_urb_queue(urb);
}
- return uhci_map_status(status, uhci_packetout(td->info));
+ return ret;
}
static int usb_control_retrigger_status(struct urb *urb)
@@ -823,7 +896,6 @@ static int usb_control_retrigger_status(struct urb *urb)
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
else
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
- urbp->queued = 0;
return -EINPROGRESS;
}
@@ -869,8 +941,9 @@ static int uhci_result_interrupt(struct urb *urb)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
- unsigned int status;
struct uhci_td *td;
+ unsigned int status;
+ int ret = 0;
if (!urbp)
return -EINVAL;
@@ -884,46 +957,58 @@ static int uhci_result_interrupt(struct urb *urb)
tmp = tmp->next;
+ if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+ !(td->status & TD_CTRL_ACTIVE)) {
+ uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+ urbp->fsbr_timeout = 0;
+ td->status &= ~TD_CTRL_IOC;
+ }
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
urb->actual_length += uhci_actual_length(td->status);
- /* If SPD is set then we received a short packet */
- if ((td->status & TD_CTRL_SPD) &&
- (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
+ if (status)
+ goto td_error;
+
+ if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
usb_settoggle(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info),
uhci_toggle(td->info) ^ 1);
- return 0;
+ if (urb->transfer_flags & USB_DISABLE_SPD) {
+ ret = -EREMOTEIO;
+ goto err;
+ } else
+ return 0;
}
-
- if (status)
- goto td_error;
}
return 0;
td_error:
- if (status & TD_CTRL_STALLED)
+ ret = uhci_map_status(status, uhci_packetout(td->info));
+ if (ret == -EPIPE)
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info));
- else if (debug) {
+
+err:
+ if (debug && ret != -EPIPE) {
/* Some debugging code */
dbg("uhci_result_interrupt/bulk() failed with status %x",
status);
/* Print the chain for debugging purposes */
if (urbp->qh)
- uhci_show_queue(urbp->qh);
+ uhci_show_urb_queue(urb);
else
uhci_show_td(td);
}
- return uhci_map_status(status, uhci_packetout(td->info));
+ return ret;
}
static void uhci_reset_interrupt(struct urb *urb)
@@ -974,6 +1059,7 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
/* 3 errors */
status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
+
if (!(urb->transfer_flags & USB_DISABLE_SPD))
status |= TD_CTRL_SPD;
@@ -1016,12 +1102,10 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
uhci_insert_tds_in_qh(qh, urb, 1);
if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
- uhci_append_urb_qh(uhci, eurb, urb);
urbp->queued = 1;
- } else {
+ uhci_append_queued_urb(uhci, eurb, urb);
+ } else
uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
- urbp->queued = 0;
- }
uhci_add_urb_list(uhci, urb);
@@ -1049,6 +1133,8 @@ static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigne
while (tmp != head) {
struct urb *u = list_entry(tmp, struct urb, urb_list);
+ tmp = tmp->next;
+
/* look for pending URB's with identical pipe handle */
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
(u->status == -EINPROGRESS) && (u != urb)) {
@@ -1056,7 +1142,6 @@ static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigne
*start = u->start_frame;
last_urb = u;
}
- tmp = tmp->next;
}
if (last_urb) {
@@ -1363,14 +1448,8 @@ static int uhci_unlink_generic(struct urb *urb)
/* The interrupt loop will reclaim the QH's */
uhci_remove_qh(uhci, urbp->qh);
- if (!list_empty(&urbp->urb_queue_list)) {
- struct list_head *tmp = urbp->urb_queue_list.next;
- struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
- if (nurbp->queued) {
- uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
- nurbp->queued = 0;
- }
- }
+ if (!list_empty(&urbp->urb_queue_list))
+ uhci_delete_queued_urb(uhci, urb);
uhci_destroy_urb_priv(urb);
@@ -1430,6 +1509,35 @@ static int uhci_unlink_urb(struct urb *urb)
return ret;
}
+static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct list_head *head, *tmp;
+
+ uhci_dec_fsbr(uhci, urb);
+
+ /* There is a race with updating IOC in here, but it's not worth */
+ /* trying to fix since this is merely an optimization. The only */
+ /* time we'd lose is if the status of the packet got updated */
+ /* and we'd be turning on FSBR next frame anyway, so it's a wash */
+ urbp->fsbr_timeout = 1;
+
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
+ if (td->status & TD_CTRL_ACTIVE) {
+ td->status |= TD_CTRL_IOC;
+ break;
+ }
+ }
+
+ return 0;
+}
+
/*
* uhci_get_current_frame_number()
*
@@ -1586,7 +1694,7 @@ static void rh_int_timer_do(unsigned long ptr)
if (urbp) {
/* Check if the FSBR timed out */
if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
- uhci_dec_fsbr(uhci, u);
+ uhci_fsbr_timeout(uhci, u);
/* Check if the URB timed out */
if (u->timeout && time_after(u->timeout, jiffies)) {
@@ -1762,7 +1870,7 @@ static int rh_submit_urb(struct urb *urb)
case RH_PORT_POWER:
OK(0); /* port power ** */
case RH_PORT_ENABLE:
- SET_RH_PORTSTAT (USBPORTSC_PE);
+ SET_RH_PORTSTAT(USBPORTSC_PE);
OK(0);
}
break;
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
index 83992bb6a..423f75309 100644
--- a/drivers/usb/uhci.h
+++ b/drivers/usb/uhci.h
@@ -339,10 +339,10 @@ struct urb_priv {
struct uhci_qh *qh; /* QH for this URB */
- int fsbr : 1; /* Did this URB turn on FSBR? */
- int queued : 1; /* 0 if QH was linked in */
-
- char short_control_packet; /* If we get a short packet during */
+ int fsbr : 1; /* URB turned on FSBR */
+ int fsbr_timeout : 1; /* URB timed out on FSBR */
+ int queued : 1; /* QH was queued (not linked in) */
+ int short_control_packet : 1; /* If we get a short packet during */
/* a control transfer, retrigger */
/* the status phase */
@@ -414,6 +414,7 @@ struct uhci_td *uhci_link_to_td(unsigned int element);
/* Debugging code */
void uhci_show_td(struct uhci_td *td);
void uhci_show_status(struct uhci *uhci);
+void uhci_show_urb_queue(struct urb *urb);
void uhci_show_queue(struct uhci_qh *qh);
void uhci_show_queues(struct uhci *uhci);
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index f42b96f61..f2e11fc28 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -28,6 +28,7 @@ void usb_major_cleanup(void);
* USB device drivers
*/
+int usb_cpia_init(void);
int usb_audio_init(void);
int usb_ibmcam_init(void);
int dabusb_init(void);
@@ -68,6 +69,9 @@ int usb_init(void)
usb_hub_init();
#ifndef CONFIG_USB_MODULE
+#ifdef CONFIG_VIDEO_CPIA_USB
+ usb_cpia_init();
+#endif
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 7c4a72c6d..9c9b38167 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -1555,7 +1555,7 @@ static int rh_submit_urb (urb_t * urb)
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff,
- (int) ohci->regs, "OHCI",
+ (int)(long) ohci->regs, "OHCI",
data, wLength);
if (len > 0) {
data_buf = data;
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index 7a3afe5c4..6ef0a97c4 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -74,42 +74,50 @@ struct us_data {
unsigned int flags; /* from filter initially */
- /* information about the device -- only good if device is attached */
- __u8 ifnum; /* interface number */
- __u8 ep_in; /* in endpoint */
- __u8 ep_out; /* out ....... */
- __u8 ep_int; /* interrupt . */
+ /* information about the device -- always good */
+ char vendor[32];
+ char product[32];
+ char serial[32];
+ char *transport_name;
+ char *protocol_name;
__u8 subclass;
__u8 protocol;
+ /* 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 */
+ __u8 ep_int; /* interrupt endpoint */
+ __u8 ep_interval; /* interrupt interval */
+
/* function pointers for this device */
- trans_cmnd transport; /* transport function */
+ trans_cmnd transport; /* transport function */
trans_reset transport_reset; /* transport device reset */
- proto_cmnd proto_handler; /* protocol handler */
+ proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */
- GUID(guid); /* unique dev id */
+ 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 */
+ 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 */
+ int action; /* what to do */
+ int pid; /* control thread */
- /* interrupt info for CBI devices */
- struct semaphore ip_waitq; /* for CBI interrupts */
- __u16 ip_data; /* interrupt data */
- int ip_wanted; /* needed */
+ /* interrupt info for CBI devices -- only good if attached */
+ struct semaphore ip_waitq; /* for CBI interrupts */
+ __u16 ip_data; /* interrupt data */
+ int ip_wanted; /* is an IRQ expected? */
void *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
/* mutual exclusion structures */
- struct semaphore notify; /* thread begin/end */
- struct semaphore sleeper; /* to sleep on */
+ struct semaphore notify; /* thread begin/end */
+ struct semaphore sleeper; /* to sleep the thread on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -118,11 +126,10 @@ struct us_data {
*/
#define US_ACT_COMMAND 1
-#define US_ACT_ABORT 2
-#define US_ACT_DEVICE_RESET 3
-#define US_ACT_BUS_RESET 4
-#define US_ACT_HOST_RESET 5
-#define US_ACT_EXIT 6
+#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 */
static struct us_data *us_list;
@@ -131,18 +138,15 @@ struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
static void storage_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver storage_driver = {
- "usb-storage",
- storage_probe,
- storage_disconnect,
- { NULL, NULL }
+ name: "usb-storage",
+ probe: storage_probe,
+ disconnect: storage_disconnect,
};
/***********************************************************************
* Data transfer routines
***********************************************************************/
-/* FIXME: the names of these functions are poorly choosen. */
-
/*
* Transfer one SCSI scatter-gather buffer via bulk transfer
*
@@ -154,15 +158,15 @@ static struct usb_driver storage_driver = {
* timeout limit. Thus we don't have to worry about it for individual
* packets.
*/
-static int us_bulk_transfer(struct us_data *us, int pipe,
- char *buf, int length)
+static int us_transfer_partial(struct us_data *us, int pipe,
+ char *buf, int length)
{
int result;
int partial;
/* transfer the data */
US_DEBUGP("Bulk xfer 0x%x(%d)\n", (unsigned int)buf, length);
- result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ*5);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ);
US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
result, partial, length);
@@ -181,7 +185,7 @@ static int us_bulk_transfer(struct us_data *us, int pipe,
if (result) {
/* NAK - that means we've retried a few times allready */
if (result == -ETIMEDOUT) {
- US_DEBUGP("us_bulk_transfer: device NAKed\n");
+ US_DEBUGP("us_transfer_partial(): device NAKed\n");
}
return US_BULK_TRANSFER_FAILED;
}
@@ -195,7 +199,7 @@ static int us_bulk_transfer(struct us_data *us, int pipe,
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
- * Note that this uses us_bulk_transfer to achive it's goals -- this
+ * 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.
*/
@@ -222,16 +226,16 @@ static void us_transfer(Scsi_Cmnd *srb, int dir_in)
*/
sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
- result = us_bulk_transfer(us, pipe, sg[i].address,
- sg[i].length);
+ result = us_transfer_partial(us, pipe, sg[i].address,
+ sg[i].length);
if (result)
break;
}
}
else
/* no scatter-gather, just make the request */
- result = us_bulk_transfer(us, pipe, srb->request_buffer,
- srb->request_bufflen);
+ result = us_transfer_partial(us, pipe, srb->request_buffer,
+ srb->request_bufflen);
/* return the result in the data structure itself */
srb->result = result;
@@ -240,12 +244,27 @@ static void us_transfer(Scsi_Cmnd *srb, int dir_in)
/* Calculate the length of the data transfer (not the command) for any
* given SCSI command
*/
-static unsigned int us_transfer_length(Scsi_Cmnd *srb)
+static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
{
int i;
unsigned int total = 0;
struct scatterlist *sg;
+ /* support those devices which need the length calculated
+ * differently
+ */
+ if (us->flags & US_FL_ALT_LENGTH) {
+ if (srb->cmnd[0] == INQUIRY) {
+ srb->cmnd[4] = 36;
+ }
+
+ if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
+ return srb->cmnd[4];
+
+ if (srb->cmnd[0] == TEST_UNIT_READY)
+ return 0;
+ }
+
/* Are we going to scatter gather? */
if (srb->use_sg) {
/* Add up the sizes of all the scatter-gather segments */
@@ -299,8 +318,10 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
*/
if (us->subclass == US_SC_UFI &&
((srb->cmnd[0] == REQUEST_SENSE) ||
- (srb->cmnd[0] == INQUIRY)))
+ (srb->cmnd[0] == INQUIRY))) {
+ US_DEBUGP("** no auto-sense for a special command\n");
need_auto_sense = 0;
+ }
}
/*
@@ -339,8 +360,13 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
int temp_result;
void* old_request_buffer;
int old_sg;
+ int old_request_bufflen;
+ unsigned char old_cmnd[MAX_COMMAND_SIZE];
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+ US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+
+ /* save the old command */
+ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
srb->cmnd[0] = REQUEST_SENSE;
srb->cmnd[1] = 0;
@@ -351,14 +377,24 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set the buffer length for transfer */
old_request_buffer = srb->request_buffer;
+ old_request_bufflen = srb->request_bufflen;
old_sg = srb->use_sg;
+ srb->use_sg = 0;
srb->request_bufflen = 18;
- srb->request_buffer = us->srb->sense_buffer;
+ srb->request_buffer = srb->sense_buffer;
- /* FIXME: what if this command fails? */
+ /* issue the auto-sense command */
temp_result = us->transport(us->srb, us);
+ if (temp_result == USB_STOR_TRANSPORT_ERROR) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- auto-sense failure\n");
+ srb->result = DID_ERROR << 16;
+ return;
+ }
+
US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ 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]);
@@ -366,16 +402,32 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set the result so the higher layers expect this data */
srb->result = CHECK_CONDITION;
- /* we're done here */
+ /* 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;
- }
+ memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
- /* Set return code, if necessary */
- if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
- srb->result = GOOD;
- if (!need_auto_sense)
+ /* If things are really okay, then let's show that */
+ if ((srb->sense_buffer[2] & 0xf) == 0x0)
+ srb->result = GOOD;
+ } else /* if (need_auto_sense) */
srb->result = GOOD;
+
+ /* 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;
+
+ /* 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) &&
+ (result == USB_STOR_TRANSPORT_GOOD) &&
+ ((srb->sense_buffer[2] & 0xf) == 0x0))
+ srb->sense_buffer[0] = 0x0;
}
/*
@@ -444,7 +496,7 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
+ if (us_transfer_length(srb, us)) {
us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
}
@@ -454,7 +506,7 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* go to sleep until we get this interrupt */
down(&(us->ip_waitq));
- /* if we were woken up by a reset instead of the actual interrupt */
+ /* if we were woken up by an abort instead of the actual interrupt */
if (us->ip_wanted) {
US_DEBUGP("Did not get interrupt on CBI\n");
us->ip_wanted = 0;
@@ -532,7 +584,7 @@ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
+ if (us_transfer_length(srb, us)) {
us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
}
@@ -558,7 +610,7 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set up the command wrapper */
bcb.Signature = US_BULK_CB_SIGN;
- bcb.DataTransferLength = us_transfer_length(srb);
+ bcb.DataTransferLength = us_transfer_length(srb, us);
bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
@@ -603,27 +655,31 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
/* get CSW for device status */
+ US_DEBUGP("Attempting to get CSW...\n");
result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+ US_BULK_CS_WRAP_LEN, &partial, HZ);
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
usb_clear_halt(us->pusb_dev, pipe);
-
+
/* get the status again */
+ US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+ US_BULK_CS_WRAP_LEN, &partial, HZ);
/* 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_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) {
- US_DEBUGP("Bulk status result = %d\n", result);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1120,14 +1176,14 @@ static int us_bus_reset( Scsi_Cmnd *srb )
printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
US_DEBUGP("Bus reset requested\n");
// us->transport_reset(us);
- return SUCCESS;
+ return FAILED;
}
/* FIXME: This doesn't actually reset anything */
static int us_host_reset( Scsi_Cmnd *srb )
{
printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
- return 0;
+ return FAILED;
}
/***********************************************************************
@@ -1136,14 +1192,14 @@ static int us_host_reset( Scsi_Cmnd *srb )
/* 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)
+#define SPRINTF(args...) \
+ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
int usb_stor_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout)
{
struct us_data *us;
char *pos = buffer;
- char *tmp_ptr;
/* if someone is sending us data, just throw it away */
if (inout)
@@ -1167,80 +1223,19 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
}
/* print the controler name */
- SPRINTF ("Host scsi%d: usb-storage\n", hostno);
-
- /* print product and vendor strings */
- tmp_ptr = kmalloc(256, GFP_KERNEL);
- if (!us->pusb_dev || !tmp_ptr) {
- SPRINTF(" Vendor: Unknown Vendor\n");
- SPRINTF(" Product: Unknown Product\n");
- } else {
- SPRINTF(" Vendor: ");
- if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
- SPRINTF("%s\n", tmp_ptr);
- else
- SPRINTF("Unknown Vendor\n");
-
- SPRINTF(" Product: ");
- if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
- SPRINTF("%s\n", tmp_ptr);
- else
- SPRINTF("Unknown Product\n");
- kfree(tmp_ptr);
- }
-
- SPRINTF(" Protocol: ");
- switch (us->protocol) {
- case US_PR_CB:
- SPRINTF("Control/Bulk\n");
- break;
-
- case US_PR_CBI:
- SPRINTF("Control/Bulk/Interrupt\n");
- break;
-
- case US_PR_BULK:
- SPRINTF("Bulk only\n");
- break;
-
- default:
- SPRINTF("Unknown Protocol\n");
- break;
- }
-
- SPRINTF(" Transport: ");
- switch (us->subclass) {
- case US_SC_RBC:
- SPRINTF("Reduced Block Commands\n");
- break;
+ SPRINTF(" Host scsi%d: usb-storage\n", hostno);
- case US_SC_8020:
- SPRINTF("8020i\n");
- break;
+ /* 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);
- case US_SC_QIC:
- SPRINTF("QIC-157\n");
- break;
-
- case US_SC_8070:
- SPRINTF("8070i\n");
- break;
-
- case US_SC_SCSI:
- SPRINTF("Transparent SCSI\n");
- break;
-
- case US_SC_UFI:
- SPRINTF("Uniform Floppy Interface\n");
- break;
-
- default:
- SPRINTF("Unknown Transport\n");
- break;
- }
+ /* 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(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
/* release our lock on the data structures */
up(&us_list_semaphore);
@@ -1263,30 +1258,30 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
*/
static Scsi_Host_Template my_host_template = {
- name: "usb-storage",
- proc_info: usb_stor_proc_info,
- info: us_info,
+ name: "usb-storage",
+ proc_info: usb_stor_proc_info,
+ info: us_info,
- detect: us_detect,
- release: us_release,
- command: us_command,
- queuecommand: us_queuecommand,
+ detect: us_detect,
+ release: us_release,
+ command: us_command,
+ queuecommand: us_queuecommand,
eh_abort_handler: us_abort,
eh_device_reset_handler:us_bus_reset,
eh_bus_reset_handler: us_bus_reset,
eh_host_reset_handler: us_host_reset,
- can_queue: 1,
- this_id: -1,
+ can_queue: 1,
+ this_id: -1,
- sg_tablesize: SG_ALL,
- cmd_per_lun: 1,
- present: 0,
- unchecked_isa_dma: FALSE,
- use_clustering: TRUE,
- use_new_eh_code: TRUE,
- emulated: TRUE,
+ sg_tablesize: SG_ALL,
+ cmd_per_lun: 1,
+ present: 0,
+ unchecked_isa_dma: FALSE,
+ use_clustering: TRUE,
+ use_new_eh_code: TRUE,
+ emulated: TRUE
};
static unsigned char sense_notready[] = {
@@ -1321,6 +1316,7 @@ static int usb_stor_control_thread(void * __us)
*/
daemonize();
+ /* set our name for identification purposes */
sprintf(current->comm, "usb-storage-%d", us->host_number);
unlock_kernel();
@@ -1334,7 +1330,7 @@ static int usb_stor_control_thread(void * __us)
down(&(us->queue_exclusion));
US_DEBUGP("*** thread awakened.\n");
- /* take the command off the queue */
+ /* take the command off the queue */
action = us->action;
us->action = 0;
us->srb = us->queue_srb;
@@ -1344,10 +1340,14 @@ static int usb_stor_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND:
- /* bad device */
- if (us->srb->target) {
- US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
- us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
+ /* reject if target != 0 or if single-lun device
+ * and LUN != 0
+ */
+ if (us->srb->target ||
+ ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) {
+ US_DEBUGP("Bad device number (%d/%d)\n",
+ us->srb->target, us->srb->lun);
+
us->srb->result = DID_BAD_TARGET << 16;
us->srb->scsi_done(us->srb);
@@ -1355,59 +1355,51 @@ static int usb_stor_control_thread(void * __us)
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->srb->result = GOOD;
+ 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 */
- /* FIXME: we also need to handle INQUIRY here,
- * probably */
- /* FIXME: fix return codes and sense buffer handling */
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,
sense_notready,
sizeof(sense_notready));
- us->srb->result = DID_OK << 16;
+ us->srb->result = GOOD;
} else {
- us->srb->result = (DID_OK << 16) | 2;
+ memcpy(us->srb->sense_buffer,
+ sense_notready,
+ sizeof(sense_notready));
+ us->srb->result = CHECK_CONDITION;
}
-
- /* unlock the device pointers */
- up(&(us->dev_semaphore));
-
- /* indicate that the command is done */
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- break;
- }
-
- /* we've got a command, let's do it! */
- US_DEBUG(us_show_command(us->srb));
-
- /* FIXME: this is to support Shuttle E-USB bridges, it
- * appears */
- if (us->srb->cmnd[0] == START_STOP &&
- us->pusb_dev->descriptor.idProduct == 0x0001 &&
- us->pusb_dev->descriptor.idVendor == 0x04e6)
- us->srb->result = DID_OK << 16;
- else {
+ } else { /* !us->pusb_dev */
+ /* we've got a command, let's do it! */
+ US_DEBUG(us_show_command(us->srb));
us->proto_handler(us->srb, us);
}
-
- US_DEBUGP("scsi cmd done, result=0x%x\n",
- us->srb->result);
/* unlock the device pointers */
up(&(us->dev_semaphore));
/* indicate that the command is done */
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
+ us->srb->result);
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
-
- case US_ACT_ABORT:
- break;
case US_ACT_DEVICE_RESET:
break;
@@ -1426,22 +1418,71 @@ static int usb_stor_control_thread(void * __us)
break;
}
} /* for (;;) */
-
+
/* notify the exit routine that we're actually exiting now */
up(&(us->notify));
return 0;
}
+static struct us_unusual_dev us_unusual_dev_list[] = {
+ { 0x057b, 0x0000, 0x0114,
+ "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN },
+ { 0x0781, 0x0001, 0x0200,
+ "Sandisk ImageMate", US_SC_SCSI, US_PR_CB,
+ US_FL_SINGLE_LUN | US_FL_START_STOP },
+ { 0x0781, 0x0002, 0x0009,
+ "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
+ { 0x04e6, 0x0002, 0x0100,
+ "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x07af, 0x0005, 0x0100,
+ "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x0000, 0x0000, 0x0,
+ "", 0, 0, 0}
+};
+
+/* Search our ususual device list, based on vendor/product combinations
+ * to see if we can support this device. Returns a pointer to a structure
+ * defining how we should support this device, or NULL if it's not in the
+ * list
+ */
+static struct us_unusual_dev* us_find_dev(__u16 idVendor, __u16 idProduct,
+ __u16 bcdDevice)
+{
+ struct us_unusual_dev* ptr;
+
+ US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
+ idVendor, idProduct, bcdDevice);
+
+ ptr = us_unusual_dev_list;
+ while ((ptr->idVendor != 0x0000) &&
+ !((ptr->idVendor == idVendor) &&
+ (ptr->idProduct == idProduct) &&
+ (ptr->bcdDevice == bcdDevice)))
+ ptr++;
+
+ /* if the search ended because we hit the end record, we failed */
+ if (ptr->idVendor == 0x0000) {
+ US_DEBUGP("-- did not find a matching device\n");
+ return NULL;
+ }
+
+ /* otherwise, we found one! */
+ US_DEBUGP("-- found matching device: %s\n", ptr->name);
+ return ptr;
+}
+
/* Probe to see if a new device is actually a SCSI device */
static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
{
int i;
- char mf[32]; /* manufacturer */
- char prod[32]; /* product */
- char serial[32]; /* serial number */
+ 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;
- GUID(guid); /* Global Unique Identifier */
int result;
/* these are temporary copies -- we test on these, then put them
@@ -1450,6 +1491,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
__u8 ep_in = 0;
__u8 ep_out = 0;
__u8 ep_int = 0;
+ __u8 ep_interval = 0;
__u8 subclass = 0;
__u8 protocol = 0;
@@ -1457,10 +1499,22 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_interface_descriptor *altsetting =
&(dev->actconfig->interface[ifnum].altsetting[0]);
- /* FIXME: this isn't quite right... */
- /* We make an exception for the shuttle E-USB */
- if (!(dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) &&
+ /* clear the temporary strings */
+ memset(mf, 0, sizeof(mf));
+ memset(prod, 0, sizeof(prod));
+ memset(serial, 0, sizeof(serial));
+
+ /* search for this device in our unusual device list */
+ unusual_dev = us_find_dev(dev->descriptor.idVendor,
+ dev->descriptor.idProduct,
+ dev->descriptor.bcdDevice);
+
+ /*
+ * 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?
+ */
+ if (!unusual_dev &&
!(dev->descriptor.bDeviceClass == 0 &&
altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
altsetting->bInterfaceSubClass >= US_SC_MIN &&
@@ -1473,37 +1527,16 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */
- /* FIXME: this isn't quite right */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- protocol = US_PR_CB;
- subclass = US_SC_8070; /* an assumption */
+ if (unusual_dev) {
+ subclass = unusual_dev->useProtocol;
+ protocol = unusual_dev->useTransport;
+ flags = unusual_dev->flags;
} else {
subclass = altsetting->bInterfaceSubClass;
protocol = altsetting->bInterfaceProtocol;
+ flags = 0;
}
-
- /* shuttle E-USB */
- /* FIXME: all we should need to do here is determine the protocol */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- __u8 qstat[2];
-
- result = usb_control_msg(ss->pusb_dev,
- usb_rcvctrlpipe(dev,0),
- 1, 0xC0,
- 0, ss->ifnum,
- qstat, 2, HZ*5);
- US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
- init_MUTEX_LOCKED(&(ss->ip_waitq));
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
- &ss->irq_handle);
- if (result < 0)
- return NULL;
- }
-
+
/*
* Find the endpoints we need
* We are expecting a minimum of 2 endpoints - in and out (bulk).
@@ -1529,10 +1562,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
ep_int = altsetting->endpoint[i].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
+ ep_interval = altsetting->endpoint[i].bInterval;
}
}
- US_DEBUGP("Endpoints In %d Out %d Int %d\n",
- ep_in, ep_out, ep_int);
+ US_DEBUGP("Endpoints: In %d Out %d Int %d (Period %d)\n",
+ ep_in, ep_out, ep_int, ep_interval);
/* set the interface -- STALL is an acceptable response here */
result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
@@ -1542,13 +1576,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
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");
+ US_DEBUGP("-- Unknown error. Rejecting device\n");
return NULL;
}
/* 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("Problems with device\n");
+ US_DEBUGP("Sanity check failed. Rejecting device.\n");
return NULL;
}
@@ -1556,9 +1590,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* clear the GUID and fetch the strings */
GUID_CLEAR(guid);
- memset(mf, 0, sizeof(mf));
- memset(prod, 0, sizeof(prod));
- memset(serial, 0, sizeof(serial));
if (dev->descriptor.iManufacturer)
usb_string(dev, dev->descriptor.iManufacturer, mf,
sizeof(mf));
@@ -1608,13 +1639,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
init_MUTEX_LOCKED(&(ss->ip_waitq));
/* set up the IRQ pipe and handler */
- /* FIXME: This needs to get period from the device */
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
+ CBI_irq, ss->ep_interval,
+ (void *)ss,
&(ss->irq_handle));
- US_DEBUGP("usb_request_irq returned %d\n", result);
+ US_DEBUGP("-- usb_request_irq returned %d\n", result);
}
} else {
/* New device -- Allocate memory and initialize */
@@ -1637,16 +1668,29 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* copy over the subclass and protocol data */
ss->subclass = subclass;
ss->protocol = protocol;
+ ss->flags = flags;
/* copy over the endpoint data */
ss->ep_in = ep_in;
ss->ep_out = ep_out;
ss->ep_int = ep_int;
+ ss->ep_interval = ep_interval;
/* 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)
+ strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
+ if (strlen(ss->product) == 0)
+ 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));
@@ -1654,81 +1698,91 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
* Set the handler pointers based on the protocol
* Again, this data is persistant across reattachments
*/
- US_DEBUGP("Transport: ");
switch (ss->protocol) {
case US_PR_CB:
- US_DEBUGPX("Control/Bulk\n");
+ ss->transport_name = "Control/Bulk";
ss->transport = CB_transport;
ss->transport_reset = CB_reset;
break;
case US_PR_CBI:
- US_DEBUGPX("Control/Bulk/Interrupt\n");
+ ss->transport_name = "Control/Bulk/Interrupt";
ss->transport = CBI_transport;
ss->transport_reset = CB_reset;
break;
case US_PR_BULK:
- US_DEBUGPX("Bulk\n");
+ ss->transport_name = "Bulk";
ss->transport = Bulk_transport;
ss->transport_reset = Bulk_reset;
break;
default:
- US_DEBUGPX("Unknown\n");
+ ss->transport_name = "Unknown";
+ up(&us_list_semaphore);
kfree(ss);
return NULL;
break;
}
+ US_DEBUGP("Transport: %s\n", ss->transport_name);
- US_DEBUGP("Protocol: ");
switch (ss->subclass) {
case US_SC_RBC:
- US_DEBUGPX("Reduced Block Commands (RBC)\n");
+ ss->protocol_name = "Reduced Block Commands (RBC)";
ss->proto_handler = transparent_scsi_command;
break;
case US_SC_8020:
- US_DEBUGPX("8020i\n");
+ ss->protocol_name = "8020i";
ss->proto_handler = ATAPI_command;
break;
case US_SC_QIC:
- US_DEBUGPX("QIC-157\n");
+ ss->protocol_name = "QIC-157";
+ US_DEBUGP("Sorry, device not supported. Please\n");
+ US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
+ US_DEBUGP("if you see this message.\n");
+ up(&us_list_semaphore);
+ kfree(ss);
+ return NULL;
break;
case US_SC_8070:
- US_DEBUGPX("8070i\n");
+ ss->protocol_name = "8070i";
ss->proto_handler = ATAPI_command;
break;
case US_SC_SCSI:
- US_DEBUGPX("Transparent SCSI\n");
+ ss->protocol_name = "Transparent SCSI";
ss->proto_handler = transparent_scsi_command;
break;
case US_SC_UFI:
- US_DEBUGPX("UFI\n");
+ ss->protocol_name = "Uniform Floppy Interface (UFI)";
ss->proto_handler = ufi_command;
break;
default:
- US_DEBUGPX("Unknown\n");
+ ss->protocol_name = "Unknown";
+ up(&us_list_semaphore);
+ kfree(ss);
+ return NULL;
break;
}
+ US_DEBUGP("Protocol: %s\n", ss->protocol_name);
if (ss->protocol == US_PR_CBI) {
/* set up so we'll wait for notification */
init_MUTEX_LOCKED(&(ss->ip_waitq));
/* set up the IRQ pipe and handler */
- /* FIXME: This needs to get period from the device */
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
+ CBI_irq, ss->ep_interval,
+ (void *)ss,
&(ss->irq_handle));
- US_DEBUGP("usb_request_irq returned %d\n", result);
+ US_DEBUGP("-- usb_request_irq returned %d\n", result);
}
/*
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 6a37924ca..c867bbe0d 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -7,7 +7,8 @@
#include <linux/config.h>
-#define USB_STORAGE "usb-storage: "
+#define USB_STORAGE "usb-storage.c: "
+#define USB_STOR_STRING_LEN 32
#ifdef CONFIG_USB_STORAGE_DEBUG
void us_show_command(Scsi_Cmnd *srb);
@@ -128,9 +129,27 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri
}
}
+/*
+ * Unusual device list definitions
+ */
+
+struct us_unusual_dev {
+ /* we search the list based on these parameters */
+ __u16 idVendor;
+ __u16 idProduct;
+ __u16 bcdDevice;
+
+ /* the list specifies these parameters */
+ const char* name;
+ __u8 useProtocol;
+ __u8 useTransport;
+ unsigned int flags;
+};
+
/* Flag definitions */
-#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */
-#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */
-#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for
+#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */
+#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for
Win/MacOS compatibility */
-#define US_FL_CBI_AS_CB 0x00000008 /* treat a CBI dev as a CB dev */
+#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */
+#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for
+ us_transfer_length() */