summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in2
-rw-r--r--drivers/usb/audio.c129
-rw-r--r--drivers/usb/hub.c4
-rw-r--r--drivers/usb/input.c8
-rw-r--r--drivers/usb/ov511.c743
-rw-r--r--drivers/usb/ov511.h139
-rw-r--r--drivers/usb/pegasus.c50
-rw-r--r--drivers/usb/printer.c45
-rw-r--r--drivers/usb/serial/Makefile22
-rw-r--r--drivers/usb/serial/digi_acceleport.c1164
-rw-r--r--drivers/usb/serial/ftdi_sio.c6
-rw-r--r--drivers/usb/serial/keyspan_pda.c4
-rw-r--r--drivers/usb/serial/omninet.c6
-rw-r--r--drivers/usb/serial/usbserial.c4
-rw-r--r--drivers/usb/serial/visor.c7
-rw-r--r--drivers/usb/serial/whiteheat.c6
-rw-r--r--drivers/usb/uhci.c31
-rw-r--r--drivers/usb/usb-ohci.c160
-rw-r--r--drivers/usb/usb-ohci.h2
-rw-r--r--drivers/usb/usb-storage.c356
-rw-r--r--drivers/usb/usb-storage.h14
-rw-r--r--drivers/usb/usb-uhci.c87
-rw-r--r--drivers/usb/usb-uhci.h4
-rw-r--r--drivers/usb/wacom.c2
24 files changed, 1778 insertions, 1217 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 3b376c365..74253ed99 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -43,7 +43,7 @@ comment 'USB Devices'
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
- dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB
+ dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
if [ "$CONFIG_USB_STORAGE" != "n" ]; then
bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
fi
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 354c1d6cf..40903a9c2 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -3,7 +3,7 @@
/*
* audio.c -- USB Audio Class driver
*
- * Copyright (C) 1999
+ * Copyright (C) 1999, 2000
* Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
@@ -59,6 +59,21 @@
* 1999-12-20: Fix bad bug in conversion to per interface probing.
* disconnect was called multiple times for the audio device,
* leading to a premature freeing of the audio structures
+ * 2000-05-13: I don't remember who changed the find_format routine,
+ * but the change was completely broken for the Dallas
+ * chip. Anyway taking sampling rate into account in find_format
+ * is bad and should not be done unless there are devices with
+ * completely broken audio descriptors. Unless someone shows
+ * me such a descriptor, I will not allow find_format to
+ * take the sampling rate into account.
+ * Also, the former find_format made:
+ * - mpg123 play mono instead of stereo
+ * - sox completely fail for wav's with sample rates < 44.1kHz
+ * for the Dallas chip.
+ * Also fix a rather long standing problem with applications that
+ * use "small" writes producing no sound at all.
+ * 2000-05-15: My fears came true, the Philips camera indeed has pretty stupid
+ * audio descriptors.
*
*/
@@ -441,9 +456,9 @@ static int dmabuf_init(struct dmabuf *db)
db->bufsize = nr << PAGE_SHIFT;
db->ready = 1;
printk(KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
- "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d\n",
+ "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x\n",
bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
- db->numfrag, db->dmasize, db->bufsize);
+ db->numfrag, db->dmasize, db->bufsize, db->format);
return 0;
}
@@ -973,6 +988,8 @@ static int usbin_start(struct usb_audiodev *as)
}
spin_lock_irqsave(&as->lock, flags);
}
+ if (u->dma.count <= 0 && !u->dma.mapped)
+ return 0;
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
urb = &u->durb[0].urb;
@@ -1332,6 +1349,8 @@ static int usbout_start(struct usb_audiodev *as)
}
spin_lock_irqsave(&as->lock, flags);
}
+ if (u->dma.count <= 0 && !u->dma.mapped)
+ return 0;
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
urb = &u->durb[0].urb;
@@ -1395,30 +1414,39 @@ static int usbout_start(struct usb_audiodev *as)
/* --------------------------------------------------------------------- */
-static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate)
+static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
{
- unsigned int i;
+ unsigned int g = 0;
+
+ if (srate < afp->sratelo)
+ g += afp->sratelo - srate;
+ if (srate > afp->sratehi)
+ g += srate - afp->sratehi;
+ if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
+ g += 0x100000;
+ if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
+ g += 0x400000;
+ if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
+ g += 0x100000;
+ if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
+ g += 0x400000;
+ return g;
+}
+
+static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
+{
+ unsigned int i, g, gb = ~0;
+ int j = -1; /* default to failure */
- /* first find an exact match, taking both format and sample rate into account,
- but ignore stereo bit */
+ /* find "best" format (according to format_goodness) */
for (i = 0; i < nr; i++) {
- if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi)
- return i;
+ g = format_goodness(&afp[i], fmt, srate);
+ if (g >= gb)
+ continue;
+ j = i;
+ gb = g;
}
-
- /* second find a match with the same stereo/mono and 8bit/16bit property */
- for (i = 0; i < nr; i++)
- if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
- !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) &&
- rate >= afp[i].sratelo && rate <= afp[i].sratehi)
- return i;
- /* third find a match with the same number of channels */
- for (i = 0; i < nr; i++)
- if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
- rate >= afp[i].sratelo && rate <= afp[i].sratehi)
- return i;
- /* return failure */
- return -1;
+ return j;
}
static int set_format_in(struct usb_audiodev *as)
@@ -1430,9 +1458,9 @@ static int set_format_in(struct usb_audiodev *as)
struct usbin *u = &as->usbin;
struct dmabuf *d = &u->dma;
struct audioformat *fmt;
- unsigned int fmtnr, ep;
+ unsigned int ep;
unsigned char data[3];
- int ret;
+ int fmtnr, ret;
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
@@ -1465,7 +1493,9 @@ static int set_format_in(struct usb_audiodev *as)
d->srate = fmt->sratelo;
if (d->srate > fmt->sratehi)
d->srate = fmt->sratehi;
-printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#if 1
+ printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#endif
if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) {
printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
dev->devnum, u->interface, fmt->altsetting);
@@ -1517,9 +1547,9 @@ static int set_format_out(struct usb_audiodev *as)
struct usbout *u = &as->usbout;
struct dmabuf *d = &u->dma;
struct audioformat *fmt;
- unsigned int fmtnr, ep;
+ unsigned int ep;
unsigned char data[3];
- int ret;
+ int fmtnr, ret;
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
@@ -1559,7 +1589,9 @@ static int set_format_out(struct usb_audiodev *as)
d->srate = fmt->sratelo;
if (d->srate > fmt->sratehi)
d->srate = fmt->sratehi;
-printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#if 1
+ printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#endif
if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
dev->devnum, u->interface, fmt->altsetting);
@@ -1927,6 +1959,7 @@ static int drain_out(struct usb_audiodev *as, int nonblock)
if (as->usbout.dma.mapped || !as->usbout.dma.ready)
return 0;
+ usbout_start(as);
add_wait_queue(&as->usbout.dma.wait, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
@@ -2033,6 +2066,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
ssize_t ret = 0;
unsigned long flags;
unsigned int ptr;
+ unsigned int start_thr;
int cnt, err;
if (ppos != &file->f_pos)
@@ -2043,10 +2077,11 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
+ start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
add_wait_queue(&as->usbout.dma.wait, &wait);
while (count > 0) {
#if 0
- printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n",
+ printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
as->usbout.flags, current->state);
#endif
@@ -2097,7 +2132,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
count -= cnt;
buffer += cnt;
ret += cnt;
- if (usbout_start(as)) {
+ if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
if (!ret)
ret = -ENODEV;
break;
@@ -2525,17 +2560,6 @@ static /*const*/ struct file_operations usb_audio_fops = {
/* --------------------------------------------------------------------- */
-/*
- * TO DO in order to get to the point of building an OSS interface
- * structure, let alone playing music..
- *
- * Use kmalloc/kfree for the descriptors we build
- * Write the descriptor->OSS convertor code
- * Figure how we deal with mixers
- * Check alternate configurations. For now assume we will find one
- * zero bandwidth (idle) config and one or more live one pers interface.
- */
-
static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum);
static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
@@ -2543,25 +2567,11 @@ static struct usb_driver usb_audio_driver = {
"audio",
usb_audio_probe,
usb_audio_disconnect,
- /*{ NULL, NULL }, */ LIST_HEAD_INIT(usb_audio_driver.driver_list),
+ LIST_HEAD_INIT(usb_audio_driver.driver_list),
NULL,
0
};
-
-#if 0
-static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
-{
-#if 0
- struct usb_audio_device *aud = (struct usb_audio_device *)dev_id;
-
- printk(KERN_DEBUG "irq on %p\n", aud);
-#endif
-
- return 1;
-}
-#endif
-
static void *find_descriptor(void *descstart, unsigned int desclen, void *after,
u8 dtype, int iface, int altsetting)
{
@@ -3559,11 +3569,6 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
unregister_sound_mixer(ms->dev_mixer);
ms->dev_mixer = -1;
}
-#if 0
- if(aud->irq_handle)
- usb_release_irq(dev, aud->irq_handle, aud->irqpipe);
- aud->irq_handle = NULL;
-#endif
release(s);
wake_up(&open_wait);
}
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 534325986..0b7cf6b09 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -338,7 +338,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
dbg("portstatus %x, change %x, %s", portstatus, portchange,
- portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+ portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
/* Clear the connection change status */
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -369,7 +369,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
dbg("portstatus %x, change %x, %s", portstatus ,portchange,
- portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+ portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
!(portstatus & USB_PORT_STAT_CONNECTION))
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index 73f39db7c..35f268fac 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -244,6 +244,7 @@ void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle = dev->handle;
struct input_dev **devptr = &input_dev;
+ struct input_handle *dnext;
/*
* Kill any pending repeat timers.
@@ -256,9 +257,10 @@ void input_unregister_device(struct input_dev *dev)
*/
while (handle) {
+ dnext = handle->dnext;
input_unlink_handle(handle);
handle->handler->disconnect(handle);
- handle = handle->dnext;
+ handle = dnext;
}
/*
@@ -309,15 +311,17 @@ void input_unregister_handler(struct input_handler *handler)
{
struct input_handler **handlerptr = &input_handler;
struct input_handle *handle = handler->handle;
+ struct input_handle *hnext;
/*
* Tell the handler to disconnect from all devices it keeps open.
*/
while (handle) {
+ hnext = handle->hnext;
input_unlink_handle(handle);
handler->disconnect(handle);
- handle = handle->hnext;
+ handle = hnext;
}
/*
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index b047d0776..e97410c32 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -6,7 +6,7 @@
* Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
* Snapshot code by Kevin Moore
* OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka, claudio@conectiva.com, 3/26/2000
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
*
* Based on the Linux CPiA driver written by Peter Pregler,
* Scott J. Bertin and Johannes Erdfelt.
@@ -30,7 +30,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-static const char version[] = "1.13";
+static const char version[] = "1.14";
#define __NO_VERSION__
@@ -64,6 +64,9 @@ static const char version[] = "1.13";
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
+#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_RGB24 ? 384 : 256)
+#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_RGB24 ? 24 : 8)
+
/* PARAMETER VARIABLES: */
static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */
@@ -90,9 +93,13 @@ static int sensor = 0;
static int i2c_detect_tries = 5;
/* For legal values, see the OV7610/7620 specs under register Common F,
- upper nybble (set to 0-F) */
+ * upper nybble (set to 0-F) */
static int aperture = -1;
+/* Force image to be read in RGB instead of BGR. This option allow
+ * programs that expect RGB data (e.g. gqcam) to work with this driver. */
+static int force_rgb = 0;
+
MODULE_PARM(autoadjust, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(fix_rgb_offset, "i");
@@ -100,8 +107,9 @@ MODULE_PARM(snapshot, "i");
MODULE_PARM(sensor, "i");
MODULE_PARM(i2c_detect_tries, "i");
MODULE_PARM(aperture, "i");
+MODULE_PARM(force_rgb, "i");
-MODULE_AUTHOR("Mark McClelland (and others)");
+MODULE_AUTHOR("Mark McClelland <mmcclelland@delphi.com> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
MODULE_DESCRIPTION("OV511 USB Camera Driver");
char kernel_version[] = UTS_RELEASE;
@@ -126,6 +134,26 @@ static struct cam_list clist[] = {
{ -1, NULL }
};
+static struct palette_list plist[] = {
+ { VIDEO_PALETTE_GREY, "GREY" },
+ { VIDEO_PALETTE_HI240, "HI240" },
+ { VIDEO_PALETTE_RGB565, "RGB565" },
+ { VIDEO_PALETTE_RGB24, "RGB24" },
+ { VIDEO_PALETTE_RGB32, "RGB32" },
+ { VIDEO_PALETTE_RGB555, "RGB555" },
+ { VIDEO_PALETTE_YUV422, "YUV422" },
+ { VIDEO_PALETTE_YUYV, "YUYV" },
+ { VIDEO_PALETTE_UYVY, "UYVY" },
+ { VIDEO_PALETTE_YUV420, "YUV420" },
+ { VIDEO_PALETTE_YUV411, "YUV411" },
+ { VIDEO_PALETTE_RAW, "RAW" },
+ { VIDEO_PALETTE_YUV422P,"YUV422P" },
+ { VIDEO_PALETTE_YUV411P,"YUV411P" },
+ { VIDEO_PALETTE_YUV420P,"YUV420P" },
+ { VIDEO_PALETTE_YUV410P,"YUV410P" },
+ { -1, NULL }
+};
+
/**********************************************************************
*
* Memory management
@@ -236,7 +264,8 @@ static void rvfree(void *mem, unsigned long size)
**********************************************************************/
#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *ov511_proc_root = NULL;
+static struct proc_dir_entry *ov511_proc_entry = NULL;
+static struct proc_dir_entry *video_proc_entry = NULL;
#define YES_NO(x) ((x) ? "yes" : "no")
@@ -244,7 +273,7 @@ static int ov511_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
char *out = page;
- int i, len;
+ int i, j, len;
struct usb_ov511 *ov511 = data;
/* IMPORTANT: This output MUST be kept under PAGE_SIZE
@@ -259,6 +288,10 @@ static int ov511_read_proc(char *page, char **start, off_t off,
out += sprintf (out, "subcapture : %s\n", YES_NO (ov511->sub_flag));
out += sprintf (out, "sub_size : %d %d %d %d\n",
ov511->subx, ov511->suby, ov511->subw, ov511->subh);
+ out += sprintf (out, "data_format : %s\n", force_rgb ? "RGB" : "BGR");
+ out += sprintf (out, "brightness : %d\n", ov511->brightness >> 8);
+ out += sprintf (out, "colour : %d\n", ov511->colour >> 8);
+ out += sprintf (out, "contrast : %d\n", ov511->contrast >> 8);
out += sprintf (out, "num_frames : %d\n", OV511_NUMFRAMES);
for (i = 0; i < OV511_NUMFRAMES; i++) {
out += sprintf (out, "frame : %d\n", i);
@@ -266,27 +299,40 @@ static int ov511_read_proc(char *page, char **start, off_t off,
ov511->frame[i].depth);
out += sprintf (out, " size : %d %d\n",
ov511->frame[i].width, ov511->frame[i].height);
+#if 0
out += sprintf (out, " hdr_size : %d %d\n",
ov511->frame[i].hdrwidth, ov511->frame[i].hdrheight);
- out += sprintf (out, " format : %d\n",
- ov511->frame[i].format);
+#endif
+ out += sprintf (out, " format : ");
+ for (j = 0; plist[j].num >= 0; j++) {
+ if (plist[j].num == ov511->frame[i].format) {
+ out += sprintf (out, "%s\n", plist[j].name);
+ break;
+ }
+ }
+ if (plist[j].num < 0)
+ out += sprintf (out, "unknown\n");
out += sprintf (out, " segsize : %d\n",
ov511->frame[i].segsize);
+ out += sprintf (out, " data_buffer : 0x%p\n",
+ ov511->frame[i].data);
#if 0
- out += sprintf (out, " curline : %d\n",
- ov511->frame[i].curline);
- out += sprintf (out, " segment : %d\n",
- ov511->frame[i].segment);
- out += sprintf (out, " scanlength : %ld\n",
- ov511->frame[i].scanlength);
out += sprintf (out, " bytesread : %ld\n",
ov511->frame[i].bytes_read);
#endif
}
out += sprintf (out, "snap_enabled : %s\n", YES_NO (ov511->snap_enabled));
- out += sprintf (out, "bridge : %d\n", ov511->bridge);
- out += sprintf (out, "sensor : %d\n", ov511->sensor);
+ out += sprintf (out, "bridge : %s\n",
+ ov511->bridge == BRG_OV511 ? "OV511" :
+ ov511->bridge == BRG_OV511PLUS ? "OV511+" :
+ "unknown");
+ out += sprintf (out, "sensor : %s\n",
+ ov511->sensor == SEN_OV7610 ? "OV7610" :
+ ov511->sensor == SEN_OV7620 ? "OV7620" :
+ ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
+ "unknown");
out += sprintf (out, "packet_size : %d\n", ov511->packet_size);
+ out += sprintf (out, "framebuffer : 0x%p\n", ov511->fbuf);
len = out - page;
len -= off;
@@ -303,130 +349,7 @@ static int ov511_read_proc(char *page, char **start, off_t off,
static int ov511_write_proc(struct file *file, const char *buffer,
unsigned long count, void *data)
{
- int retval = -EINVAL;
-
-#if 0
- /* struct cam_data *cam = data; */
- struct usb_ov511 new_params;
- int size = count;
- int find_colon;
- unsigned long val;
- u32 command_flags = 0;
- u8 new_mains;
-
- if (down_interruptible(&cam->param_lock))
- return -ERESTARTSYS;
-
- /*
- * Skip over leading whitespace
- */
- while (count && isspace(*buffer)) {
- --count;
- ++buffer;
- }
-
-
-#define MATCH(x) \
- ({ \
- int _len = strlen(x), _ret, _colon_found; \
- _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
- if (_ret) { \
- buffer += _len; \
- count -= _len; \
- if (find_colon) { \
- _colon_found = 0; \
- while (count && (*buffer == ' ' || *buffer == '\t' || \
- (!_colon_found && *buffer == ':'))) { \
- if (*buffer == ':') \
- _colon_found = 1; \
- --count; \
- ++buffer; \
- } \
- if (!count || !_colon_found) \
- retval = -EINVAL; \
- find_colon = 0; \
- } \
- } \
- _ret; \
- })
-
-#define VALUE \
- ({ \
- char *_p; \
- unsigned long int _ret; \
- _ret = simple_strtoul(buffer, &_p, 0); \
- if (_p == buffer) \
- retval = -EINVAL; \
- else { \
- count -= _p - buffer; \
- buffer = _p; \
- } \
- _ret; \
- })
-
-
- retval = 0;
- while (count && !retval) {
- find_colon = 1;
-
- if (MATCH("")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- /* ... = val */ ;
- else
- retval = -EINVAL;
- }
- } else {
- DBG("No match found\n");
- retval = -EINVAL;
- }
-
- if (!retval) {
- while (count && isspace(*buffer) && *buffer != '\n') {
- --count;
- ++buffer;
- }
- if (count) {
- if (*buffer != '\n' && *buffer != ';')
- retval = -EINVAL;
- else {
- --count;
- ++buffer;
- }
- }
- }
- }
-
-#undef MATCH
-#undef FIRMWARE_VERSION
-#undef VALUE
-#undef FIND_VALUE
-#undef FIND_END
- if (!retval) {
- if (command_flags & COMMAND_SETCOLOURPARAMS) {
- /* Adjust cam->vp to reflect these changes */
- cam->vp.brightness =
- new_params.colourParams.brightness*65535/100;
- cam->vp.contrast =
- new_params.colourParams.contrast*65535/100;
- cam->vp.colour =
- new_params.colourParams.saturation*65535/100;
- }
-
- memcpy(&cam->params, &new_params, sizeof(struct cam_params));
- cam->mainsFreq = new_mains;
- cam->cmd_queue |= command_flags;
- retval = size;
- } else
- PDEBUG(3, "error: %d\n", retval);
-
- up(&cam->param_lock);
-#endif
-
- return retval;
+ return -EINVAL;
}
static void create_proc_ov511_cam (struct usb_ov511 *ov511)
@@ -434,14 +357,15 @@ static void create_proc_ov511_cam (struct usb_ov511 *ov511)
char name[7];
struct proc_dir_entry *ent;
- PDEBUG (4, "***************");
- if (!ov511_proc_root || !ov511)
+ PDEBUG (4, "creating /proc/video/ov511/videoX entry");
+ if (!ov511_proc_entry || !ov511)
return;
sprintf(name, "video%d", ov511->vdev.minor);
- PDEBUG (4, "==== name: %s", name);
+ PDEBUG (4, "creating %s", name);
- ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_root);
+ ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry);
+
if (!ent)
return;
@@ -460,26 +384,44 @@ static void destroy_proc_ov511_cam (struct usb_ov511 *ov511)
return;
sprintf(name, "video%d", ov511->vdev.minor);
- PDEBUG (4, "==== name: %s", name);
-#if 0
- remove_proc_entry(name, ov511_proc_root);
+ PDEBUG (4, "destroying %s", name);
+ remove_proc_entry(name, ov511_proc_entry);
ov511->proc_entry = NULL;
-#endif
}
static void proc_ov511_create(void)
{
- ov511_proc_root = create_proc_entry("ov511", S_IFDIR, 0);
+ struct proc_dir_entry *p = NULL;
+
+ /* No current standard here. Alan prefers /proc/video/ as it keeps
+ * /proc "less cluttered than /proc/randomcardifoundintheshed/"
+ * -claudio
+ */
+ PDEBUG (3, "creating /proc/video");
+ video_proc_entry = proc_mkdir("video", p);
+ if (!video_proc_entry) {
+ if (!p) {
+ err("Unable to initialise /proc/video\n");
+ return;
+ } else { /* FIXME - this doesn't work */
+ PDEBUG (3, "/proc/video already exists");
+ video_proc_entry = p;
+ }
+ }
- if (ov511_proc_root)
- ov511_proc_root->owner = THIS_MODULE;
+ ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry);
+
+ if (ov511_proc_entry)
+ ov511_proc_entry->owner = THIS_MODULE;
else
- printk("Unable to initialise /proc/ov511\n"); /***********/
+ err("Unable to initialise /proc/video/ov511\n");
}
static void proc_ov511_destroy(void)
{
- remove_proc_entry("ov511", 0);
+ PDEBUG (3, "removing /proc/video/ov511");
+ remove_proc_entry("ov511", video_proc_entry);
+ remove_proc_entry("video", NULL);
}
#endif /* CONFIG_PROC_FS */
@@ -510,7 +452,6 @@ static int ov511_reg_write(struct usb_device *dev,
return rc;
}
-
/* returns: negative is error, pos or zero is data */
static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
{
@@ -533,7 +474,6 @@ static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
}
}
-
static int ov511_i2c_write(struct usb_device *dev,
unsigned char reg,
unsigned char value)
@@ -580,7 +520,6 @@ error:
return rc;
}
-
/* returns: negative is error, pos or zero is data */
static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
{
@@ -653,7 +592,6 @@ error:
return rc;
}
-
static int ov511_write_regvals(struct usb_device *dev,
struct ov511_regvals * pRegvals)
{
@@ -682,9 +620,8 @@ error:
return rc;
}
-
-#if 0
-static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
+#ifdef OV511_DEBUG
+static void ov511_dump_i2c_range(struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
@@ -694,15 +631,13 @@ static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
}
}
-
-static void ov511_dump_i2c_regs( struct usb_device *dev)
+static void ov511_dump_i2c_regs(struct usb_device *dev)
{
PDEBUG(3, "I2C REGS");
ov511_dump_i2c_range(dev, 0x00, 0x38);
}
-
-static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
+static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
@@ -712,8 +647,8 @@ static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
}
}
-
-static void ov511_dump_regs( struct usb_device *dev)
+#if 0
+static void ov511_dump_regs(struct usb_device *dev)
{
PDEBUG(1, "CAMERA INTERFACE REGS");
ov511_dump_reg_range(dev, 0x10, 0x1f);
@@ -736,7 +671,7 @@ static void ov511_dump_regs( struct usb_device *dev)
}
#endif
-
+#endif
static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
@@ -752,24 +687,21 @@ static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
return rc;
}
-
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */
static inline int ov511_stop(struct usb_device *dev)
{
- PDEBUG(4, "ov511_stop()");
+ PDEBUG(4, "stopping");
return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
}
-
/* Restarts OV511 after ov511_stop() is called */
static inline int ov511_restart(struct usb_device *dev)
{
- PDEBUG(4, "ov511_restart()");
+ PDEBUG(4, "restarting");
return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
}
-
static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
{
int alt, mult;
@@ -844,9 +776,16 @@ ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
if (ov511_stop(dev) < 0)
return -EIO;
+ ov511->contrast = p->contrast;
+ ov511->brightness = p->brightness;
+ ov511->colour = p->colour;
+ ov511->hue = p->hue;
+ ov511->whiteness = p->whiteness;
+
if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
return -EIO;
#if 0
+ /* disable auto adjust mode */
if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
return -EIO;
#endif
@@ -880,7 +819,6 @@ ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
return 0;
}
-
static inline int
ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
{
@@ -903,12 +841,10 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
p->hue = 0x8000;
p->whiteness = 105 << 8;
-#if 0
- p->depth = 3; /* Don't know if this is right */
-#else
- p->depth = 24;
-#endif
- p->palette = VIDEO_PALETTE_RGB24;
+
+ /* Can we get these from frame[0]? -claudio? */
+ p->depth = ov511->frame[0].depth;
+ p->palette = ov511->frame[0].format;
if (ov511_restart(dev) < 0)
return -EIO;
@@ -916,6 +852,22 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
return 0;
}
+/* FIXME: add 176x144, 160x140 */
+static struct mode_list mlist[] = {
+ { 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00,
+ 0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e },
+ { 640, 480, VIDEO_PALETTE_RGB24,0x4f, 0x3d, 0x00, 0x00,
+ 0x4f, 0x3d, 0x00, 0x00, 0x06, 0x03, 0x24, 0x04, 0x9e },
+ { 320, 240, VIDEO_PALETTE_GREY, 0x27, 0x1f, 0x00, 0x00,
+ 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
+ { 320, 240, VIDEO_PALETTE_RGB24,0x27, 0x1f, 0x00, 0x00,
+ 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
+ { 352, 288, VIDEO_PALETTE_GREY, 0x2b, 0x25, 0x00, 0x00,
+ 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00,
+ 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ { 0, 0 }
+};
static int
ov511_mode_init_regs(struct usb_ov511 *ov511,
@@ -925,6 +877,7 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
struct usb_device *dev = ov511->dev;
int hwsbase = 0;
int hwebase = 0;
+ int i;
PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
width, height, mode, sub_flag);
@@ -975,6 +928,9 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
break;
}
+#if 0
+ /* FIXME: subwindow support is currently broken!
+ */
if (width == 640 && height == 480) {
if (sub_flag) {
/* horizontal window start */
@@ -1018,41 +974,51 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
}
}
- ov511_reg_write(dev, 0x14, 0x00);
- ov511_reg_write(dev, 0x15, 0x00);
+ ov511_reg_write(dev, 0x14, 0x00); /* Pixel divisor */
+ ov511_reg_write(dev, 0x15, 0x00); /* Line divisor */
/* FIXME?? Shouldn't below be true only for YUV420? */
- ov511_reg_write(dev, 0x18, 0x03);
+ ov511_reg_write(dev, 0x18, 0x03); /* YUV420/422, YFIR */
- ov511_i2c_write(dev, 0x12, 0x24);
- ov511_i2c_write(dev, 0x14, 0x04);
+ ov511_i2c_write(dev, 0x12, 0x24); /* Common A */
+ ov511_i2c_write(dev, 0x14, 0x04); /* Common C */
/* 7620 doesn't have register 0x35, so play it safe */
if (ov511->sensor != SEN_OV7620)
ov511_i2c_write(dev, 0x35, 0x9e);
- } else if (width == 320 && height == 240) {
- ov511_reg_write(dev, 0x12, 0x27);
- ov511_reg_write(dev, 0x13, 0x1f);
- ov511_reg_write(dev, 0x14, 0x00);
- ov511_reg_write(dev, 0x15, 0x00);
- ov511_reg_write(dev, 0x18, 0x03);
+#endif
+
+ for (i = 0; mlist[i].width; i++) {
+ if (width != mlist[i].width ||
+ height != mlist[i].height ||
+ mode != mlist[i].mode)
+ continue;
+
+ ov511_reg_write(dev, 0x12, mlist[i].pxcnt);
+ ov511_reg_write(dev, 0x13, mlist[i].lncnt);
+ ov511_reg_write(dev, 0x14, mlist[i].pxdv);
+ ov511_reg_write(dev, 0x15, mlist[i].lndv);
+ ov511_reg_write(dev, 0x18, mlist[i].m420);
/* Snapshot additions */
- ov511_reg_write(dev, 0x1a, 0x27);
- ov511_reg_write(dev, 0x1b, 0x1f);
- ov511_reg_write(dev, 0x1c, 0x00);
- ov511_reg_write(dev, 0x1d, 0x00);
+ ov511_reg_write(dev, 0x1a, mlist[i].s_pxcnt);
+ ov511_reg_write(dev, 0x1b, mlist[i].s_lncnt);
+ ov511_reg_write(dev, 0x1c, mlist[i].s_pxdv);
+ ov511_reg_write(dev, 0x1d, mlist[i].s_lndv);
- if (mode == VIDEO_PALETTE_GREY) {
- ov511_i2c_write(dev, 0x11, 1); /* check */
- } else {
- ov511_i2c_write(dev, 0x11, 1); /* check */
- }
+ ov511_i2c_write(dev, 0x11, mlist[i].clock); /* check */
- ov511_i2c_write(dev, 0x12, 0x04);
- ov511_i2c_write(dev, 0x14, 0x24);
- ov511_i2c_write(dev, 0x35, 0x1e);
- } else {
+ ov511_i2c_write(dev, 0x12, mlist[i].common_A);
+ ov511_i2c_write(dev, 0x14, mlist[i].common_C);
+
+ /* 7620 doesn't have register 0x35, so play it safe */
+ if (ov511->sensor != SEN_OV7620)
+ ov511_i2c_write(dev, 0x35, mlist[i].common_L);
+
+ break;
+ }
+
+ if (mlist[i].width == 0) {
err("Unknown mode (%d, %d): %d", width, height, mode);
rc = -EINVAL;
}
@@ -1060,10 +1026,14 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
if (ov511_restart(ov511->dev) < 0)
return -EIO;
+#ifdef OV511_DEBUG
+ if (debug >= 5)
+ ov511_dump_i2c_regs(dev);
+#endif
+
return rc;
}
-
/**********************************************************************
*
* Color correction functions
@@ -1093,32 +1063,38 @@ static inline void
ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
int rowPixels, unsigned char * rgb)
{
- const double brightness = 1.0; // 0->black; 1->full scale
- const double saturation = 1.0; // 0->greyscale; 1->full color
+ const double brightness = 1.0; /* 0->black; 1->full scale */
+ const double saturation = 1.0; /* 0->greyscale; 1->full color */
const double fixScale = brightness * 256 * 256;
const int rvScale = (int)(1.402 * saturation * fixScale);
const int guScale = (int)(-0.344136 * saturation * fixScale);
const int gvScale = (int)(-0.714136 * saturation * fixScale);
const int buScale = (int)(1.772 * saturation * fixScale);
const int yScale = (int)(fixScale);
+ int r, g, b;
+
+ g = guScale * u + gvScale * v;
+ if (force_rgb) {
+ r = buScale * u;
+ b = rvScale * v;
+ } else {
+ r = rvScale * v;
+ b = buScale * u;
+ }
- int r = rvScale * v;
- int g = guScale * u + gvScale * v;
- int b = buScale * u;
yTL *= yScale; yTR *= yScale;
yBL *= yScale; yBR *= yScale;
- //Write out top two pixels
+ /* Write out top two pixels */
rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
- //Skip down to next line to write out bottom two pixels
+ /* Skip down to next line to write out bottom two pixels */
rgb += 3 * rowPixels;
rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
}
-
/*
* For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
* The first 64 bytes of each segment are U, the next 64 are V. The U and
@@ -1155,13 +1131,13 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
#undef OV511_DUMPPIX
static void
-ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
+ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
int iOutY, int iOutUV, int iHalf, int iWidth)
{
#ifndef OV511_DUMPPIX
int k, l, m;
- unsigned char * pIn;
- unsigned char * pOut, * pOut1;
+ unsigned char *pIn;
+ unsigned char *pOut, *pOut1;
/* Just copy the Y's if in the first stripe */
if (!iHalf) {
@@ -1232,7 +1208,6 @@ ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
pOut += 8 * 3;
}
}
-
#else
/* Just dump pix data straight out for debug */
int i, j;
@@ -1249,7 +1224,6 @@ ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
#endif
}
-
/*
* For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
* The segments represent 4 squares of 8x8 pixels as follows:
@@ -1257,11 +1231,11 @@ ov511_parse_data_rgb24(unsigned char * pIn0, unsigned char * pOut0,
* 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
* 8 9 ... 15 72 73 ... 79 200 201 ... 207
* ... ... ...
- * 56 57 ... 63 120 121 127 248 249 ... 255
+ * 56 57 ... 63 120 121 ... 127 248 249 ... 255
*
*/
static void
-ov511_parse_data_grey(unsigned char * pIn0, unsigned char * pOut0,
+ov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0,
int iOutY, int iWidth)
{
int k, l, m;
@@ -1276,13 +1250,12 @@ ov511_parse_data_grey(unsigned char * pIn0, unsigned char * pOut0,
for (m = 0; m < 8; m++) {
*pOut1++ = *pIn++;
}
- pOut1 += iWidth - 8;
+ pOut1 += iWidth - WDIV;
}
pOut += 8;
}
}
-
/*
* fixFrameRGBoffset--
* My camera seems to return the red channel about 1 pixel
@@ -1317,7 +1290,6 @@ static void fixFrameRGBoffset(struct ov511_frame *frame)
}
}
-
/**********************************************************************
*
* OV511 data transfer, IRQ handler
@@ -1488,7 +1460,6 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
return totlen;
}
-
static void ov511_isoc_irq(struct urb *urb)
{
int len;
@@ -1520,7 +1491,6 @@ static void ov511_isoc_irq(struct urb *urb)
return;
}
-
static int ov511_init_isoc(struct usb_ov511 *ov511)
{
urb_t *urb;
@@ -1595,7 +1565,6 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
return 0;
}
-
static void ov511_stop_isoc(struct usb_ov511 *ov511)
{
if (!ov511->streaming || !ov511->dev)
@@ -1622,7 +1591,6 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511)
}
}
-
static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
{
struct ov511_frame *frame;
@@ -1658,25 +1626,17 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
/* Make sure it's not too big */
if (width > DEFAULT_WIDTH)
width = DEFAULT_WIDTH;
-#if 0
- width = (width / 8) * 8; /* Multiple of 8 */
-#endif
- width &= ~7L;
+
+ width &= ~7L; /* Multiple of 8 */
if (height > DEFAULT_HEIGHT)
height = DEFAULT_HEIGHT;
-#if 0
- height = (height / 4) * 4; /* Multiple of 4 */
-#endif
- width &= ~3L;
-// /* We want a fresh frame every 30 we get */
-// ov511->compress = (ov511->compress + 1) % 30;
+ width &= ~3L; /* Multiple of 4 */
return 0;
}
-
/****************************************************************************
*
* V4L API
@@ -1687,43 +1647,45 @@ static int ov511_open(struct video_device *dev, int flags)
{
int err = -EBUSY;
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+ int i;
- PDEBUG(4, "ov511_open");
+ PDEBUG(4, "opening");
down(&ov511->lock);
- if (ov511->user)
- goto out_unlock;
- ov511->frame[0].grabstate = FRAME_UNUSED;
- ov511->frame[1].grabstate = FRAME_UNUSED;
+ if (ov511->user) {
+ up(&ov511->lock);
+ return -EBUSY;
+ }
err = -ENOMEM;
/* Allocate memory for the frame buffers */
- ov511->fbuf = rvmalloc(2 * MAX_DATA_SIZE);
+ ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE);
if (!ov511->fbuf)
- goto open_err_ret;
+ return err;
- ov511->frame[0].data = ov511->fbuf;
- ov511->frame[1].data = ov511->fbuf + MAX_DATA_SIZE;
ov511->sub_flag = 0;
- PDEBUG(4, "frame [0] @ %p", ov511->frame[0].data);
- PDEBUG(4, "frame [1] @ %p", ov511->frame[1].data);
+ for (i = 0; i < OV511_NUMFRAMES; i++) {
+ ov511->frame[i].grabstate = FRAME_UNUSED;
+ ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE;
+ PDEBUG(4, "frame [%d] @ %p", i, ov511->frame[0].data);
- ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ov511->sbuf[0].data)
- goto open_err_on0;
- ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ov511->sbuf[1].data)
- goto open_err_on1;
-
- PDEBUG(4, "sbuf[0] @ %p", ov511->sbuf[0].data);
- PDEBUG(4, "sbuf[1] @ %p", ov511->sbuf[1].data);
+ ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+ MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!ov511->sbuf[i].data) {
+open_free_ret:
+ while (--i) kfree(ov511->sbuf[i].data);
+ rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
+ return err;
+ }
+ PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);
+ }
err = ov511_init_isoc(ov511);
if (err)
- goto open_err_on2;
+ goto open_free_ret;
ov511->user++;
up(&ov511->lock);
@@ -1731,24 +1693,12 @@ static int ov511_open(struct video_device *dev, int flags)
MOD_INC_USE_COUNT;
return 0;
-
-open_err_on2:
- kfree (ov511->sbuf[1].data);
-open_err_on1:
- kfree (ov511->sbuf[0].data);
-open_err_on0:
- rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
-open_err_ret:
- return err;
-out_unlock:
- up(&ov511->lock);
- return err;
}
-
static void ov511_close(struct video_device *dev)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+ int i;
PDEBUG(4, "ov511_close");
@@ -1759,10 +1709,9 @@ static void ov511_close(struct video_device *dev)
ov511_stop_isoc(ov511);
- rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
-
- kfree(ov511->sbuf[1].data);
- kfree(ov511->sbuf[0].data);
+ rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);
+ for (i = 0; i < OV511_NUMFRAMES; i++)
+ kfree(ov511->sbuf[i].data);
up(&ov511->lock);
@@ -1772,7 +1721,6 @@ static void ov511_close(struct video_device *dev)
}
}
-
static int ov511_init_done(struct video_device *dev)
{
#ifdef CONFIG_PROC_FS
@@ -1782,13 +1730,11 @@ static int ov511_init_done(struct video_device *dev)
return 0;
}
-
static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
}
-
static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
@@ -2097,7 +2043,6 @@ redo:
return 0;
}
-
static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
@@ -2138,10 +2083,6 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
frame = &ov511->frame[frmx];
- /* FIXME */
- frame->segsize = frame->format == VIDEO_PALETTE_RGB24 ? 384 : 256;
- frame->depth = frame->format == VIDEO_PALETTE_RGB24 ? 24 : 8;
-
restart:
if (!ov511->dev)
return -EIO;
@@ -2165,11 +2106,8 @@ restart:
/* Repeat until we get a snapshot frame */
- if (!ov511->snap_enabled) {
- PDEBUG (4, "snap disabled");
- } else {
+ if (ov511->snap_enabled)
PDEBUG (4, "Waiting snapshot frame");
- }
if (ov511->snap_enabled && !frame->snapshot) {
frame->bytes_read = 0;
if (ov511_new_frame(ov511, frmx))
@@ -2178,13 +2116,11 @@ restart:
}
/* Clear the snapshot */
- if (ov511->snap_enabled)
- PDEBUG (4, "Clear snapshot");
if (ov511->snap_enabled && frame->snapshot) {
frame->snapshot = 0;
- ov511_reg_write(ov511->dev, 0x52, 0x01);
- ov511_reg_write(ov511->dev, 0x52, 0x03);
- ov511_reg_write(ov511->dev, 0x52, 0x01);
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
+ ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
}
PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
@@ -2212,7 +2148,7 @@ restart:
/* Mark it as available to be used again. */
ov511->frame[frmx].grabstate = FRAME_UNUSED;
- if (ov511_new_frame(ov511, frmx ? 0 : 1))
+ if (ov511_new_frame(ov511, !frmx))
err("ov511_new_frame returned error");
}
@@ -2221,7 +2157,6 @@ restart:
return count;
}
-
static int ov511_mmap(struct video_device *dev, const char *adr,
unsigned long size)
{
@@ -2229,7 +2164,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr,
unsigned long start = (unsigned long)adr;
unsigned long page, pos;
- if (!ov511->dev)
+ if (ov511->dev == NULL)
return -EIO;
PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
@@ -2238,8 +2173,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr,
return -EINVAL;
pos = (unsigned long)ov511->fbuf;
- while (size > 0)
- {
+ while (size > 0) {
page = kvirt_to_pa(pos);
if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
@@ -2254,7 +2188,6 @@ static int ov511_mmap(struct video_device *dev, const char *adr,
return 0;
}
-
static struct video_device ov511_template = {
name: "OV511 USB Camera",
type: VID_TYPE_CAPTURE,
@@ -2268,7 +2201,6 @@ static struct video_device ov511_template = {
initialize: ov511_init_done,
};
-
/****************************************************************************
*
* OV511/OV7610 configuration
@@ -2281,68 +2213,70 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
int i, success;
int rc;
- static struct ov511_regvals aRegvalsNorm7610[] =
- {{OV511_I2C_BUS, 0x10, 0xff},
- {OV511_I2C_BUS, 0x16, 0x06},
- {OV511_I2C_BUS, 0x28, 0x24},
- {OV511_I2C_BUS, 0x2b, 0xac},
- {OV511_I2C_BUS, 0x05, 0x00},
- {OV511_I2C_BUS, 0x06, 0x00},
- {OV511_I2C_BUS, 0x12, 0x00},
- {OV511_I2C_BUS, 0x38, 0x81},
- {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
- {OV511_I2C_BUS, 0x05, 0x00},
- {OV511_I2C_BUS, 0x0f, 0x05},
- {OV511_I2C_BUS, 0x15, 0x01},
- {OV511_I2C_BUS, 0x20, 0x1c},
- {OV511_I2C_BUS, 0x23, 0x2a},
- {OV511_I2C_BUS, 0x24, 0x10},
- {OV511_I2C_BUS, 0x25, 0x8a},
- {OV511_I2C_BUS, 0x27, 0xc2},
- {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
- {OV511_I2C_BUS, 0x2a, 0x04},
- {OV511_I2C_BUS, 0x2c, 0xfe},
- {OV511_I2C_BUS, 0x30, 0x71},
- {OV511_I2C_BUS, 0x31, 0x60},
- {OV511_I2C_BUS, 0x32, 0x26},
- {OV511_I2C_BUS, 0x33, 0x20},
- {OV511_I2C_BUS, 0x34, 0x48},
- {OV511_I2C_BUS, 0x12, 0x24},
- {OV511_I2C_BUS, 0x11, 0x01},
- {OV511_I2C_BUS, 0x0c, 0x24},
- {OV511_I2C_BUS, 0x0d, 0x24},
- {OV511_DONE_BUS, 0x0, 0x00},
+ static struct ov511_regvals aRegvalsNorm7610[] = {
+ { OV511_I2C_BUS, 0x10, 0xff },
+ { OV511_I2C_BUS, 0x16, 0x06 },
+ { OV511_I2C_BUS, 0x28, 0x24 },
+ { OV511_I2C_BUS, 0x2b, 0xac },
+ { OV511_I2C_BUS, 0x05, 0x00 },
+ { OV511_I2C_BUS, 0x06, 0x00 },
+ { OV511_I2C_BUS, 0x12, 0x00 },
+ { OV511_I2C_BUS, 0x38, 0x81 },
+ { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */
+ { OV511_I2C_BUS, 0x05, 0x00 },
+ { OV511_I2C_BUS, 0x0f, 0x05 },
+ { OV511_I2C_BUS, 0x15, 0x01 },
+ { OV511_I2C_BUS, 0x20, 0x1c },
+ { OV511_I2C_BUS, 0x23, 0x2a },
+ { OV511_I2C_BUS, 0x24, 0x10 },
+ { OV511_I2C_BUS, 0x25, 0x8a },
+ { OV511_I2C_BUS, 0x27, 0xc2 },
+ { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */
+ { OV511_I2C_BUS, 0x2a, 0x04 },
+ { OV511_I2C_BUS, 0x2c, 0xfe },
+ { OV511_I2C_BUS, 0x30, 0x71 },
+ { OV511_I2C_BUS, 0x31, 0x60 },
+ { OV511_I2C_BUS, 0x32, 0x26 },
+ { OV511_I2C_BUS, 0x33, 0x20 },
+ { OV511_I2C_BUS, 0x34, 0x48 },
+ { OV511_I2C_BUS, 0x12, 0x24 },
+ { OV511_I2C_BUS, 0x11, 0x01 },
+ { OV511_I2C_BUS, 0x0c, 0x24 },
+ { OV511_I2C_BUS, 0x0d, 0x24 },
+ { OV511_DONE_BUS, 0x0, 0x00 },
};
- static struct ov511_regvals aRegvalsNorm7620[] =
- {{OV511_I2C_BUS, 0x10, 0xff},
- {OV511_I2C_BUS, 0x16, 0x06},
- {OV511_I2C_BUS, 0x28, 0x24},
- {OV511_I2C_BUS, 0x2b, 0xac},
- {OV511_I2C_BUS, 0x12, 0x00},
- {OV511_I2C_BUS, 0x28, 0x24},
- {OV511_I2C_BUS, 0x05, 0x00},
- {OV511_I2C_BUS, 0x0f, 0x05},
- {OV511_I2C_BUS, 0x15, 0x01},
- {OV511_I2C_BUS, 0x23, 0x00},
- {OV511_I2C_BUS, 0x24, 0x10},
- {OV511_I2C_BUS, 0x25, 0x8a},
- {OV511_I2C_BUS, 0x27, 0xe2},
- {OV511_I2C_BUS, 0x29, 0x03},
- {OV511_I2C_BUS, 0x2a, 0x00},
- {OV511_I2C_BUS, 0x2c, 0xfe},
- {OV511_I2C_BUS, 0x30, 0x71},
- {OV511_I2C_BUS, 0x31, 0x60},
- {OV511_I2C_BUS, 0x32, 0x26},
- {OV511_I2C_BUS, 0x33, 0x20},
- {OV511_I2C_BUS, 0x34, 0x48},
- {OV511_I2C_BUS, 0x12, 0x24},
- {OV511_I2C_BUS, 0x11, 0x01},
- {OV511_I2C_BUS, 0x0c, 0x24},
- {OV511_I2C_BUS, 0x0d, 0x24},
- {OV511_DONE_BUS, 0x0, 0x00},
+ static struct ov511_regvals aRegvalsNorm7620[] = {
+ { OV511_I2C_BUS, 0x10, 0xff },
+ { OV511_I2C_BUS, 0x16, 0x06 },
+ { OV511_I2C_BUS, 0x28, 0x24 },
+ { OV511_I2C_BUS, 0x2b, 0xac },
+ { OV511_I2C_BUS, 0x12, 0x00 },
+ { OV511_I2C_BUS, 0x28, 0x24 },
+ { OV511_I2C_BUS, 0x05, 0x00 },
+ { OV511_I2C_BUS, 0x0f, 0x05 },
+ { OV511_I2C_BUS, 0x15, 0x01 },
+ { OV511_I2C_BUS, 0x23, 0x00 },
+ { OV511_I2C_BUS, 0x24, 0x10 },
+ { OV511_I2C_BUS, 0x25, 0x8a },
+ { OV511_I2C_BUS, 0x27, 0xe2 },
+ { OV511_I2C_BUS, 0x29, 0x03 },
+ { OV511_I2C_BUS, 0x2a, 0x00 },
+ { OV511_I2C_BUS, 0x2c, 0xfe },
+ { OV511_I2C_BUS, 0x30, 0x71 },
+ { OV511_I2C_BUS, 0x31, 0x60 },
+ { OV511_I2C_BUS, 0x32, 0x26 },
+ { OV511_I2C_BUS, 0x33, 0x20 },
+ { OV511_I2C_BUS, 0x34, 0x48 },
+ { OV511_I2C_BUS, 0x12, 0x24 },
+ { OV511_I2C_BUS, 0x11, 0x01 },
+ { OV511_I2C_BUS, 0x0c, 0x24 },
+ { OV511_I2C_BUS, 0x0d, 0x24 },
+ { OV511_DONE_BUS, 0x0, 0x00 },
};
+ PDEBUG (4, "starting configuration");
+
if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
OV7610_I2C_WRITE_ID) < 0)
return -1;
@@ -2385,13 +2319,13 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
err("Error detecting sensor type");
return -1;
} else if((rc & 3) == 3) {
- printk("ov511: Sensor is an OV7610\n");
+ info("Sensor is an OV7610");
ov511->sensor = SEN_OV7610;
} else if((rc & 3) == 1) {
- printk("ov511: Sensor is an OV7620AE\n");
+ info("Sensor is an OV7620AE");
ov511->sensor = SEN_OV7620AE;
} else if((rc & 3) == 0) {
- printk("ov511: Sensor is an OV7620\n");
+ info("Sensor is an OV7620");
ov511->sensor = SEN_OV7620;
} else {
err("Unknown image sensor version: %d", rc & 3);
@@ -2399,13 +2333,15 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
}
} else { /* sensor != 0; user overrode detection */
ov511->sensor = sensor;
- printk("ov511: Sensor set to type %d\n", ov511->sensor);
+ info("Sensor set to type %d", ov511->sensor);
}
if (ov511->sensor == SEN_OV7620) {
+ PDEBUG(4, "Writing 7620 registers");
if (ov511_write_regvals(dev, aRegvalsNorm7620))
return -1;
} else {
+ PDEBUG(4, "Writing 7610 registers");
if (ov511_write_regvals(dev, aRegvalsNorm7610))
return -1;
}
@@ -2438,34 +2374,35 @@ static int ov76xx_configure(struct usb_ov511 *ov511)
static int ov511_configure(struct usb_ov511 *ov511)
{
struct usb_device *dev = ov511->dev;
+ int i;
- static struct ov511_regvals aRegvalsInit[] =
- {{OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f},
- {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01},
- {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f},
- {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01},
- {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f},
- {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01},
- {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d},
- {OV511_DONE_BUS, 0x0, 0x00},
+ static struct ov511_regvals aRegvalsInit[] = {
+ { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d },
+ { OV511_DONE_BUS, 0x0, 0x00},
};
- static struct ov511_regvals aRegvalsNorm511[] =
- {{OV511_REG_BUS, 0x20, 0x01},
- {OV511_REG_BUS, 0x52, 0x02},
- {OV511_REG_BUS, 0x52, 0x00},
- {OV511_REG_BUS, 0x31, 0x1f}, /* 0f */
- {OV511_REG_BUS, 0x70, 0x3f},
- {OV511_REG_BUS, 0x71, 0x3f},
- {OV511_REG_BUS, 0x72, 0x01},
- {OV511_REG_BUS, 0x73, 0x01},
- {OV511_REG_BUS, 0x74, 0x01},
- {OV511_REG_BUS, 0x75, 0x01},
- {OV511_REG_BUS, 0x76, 0x01},
- {OV511_REG_BUS, 0x77, 0x01},
- {OV511_REG_BUS, 0x78, 0x06},
- {OV511_REG_BUS, 0x79, 0x03},
- {OV511_DONE_BUS, 0x0, 0x00},
+ static struct ov511_regvals aRegvalsNorm511[] = {
+ { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 },
+ { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 },
+ { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, /* 0f */
+ { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x3f },
+ { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x3f },
+ { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_UV, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_UV, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_UV, 0x01 },
+ { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x06 },
+ { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 },
+ { OV511_DONE_BUS, 0x0, 0x00 },
};
memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
@@ -2488,16 +2425,15 @@ static int ov511_configure(struct usb_ov511 *ov511)
/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
* (using read() instead). */
- ov511->frame[0].width = DEFAULT_WIDTH;
- ov511->frame[0].height = DEFAULT_HEIGHT;
- ov511->frame[0].depth = 24; /**************/
- ov511->frame[0].bytes_read = 0;
- ov511->frame[0].segment = 0;
- ov511->frame[1].width = DEFAULT_WIDTH;
- ov511->frame[1].height = DEFAULT_HEIGHT;
- ov511->frame[1].depth = 24;
- ov511->frame[1].bytes_read = 0;
- ov511->frame[1].segment = 0;
+ for (i = 0; i < OV511_NUMFRAMES; i++) {
+ ov511->frame[i].width = DEFAULT_WIDTH;
+ ov511->frame[i].height = DEFAULT_HEIGHT;
+ ov511->frame[i].depth = 24;
+ ov511->frame[i].bytes_read = 0;
+ ov511->frame[i].segment = 0;
+ ov511->frame[i].format = VIDEO_PALETTE_RGB24;
+ ov511->frame[i].segsize = GET_SEGSIZE(ov511->frame[i].format);
+ }
/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
@@ -2588,7 +2524,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
PDEBUG (4, "CustomID = %d", ov511->customid);
for (i = 0; clist[i].id >= 0; i++) {
if (ov511->customid == clist[i].id) {
- printk ("Camera: %s\n", clist[i].description);
+ info("camera: %s", clist[i].description);
ov511->desc = i;
break;
}
@@ -2606,6 +2542,11 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
err("support for your camera.");
}
+ /* Workaround for some applications that want data in RGB
+ * instead of BGR */
+ if (force_rgb)
+ info("data format set to RGB");
+
if (!ov511_configure(ov511)) {
ov511->user = 0;
init_MUTEX(&ov511->lock); /* to 1 == available */
@@ -2670,7 +2611,6 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
}
#ifdef CONFIG_PROC_FS
- PDEBUG(3, "destroying /proc/ov511/video%d", ov511->vdev.minor);
destroy_proc_ov511_cam(ov511);
#endif
@@ -2712,13 +2652,12 @@ static int __init usb_ov511_init(void)
static void __exit usb_ov511_exit(void)
{
+ usb_deregister(&ov511_driver);
+ info("ov511 driver deregistered");
+
#ifdef CONFIG_PROC_FS
- PDEBUG(3, "destroying /proc/ov511");
proc_ov511_destroy();
#endif
-
- usb_deregister(&ov511_driver);
- info("ov511 driver deregistered");
}
module_init(usb_ov511_init);
diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h
index 5b8ce967d..d3a9a78ba 100644
--- a/drivers/usb/ov511.h
+++ b/drivers/usb/ov511.h
@@ -1,3 +1,4 @@
+
#ifndef __LINUX_OV511_H
#define __LINUX_OV511_H
@@ -9,7 +10,7 @@
#ifdef OV511_DEBUG
# define PDEBUG(level, fmt, args...) \
-if (debug >= level) printk("ov511: [" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LINE__ , ## args)
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
#else
# define PDEBUG(level, fmt, args...) do {} while(0)
#endif
@@ -119,48 +120,55 @@ if (debug >= level) printk("ov511: [" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LI
#define OV511PLUS_ALT_SIZE_961 7
/* OV7610 registers */
-#define OV7610_REG_GAIN 0x00
-#define OV7610_REG_BLUE 0x01
-#define OV7610_REG_RED 0x02
-#define OV7610_REG_SAT 0x03
-#define OV7610_REG_CNT 0x05
-#define OV7610_REG_BRT 0x06
-#define OV7610_REG_BLUE_BIAS 0x0C
-#define OV7610_REG_RED_BIAS 0x0D
-#define OV7610_REG_GAMMA_COEFF 0x0E
-#define OV7610_REG_WB_RANGE 0x0F
-#define OV7610_REG_EXP 0x10
-#define OV7610_REG_CLOCK 0x11
-#define OV7610_REG_COM_A 0x12
-#define OV7610_REG_COM_B 0x13
-#define OV7610_REG_COM_C 0x14
-#define OV7610_REG_COM_D 0x15
-#define OV7610_REG_FIELD_DIVIDE 0x16
-#define OV7610_REG_HWIN_START 0x17
-#define OV7610_REG_HWIN_END 0x18
-#define OV7610_REG_VWIN_START 0x19
-#define OV7610_REG_VWIN_END 0x1A
-#define OV7610_REG_PIXEL_SHIFT 0x1B
-#define OV7610_REG_ID_HIGH 0x1C
-#define OV7610_REG_ID_LOW 0x1D
-#define OV7610_REG_COM_E 0x20
-#define OV7610_REG_YOFFSET 0x21
-#define OV7610_REG_UOFFSET 0x22
-#define OV7610_REG_ECW 0x24
-#define OV7610_REG_ECB 0x25
-#define OV7610_REG_COM_F 0x26
-#define OV7610_REG_COM_G 0x27
-#define OV7610_REG_COM_H 0x28
-#define OV7610_REG_COM_I 0x29
-#define OV7610_REG_FRAMERATE_H 0x2A
-#define OV7610_REG_FRAMERATE_L 0x2B
-#define OV7610_REG_ALC 0x2C
-#define OV7610_REG_COM_J 0x2D
-#define OV7610_REG_VOFFSET 0x2E
-#define OV7610_REG_YGAMMA 0x33
-#define OV7610_REG_BIAS_ADJUST 0x34
-#define OV7610_REG_COM_L 0x35
-#define OV7610_REG_COM_K 0x38
+#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
+#define OV7610_REG_BLUE 0x01 /* blue channel balance */
+#define OV7610_REG_RED 0x02 /* red channel balance */
+#define OV7610_REG_SAT 0x03 /* saturation */
+ /* 04 reserved */
+#define OV7610_REG_CNT 0x05 /* Y contrast */
+#define OV7610_REG_BRT 0x06 /* Y brightness */
+ /* 08-0b reserved */
+#define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */
+#define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */
+#define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */
+#define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
+#define OV7610_REG_EXP 0x10 /* manual exposure setting */
+#define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */
+#define OV7610_REG_COM_A 0x12 /* misc common regs */
+#define OV7610_REG_COM_B 0x13 /* misc common regs */
+#define OV7610_REG_COM_C 0x14 /* misc common regs */
+#define OV7610_REG_COM_D 0x15 /* misc common regs */
+#define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
+#define OV7610_REG_HWIN_START 0x17 /* horizontal window start */
+#define OV7610_REG_HWIN_END 0x18 /* horizontal window end */
+#define OV7610_REG_VWIN_START 0x19 /* vertical window start */
+#define OV7610_REG_VWIN_END 0x1A /* vertical window end */
+#define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */
+#define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */
+ /* 0e-0f reserved */
+#define OV7610_REG_COM_E 0x20 /* misc common regs */
+#define OV7610_REG_YOFFSET 0x21 /* Y channel offset */
+#define OV7610_REG_UOFFSET 0x22 /* U channel offset */
+ /* 23 reserved */
+#define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */
+#define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */
+#define OV7610_REG_COM_F 0x26 /* misc settings */
+#define OV7610_REG_COM_G 0x27 /* misc settings */
+#define OV7610_REG_COM_H 0x28 /* misc settings */
+#define OV7610_REG_COM_I 0x29 /* misc settings */
+#define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
+#define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */
+#define OV7610_REG_ALC 0x2C /* Auto Level Control settings */
+#define OV7610_REG_COM_J 0x2D /* misc settings */
+#define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */
+#define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */
+ /* 30-32 reserved */
+#define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */
+#define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */
+#define OV7610_REG_COM_L 0x35 /* misc settings */
+ /* 36-37 reserved */
+#define OV7610_REG_COM_K 0x38 /* misc registers */
#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
@@ -171,8 +179,7 @@ if (debug >= level) printk("ov511: [" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LI
#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */
#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */
-// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
-#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
+#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
// CAMERA SPECIFIC
// FIXME - these can vary between specific models
@@ -223,9 +230,9 @@ enum {
struct ov511_regvals {
enum {
- OV511_DONE_BUS,
- OV511_REG_BUS,
- OV511_I2C_BUS,
+ OV511_DONE_BUS,
+ OV511_REG_BUS,
+ OV511_I2C_BUS,
} bus;
unsigned char reg;
unsigned char val;
@@ -269,15 +276,16 @@ struct usb_ov511 {
/* Device structure */
struct usb_device *dev;
-#if 0
- unsigned char customid; /* Type of camera */
-#else
int customid;
int desc;
-#endif
-
unsigned char iface;
+ int brightness;
+ int colour;
+ int contrast;
+ int hue;
+ int whiteness;
+
struct semaphore lock;
int user; /* user count for exclusive use */
@@ -318,11 +326,34 @@ struct usb_ov511 {
struct proc_dir_entry *proc_entry; /* /proc/ov511/videoX */
};
-
struct cam_list {
int id;
char *description;
};
+struct palette_list {
+ int num;
+ char *name;
+};
+
+struct mode_list {
+ int width;
+ int height;
+ int mode;
+ u8 pxcnt;
+ u8 lncnt;
+ u8 pxdv;
+ u8 lndv;
+ u8 s_pxcnt;
+ u8 s_lncnt;
+ u8 s_pxdv;
+ u8 s_lndv;
+ u8 clock;
+ u8 m420;
+ u8 common_A;
+ u8 common_C;
+ u8 common_L;
+};
+
#endif
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 7f4459d2f..b40a947ed 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -16,7 +16,7 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.12 2000/05/22 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500
@@ -24,12 +24,15 @@ static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Mano
#define SROM_WRITE 0x01
#define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
+#define PEGASUS_RESET 1
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
+
struct pegasus {
struct usb_device *usb;
struct net_device *net;
struct net_device_stats stats;
+ int flags;
spinlock_t pegasus_lock;
struct urb rx_urb, tx_urb, intr_urb;
unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
@@ -44,9 +47,11 @@ struct usb_eth_dev {
void *private;
};
+
static int loopback = 0;
static int multicast_filter_limit = 32;
+
MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
@@ -98,6 +103,7 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd
return 1;
}
+
static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
{
int i;
@@ -115,6 +121,7 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
return 1;
}
+
static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
@@ -134,6 +141,7 @@ static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retda
return 1;
}
+
static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
{
int i;
@@ -143,6 +151,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
return 0;
}
+
static int pegasus_reset_mac(struct usb_device *dev)
{
__u8 data = 0x8;
@@ -165,6 +174,7 @@ static int pegasus_reset_mac(struct usb_device *dev)
return 1;
}
+
static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
{
__u16 partmedia, temp;
@@ -195,13 +205,14 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
data[0] = 0xc9;
data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
- data[2] = (loopback & 1) ? 0x08 : 0x00;
+ data[2] = (loopback & 1) ? 0x09 : 0x01;
pegasus_set_registers(usb, 0, 3, data);
return 0;
}
+
static void pegasus_read_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
@@ -253,15 +264,16 @@ goon:
warn("(prb)failed rx_urb %d", res);
}
+
static void pegasus_irq(urb_t *urb)
{
- if(urb->status) {
- __u8 *d = urb->transfer_buffer;
- printk("txst0 %x, txst1 %x, rxst %x, rxlst0 %x, rxlst1 %x, wakest %x",
- d[0], d[1], d[2], d[3], d[4], d[5]);
- }
+ __u8 *d = urb->transfer_buffer;
+
+ if ( d[0] )
+ dbg("txst0=0x%2x", d[0]);
}
+
static void pegasus_write_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
@@ -280,12 +292,15 @@ static void pegasus_tx_timeout(struct net_device *net)
struct pegasus *pegasus = net->priv;
warn("%s: Tx timed out. Reseting...", net->name);
+ usb_unlink_urb(&pegasus->tx_urb);
pegasus->stats.tx_errors++;
net->trans_start = jiffies;
+ pegasus->flags |= PEGASUS_RESET;
netif_wake_queue(net);
}
+
static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
{
struct pegasus *pegasus = net->priv;
@@ -317,11 +332,13 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
return 0;
}
+
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
{
return &((struct pegasus *)dev->priv)->stats;
}
+
static int pegasus_open(struct net_device *net)
{
struct pegasus *pegasus = (struct pegasus *)net->priv;
@@ -334,8 +351,10 @@ static int pegasus_open(struct net_device *net)
if ((res = usb_submit_urb(&pegasus->rx_urb)))
warn("(open)failed rx_urb %d", res);
-
-/* usb_submit_urb(&pegasus->intr_urb);*/
+
+ if ((res = usb_submit_urb(&pegasus->intr_urb)))
+ warn("(open)failed intr_urb %d", res);
+
netif_start_queue(net);
MOD_INC_USE_COUNT;
@@ -343,6 +362,7 @@ static int pegasus_open(struct net_device *net)
return 0;
}
+
static int pegasus_close(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
@@ -351,13 +371,14 @@ static int pegasus_close(struct net_device *net)
usb_unlink_urb(&pegasus->rx_urb);
usb_unlink_urb(&pegasus->tx_urb);
-/* usb_unlink_urb(&pegasus->intr_urb); */
+ usb_unlink_urb(&pegasus->intr_urb);
MOD_DEC_USE_COUNT;
return 0;
}
+
static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
__u16 *data = (__u16 *)&rq->ifr_data;
@@ -379,6 +400,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
}
}
+
static void pegasus_set_rx_mode(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
@@ -400,6 +422,7 @@ static void pegasus_set_rx_mode(struct net_device *net)
netif_wake_queue(net);
}
+
static int check_device_ids( __u16 vendor, __u16 product )
{
int i=0;
@@ -413,6 +436,7 @@ static int check_device_ids( __u16 vendor, __u16 product )
return -1;
}
+
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
@@ -463,7 +487,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
pegasus);
FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
- pegasus->intr_buff, 8, pegasus_irq, pegasus, 250);
+ pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
@@ -471,6 +495,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
return pegasus;
}
+
static void pegasus_disconnect(struct usb_device *dev, void *ptr)
{
struct pegasus *pegasus = ptr;
@@ -487,11 +512,12 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb(&pegasus->rx_urb);
usb_unlink_urb(&pegasus->tx_urb);
-/* usb_unlink_urb(&pegasus->intr_urb);*/
+ usb_unlink_urb(&pegasus->intr_urb);
kfree(pegasus);
}
+
static struct usb_driver pegasus_driver = {
name: "pegasus",
probe: pegasus_probe,
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index d64258e8e..c013a8154 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -1,5 +1,5 @@
/*
- * printer.c Version 0.3
+ * printer.c Version 0.4
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
@@ -13,6 +13,7 @@
* v0.1 - thorough cleaning, URBification, almost a rewrite
* v0.2 - some more cleanups
* v0.3 - cleaner again, waitqueue fixes
+ * v0.4 - fixes in unidirectional mode
*/
/*
@@ -102,7 +103,7 @@ static void usblp_bulk(struct urb *urb)
return;
if (urb->status)
- warn("nonzero read bulk status received: %d", urb->status);
+ warn("nonzero read/write bulk status received: %d", urb->status);
wake_up_interruptible(&usblp->wait);
}
@@ -172,9 +173,12 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb.transfer_buffer_length = 0;
usblp->writeurb.status = 0;
- usblp->readcount = 0;
- usb_submit_urb(&usblp->readurb);
+ if (usblp->bidir) {
+ usblp->readcount = 0;
+ usb_submit_urb(&usblp->readurb);
+ }
+
return 0;
}
@@ -185,7 +189,8 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->dev) {
- usb_unlink_urb(&usblp->readurb);
+ if (usblp->bidir)
+ usb_unlink_urb(&usblp->readurb);
usb_unlink_urb(&usblp->writeurb);
MOD_DEC_USE_COUNT;
return 0;
@@ -203,8 +208,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
{
struct usblp *usblp = file->private_data;
poll_wait(file, &usblp->wait, wait);
- return (usblp->readurb.status == -EINPROGRESS ? 0 : POLLIN | POLLRDNORM)
- | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
+ return ((usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM)
+ | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
}
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
@@ -315,7 +320,6 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
int minor, i, alts = -1, bidir = 0;
char *buf;
-
for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
interface = &dev->actconfig->interface[ifnum].altsetting[i];
@@ -342,22 +346,21 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
err("can't set desired altsetting %d on interface %d", alts, ifnum);
epwrite = interface->endpoint + 0;
- epread = NULL;
-
- if (bidir) {
- epread = interface->endpoint + 1;
- if ((epread->bEndpointAddress & 0x80) != 0x80) {
- epwrite = interface->endpoint + 1;
- epread = interface->endpoint + 0;
+ epread = bidir ? interface->endpoint + 1 : NULL;
- if ((epread->bEndpointAddress & 0x80) != 0x80)
- return NULL;
- }
+ if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
+ if (interface->bNumEndpoints == 1)
+ return NULL;
+ epwrite = interface->endpoint + 1;
+ epread = bidir ? interface->endpoint + 0 : NULL;
}
if ((epwrite->bEndpointAddress & 0x80) == 0x80)
return NULL;
+ if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
+ return NULL;
+
for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
if (usblp_table[minor]) {
err("no more free usblp devices");
@@ -386,10 +389,9 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf, 0, usblp_bulk, usblp);
- if (bidir) {
+ if (bidir)
FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
- }
info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
@@ -408,8 +410,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
usblp->dev = NULL;
- usb_unlink_urb(&usblp->readurb);
usb_unlink_urb(&usblp->writeurb);
+ if (usblp->bidir)
+ usb_unlink_urb(&usblp->readurb);
kfree(usblp->writeurb.transfer_buffer);
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index fa69fa52a..7d24c34f9 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -4,8 +4,26 @@
O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o digi_acceleport.o
+O_OBJS := usbserial.o
MOD_LIST_NAME := USB_SERIAL_MODULES
+ifeq ($(CONFIG_USB_SERIAL_VISOR),y)
+ O_OBJS += visor.o
+endif
+ifeq ($(CONFIG_USB_SERIAL_WHITEHEAT),y)
+ O_OBJS += whiteheat.o
+endif
+ifeq ($(CONFIG_USB_SERIAL_FTDI_SIO),y)
+ O_OBJS += ftdi_sio.o
+endif
+ifeq ($(CONFIG_USB_SERIAL_KEYSPAN_PDA),y)
+ O_OBJS += keyspan_pda.o
+endif
+ifeq ($(CONFIG_USB_SERIAL_OMNINET),y)
+ O_OBJS += omninet.o
+endif
+ifeq ($(CONFIG_USB_SERIAL_DIGI_ACCELEPORT),y)
+ O_OBJS += digi_acceleport.o
+endif
+
include $(TOPDIR)/Rules.make
-
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 6700f9e01..fe2d2013b 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -14,16 +14,39 @@
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (5/16/2000) pberger and borchers
+* -- added timeouts to sleeps
+* -- handle transition to/from B0 in digi_set_termios
+*
+* (5/13/2000) pberger and borchers
+* -- all commands now sent on out of band port, using digi_write_oob
+* -- get modem control signals whenever they change, support TIOCMGET/
+* SET/BIS/BIC ioctls
+* -- digi_set_termios now supports parity, word size, stop bits, and
+* receive enable
+* -- cleaned up open and close, use digi_set_termios and digi_write_oob
+* to set port parameters
+* -- added digi_startup_device to start read chains on all ports
+* -- write buffer is only used when count==1, to be sure put_char can
+* write a char (unless the buffer is full)
+*
+* (5/10/2000) pberger and borchers
+* -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls
+* -- Fixed problem where the first incoming character is lost on
+* port opens after the first close on that port. Now we keep
+* the read_urb chain open until shutdown.
+* -- Added more port conditioning calls in digi_open and digi_close.
+* -- Convert port->active to a use count so that we can deal with multiple
+* opens and closes properly.
+* -- Fixed some problems with the locking code.
+*
* (5/3/2000) pberger and borchers
-* First alpha version of the driver--many known limitations and bugs.
+* -- First alpha version of the driver--many known limitations and bugs.
*
-* $Id: digi_acceleport.c,v 1.28 2000/05/04 01:47:08 root Exp root $
+* $Id: digi_acceleport.c,v 1.43 2000/05/17 03:21:38 root Exp root $
*/
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -37,45 +60,57 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
#ifdef CONFIG_USB_SERIAL_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
-#include <linux/usb.h>
-#include "usb-serial.h"
/* Defines */
/* port buffer length -- must be <= transfer buffer length - 2 */
/* so we can be sure to send the full buffer in one urb */
-#define DIGI_PORT_BUF_LEN 16
+#define DIGI_PORT_BUF_LEN 16
+
+/* retry timeout while waiting for urb->status to go to 0 */
+#define DIGI_RETRY_TIMEOUT (HZ/10)
/* AccelePort USB Defines */
/* ids */
-#define DIGI_VENDOR_ID 0x05c5
-#define DIGI_ID 0x0004
-
-/* commands */
-#define DIGI_CMD_SET_BAUD_RATE 0
-#define DIGI_CMD_SET_WORD_SIZE 1
-#define DIGI_CMD_SET_PARITY 2
-#define DIGI_CMD_SET_STOP_BITS 3
-#define DIGI_CMD_SET_INPUT_FLOW_CONTROL 4
-#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL 5
-#define DIGI_CMD_SET_DTR_SIGNAL 6
-#define DIGI_CMD_SET_RTS_SIGNAL 7
-#define DIGI_CMD_RECEIVE_ENABLE 10
-#define DIGI_CMD_BREAK_CONTROL 11
-#define DIGI_CMD_LOCAL_LOOPBACK 12
-#define DIGI_CMD_TRANSMIT_IDLE 13
-#define DIGI_CMD_WRITE_UART_REGISTER 15
-#define DIGI_CMD_AND_UART_REGISTER 16
-#define DIGI_CMD_OR_UART_REGISTER 17
-#define DIGI_CMD_SEND_DATA 18
+#define DIGI_VENDOR_ID 0x05c5
+#define DIGI_ID 0x0004
+
+/* commands
+ * "INB": can be used on the in-band endpoint
+ * "OOB": can be used on the out-of-band endpoint
+ */
+#define DIGI_CMD_SET_BAUD_RATE 0 /* INB, OOB */
+#define DIGI_CMD_SET_WORD_SIZE 1 /* INB, OOB */
+#define DIGI_CMD_SET_PARITY 2 /* INB, OOB */
+#define DIGI_CMD_SET_STOP_BITS 3 /* INB, OOB */
+#define DIGI_CMD_SET_INPUT_FLOW_CONTROL 4 /* INB, OOB */
+#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL 5 /* INB, OOB */
+#define DIGI_CMD_SET_DTR_SIGNAL 6 /* INB, OOB */
+#define DIGI_CMD_SET_RTS_SIGNAL 7 /* INB, OOB */
+#define DIGI_CMD_READ_INPUT_SIGNALS 8 /* OOB */
+#define DIGI_CMD_IFLUSH_FIFO 9 /* OOB */
+#define DIGI_CMD_RECEIVE_ENABLE 10 /* INB, OOB */
+#define DIGI_CMD_BREAK_CONTROL 11 /* INB, OOB */
+#define DIGI_CMD_LOCAL_LOOPBACK 12 /* INB, OOB */
+#define DIGI_CMD_TRANSMIT_IDLE 13 /* INB, OOB */
+#define DIGI_CMD_READ_UART_REGISTER 14 /* OOB */
+#define DIGI_CMD_WRITE_UART_REGISTER 15 /* INB, OOB */
+#define DIGI_CMD_AND_UART_REGISTER 16 /* INB, OOB */
+#define DIGI_CMD_OR_UART_REGISTER 17 /* INB, OOB */
+#define DIGI_CMD_SEND_DATA 18 /* INB */
+#define DIGI_CMD_RECEIVE_DATA 19 /* INB */
+#define DIGI_CMD_RECEIVE_DISABLE 20 /* INB */
+#define DIGI_CMD_GET_PORT_TYPE 21 /* OOB */
/* baud rates */
#define DIGI_BAUD_50 0
@@ -102,10 +137,71 @@
#define DIGI_BAUD_230400 21
#define DIGI_BAUD_460800 22
-/* flow control arguments */
-#define DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL 1
-#define DIGI_ENABLE_RTS_CTS_FLOW_CONTROL 2
-#define DIGI_ENABLE_DTR_DSR_FLOW_CONTROL 4
+/* arguments */
+#define DIGI_WORD_SIZE_5 0
+#define DIGI_WORD_SIZE_6 1
+#define DIGI_WORD_SIZE_7 2
+#define DIGI_WORD_SIZE_8 3
+
+#define DIGI_PARITY_NONE 0
+#define DIGI_PARITY_ODD 1
+#define DIGI_PARITY_EVEN 2
+#define DIGI_PARITY_MARK 3
+#define DIGI_PARITY_SPACE 4
+
+#define DIGI_STOP_BITS_1 0
+#define DIGI_STOP_BITS_2 1
+
+#define DIGI_INPUT_FLOW_CONTROL_XON_XOFF 1
+#define DIGI_INPUT_FLOW_CONTROL_RTS 2
+#define DIGI_INPUT_FLOW_CONTROL_DTR 4
+
+#define DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF 1
+#define DIGI_OUTPUT_FLOW_CONTROL_CTS 2
+#define DIGI_OUTPUT_FLOW_CONTROL_DSR 4
+
+#define DIGI_DTR_INACTIVE 0
+#define DIGI_DTR_ACTIVE 1
+#define DIGI_DTR_INPUT_FLOW_CONTROL 2
+
+#define DIGI_RTS_INACTIVE 0
+#define DIGI_RTS_ACTIVE 1
+#define DIGI_RTS_INPUT_FLOW_CONTROL 2
+#define DIGI_RTS_TOGGLE 3
+
+#define DIGI_FLUSH_TX 1
+#define DIGI_FLUSH_RX 2
+#define DIGI_RESUME_TX 4 /* clears xoff condition */
+
+#define DIGI_DISABLE 0
+#define DIGI_ENABLE 1
+
+#define DIGI_DEASSERT 0
+#define DIGI_ASSERT 1
+
+/* in band status codes */
+#define DIGI_OVERRUN_ERROR 4
+#define DIGI_PARITY_ERROR 8
+#define DIGI_FRAMING_ERROR 16
+#define DIGI_BREAK_ERROR 32
+
+/* out of band status */
+#define DIGI_NO_ERROR 0
+#define DIGI_BAD_FIRST_PARAMETER 1
+#define DIGI_BAD_SECOND_PARAMETER 2
+#define DIGI_INVALID_LINE 3
+#define DIGI_INVALID_OPCODE 4
+
+/* input signals */
+#define DIGI_READ_INPUT_SIGNALS_SLOT 1
+#define DIGI_READ_INPUT_SIGNALS_ERR 2
+#define DIGI_READ_INPUT_SIGNALS_BUSY 4
+#define DIGI_READ_INPUT_SIGNALS_PE 8
+#define DIGI_READ_INPUT_SIGNALS_CTS 16
+#define DIGI_READ_INPUT_SIGNALS_DSR 32
+#define DIGI_READ_INPUT_SIGNALS_RI 64
+#define DIGI_READ_INPUT_SIGNALS_DCD 128
+
/* macros */
#define MAX(a,b) (((a)>(b))?(a):(b))
@@ -117,32 +213,21 @@
typedef struct digi_private {
spinlock_t dp_port_lock;
int dp_buf_len;
- char dp_buf[32];
+ unsigned char dp_buf[DIGI_PORT_BUF_LEN];
+ unsigned int dp_modem_signals;
} digi_private_t;
-struct s_digiusb {
- u8 opcode;
- u8 length;
- u8 val;
- u8 pad;
-};
-
/* Local Function Declarations */
-static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
- int length, int val );
-static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 );
+static int digi_write_oob( unsigned char *buf, int count );
+static int digi_set_modem_signals( struct usb_serial_port *port,
+ unsigned int modem_signals );
static void digi_rx_throttle (struct usb_serial_port *port);
static void digi_rx_unthrottle (struct usb_serial_port *port);
-static int digi_setbaud( struct usb_serial_port *port, int baud );
static void digi_set_termios( struct usb_serial_port *port,
struct termios *old_termios );
static void digi_break_ctl( struct usb_serial_port *port, int break_state );
-static int digi_get_modem_info( struct usb_serial *serial,
- unsigned char *value );
-static int digi_set_modem_info( struct usb_serial *serial,
- unsigned char value );
static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg );
static int digi_write( struct usb_serial_port *port, int from_user,
@@ -152,138 +237,186 @@ static int digi_write_room( struct usb_serial_port *port );
static int digi_chars_in_buffer( struct usb_serial_port *port );
static int digi_open( struct usb_serial_port *port, struct file *filp );
static void digi_close( struct usb_serial_port *port, struct file *filp );
-static int digi_startup (struct usb_serial *serial);
+static int digi_startup_device( struct usb_serial *serial );
+static int digi_startup( struct usb_serial *serial );
static void digi_shutdown( struct usb_serial *serial );
static void digi_read_bulk_callback( struct urb *urb );
+static void digi_read_oob( struct urb *urb );
/* Statics */
/* device info needed for the Digi serial converter */
-static __u16 digi_vendor_id = DIGI_VENDOR_ID;
-static __u16 digi_product_id = DIGI_ID;
+static __u16 digi_vendor_id = DIGI_VENDOR_ID;
+static __u16 digi_product_id = DIGI_ID;
/* out of band port */
-static int oob_port_num; /* index of out-of-band port */
-static struct usb_serial_port *oob_port; /* out-of-band control port */
-static int oob_read_started = 0;
+static int oob_port_num; /* index of out-of-band port */
+static struct usb_serial_port *oob_port; /* out-of-band port */
+static int device_startup = 0;
-/* config lock -- used to protect digi statics and globals, like oob vars */
-spinlock_t config_lock;
+/* startup lock -- used to by digi_startup_device */
+spinlock_t startup_lock;
/* Globals */
struct usb_serial_device_type digi_acceleport_device = {
- name: "Digi USB",
- idVendor: &digi_vendor_id,
- idProduct: &digi_product_id,
- needs_interrupt_in: DONT_CARE,
- needs_bulk_in: MUST_HAVE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: 0,
- num_bulk_in: 5,
- num_bulk_out: 5,
- num_ports: 4,
- open: digi_open,
- close: digi_close,
- write: digi_write,
- write_room: digi_write_room,
- write_bulk_callback: digi_write_bulk_callback,
- read_bulk_callback: digi_read_bulk_callback,
- chars_in_buffer: digi_chars_in_buffer,
- throttle: digi_rx_throttle,
- unthrottle: digi_rx_unthrottle,
- ioctl: digi_ioctl,
- set_termios: digi_set_termios,
- break_ctl: digi_break_ctl,
- startup: digi_startup,
- shutdown: digi_shutdown,
+ name: "Digi USB",
+ idVendor: &digi_vendor_id,
+ idProduct: &digi_product_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 0,
+ num_bulk_in: 5,
+ num_bulk_out: 5,
+ num_ports: 4,
+ open: digi_open,
+ close: digi_close,
+ write: digi_write,
+ write_room: digi_write_room,
+ write_bulk_callback: digi_write_bulk_callback,
+ read_bulk_callback: digi_read_bulk_callback,
+ chars_in_buffer: digi_chars_in_buffer,
+ throttle: digi_rx_throttle,
+ unthrottle: digi_rx_unthrottle,
+ ioctl: digi_ioctl,
+ set_termios: digi_set_termios,
+ break_ctl: digi_break_ctl,
+ startup: digi_startup,
+ shutdown: digi_shutdown,
};
/* Functions */
-/* Send message on the out-of-Band endpoint */
-static void digi_send_oob( char *mes, int opcode, int linenum, int data1, int data2 )
+/*
+* Digi Write OOB
+*
+* Write commands on the out of band port. Commands are 4
+* bytes each, multiple commands can be sent at once, and
+* no command will be split across USB packets. Returns 0
+* if successful, -EINTR if interrupted while sleeping, or
+* a negative error returned by usb_submit_urb.
+*/
+
+static int digi_write_oob( unsigned char *buf, int count )
{
- int ret;
- struct s_digiusb digiusb;
- digi_private_t *priv = (digi_private_t *)(oob_port->private);
+ int ret = 0;
+ int len;
+ digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
-dbg( "digi_send_oob: TOP: from '%s', opcode: %d, linenum:%d, data1: %d, data2: %d", mes, opcode, linenum, data1, data2 );
- digiusb.opcode = (u8)opcode;
- digiusb.length = (u8)linenum;
- digiusb.val = (u8)data1;
- digiusb.pad = (u8)data2;
+dbg( "digi_write_oob: TOP: port=%d, count=%d", oob_port->number, count );
- spin_lock( &priv->dp_port_lock );
+ spin_lock( &oob_priv->dp_port_lock );
- while (oob_port->write_urb->status == -EINPROGRESS) {
-dbg( "digi_send_oob: opcode:%d already writing...", opcode );
- spin_unlock( &priv->dp_port_lock );
- interruptible_sleep_on(&oob_port->write_wait);
- if (signal_pending(current)) {
- return;
+ while( count > 0 ) {
+
+ while( oob_port->write_urb->status == -EINPROGRESS ) {
+ spin_unlock( &oob_priv->dp_port_lock );
+ interruptible_sleep_on_timeout( &oob_port->write_wait,
+ DIGI_RETRY_TIMEOUT );
+ if( signal_pending(current) ) {
+ return( -EINTR );
+ }
+ spin_lock( &oob_priv->dp_port_lock );
+ }
+
+ /* len must be a multiple of 4, so commands are not split */
+ len = MIN( count, oob_port->bulk_out_size );
+ if( len > 4 )
+ len &= ~3;
+
+ memcpy( oob_port->write_urb->transfer_buffer, buf, len );
+ oob_port->write_urb->transfer_buffer_length = len;
+
+ if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+ count -= len;
+ buf += len;
+ } else {
+ dbg( "digi_write_oob: usb_submit_urb failed, ret=%d",
+ ret );
+ break;
}
- spin_lock( &priv->dp_port_lock );
- }
- memcpy( oob_port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
- oob_port->write_urb->transfer_buffer_length = sizeof(digiusb);
- if( (ret=usb_submit_urb(oob_port->write_urb)) != 0 ) {
- dbg(
- "digi_send_oob: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
- opcode, ret );
}
- spin_unlock( &priv->dp_port_lock );
+ spin_unlock( &oob_priv->dp_port_lock );
-dbg( "digi_send_oob: opcode %d done", opcode );
+ return( ret );
}
-static void digi_send_cmd( char *mes, struct usb_serial_port *port, int opcode,
- int length, int val )
+/*
+* Digi Set Modem Signals
+*
+* Sets or clears DTR and RTS on the port, according to the
+* modem_signals argument. Use TIOCM_DTR and TIOCM_RTS flags
+* for the modem_signals argument. Returns 0 if successful,
+* -EINTR if interrupted while sleeping, or a non-zero error
+* returned by usb_submit_urb.
+*/
+
+static int digi_set_modem_signals( struct usb_serial_port *port,
+ unsigned int modem_signals )
{
int ret;
- struct s_digiusb digiusb;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ unsigned char *data = oob_port->write_urb->transfer_buffer;
+ digi_private_t *port_priv = (digi_private_t *)(port->private);
+ digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
-dbg( "digi_send_cmd: TOP: from '%s', opcode: %d, val: %d", mes, opcode, val );
+dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
+port->number, modem_signals );
- digiusb.opcode = (u8)opcode;
- digiusb.length = (u8)length;
- digiusb.val = (u8)val;
- digiusb.pad = 0;
+ spin_lock( &oob_priv->dp_port_lock );
+ spin_lock( &port_priv->dp_port_lock );
- spin_lock( &priv->dp_port_lock );
-
- while( port->write_urb->status == -EINPROGRESS ) {
-dbg( "digi_send_cmd: opcode=%d already writing...", opcode );
- spin_unlock( &priv->dp_port_lock );
- interruptible_sleep_on( &port->write_wait );
+ while( oob_port->write_urb->status == -EINPROGRESS ) {
+ spin_unlock( &port_priv->dp_port_lock );
+ spin_unlock( &oob_priv->dp_port_lock );
+ interruptible_sleep_on_timeout( &oob_port->write_wait,
+ DIGI_RETRY_TIMEOUT );
if( signal_pending(current) ) {
- return;
+ return( -EINTR );
}
- spin_lock( &priv->dp_port_lock );
+ spin_lock( &oob_priv->dp_port_lock );
+ spin_lock( &port_priv->dp_port_lock );
}
- memcpy( port->write_urb->transfer_buffer, &digiusb, sizeof(digiusb) );
- port->write_urb->transfer_buffer_length = sizeof(digiusb);
- if( (ret=usb_submit_urb(port->write_urb)) != 0 )
- dbg(
- "digi_send_cmd: usb_submit_urb(write bulk) failed, opcode=%d, ret=%d",
- opcode, ret );
+ /* command is 4 bytes: command, line, argument, pad */
+ data[0] = DIGI_CMD_SET_DTR_SIGNAL;
+ data[1] = port->number;
+ data[2] = (modem_signals&TIOCM_DTR) ?
+ DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
+ data[3] = 0;
+
+ data[4] = DIGI_CMD_SET_RTS_SIGNAL;
+ data[5] = port->number;
+ data[6] = (modem_signals&TIOCM_RTS) ?
+ DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
+ data[7] = 0;
+
+ oob_port->write_urb->transfer_buffer_length = 8;
+
+ if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+ port_priv->dp_modem_signals =
+ (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
+ | (modem_signals&(TIOCM_DTR|TIOCM_RTS));
+ } else {
+ dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
+ ret );
+ }
-dbg( "digi_send_cmd: opcode %d done", opcode );
+ spin_unlock( &port_priv->dp_port_lock );
+ spin_unlock( &oob_priv->dp_port_lock );
- spin_unlock( &priv->dp_port_lock );
+ return( ret );
}
@@ -312,52 +445,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", port->number );
/* just restart the receive interrupt URB */
//if (usb_submit_urb(port->interrupt_in_urb))
- // dbg( "digi_rx_unthrottle: usb_submit_urb(read urb) failed" );
-
-}
-
-
-static int digi_setbaud( struct usb_serial_port *port, int baud )
-{
-
- int bindex;
-
-
-dbg( "digi_setbaud: TOP: port=%d", port->number );
-
- switch( baud ) {
- case 50: bindex = DIGI_BAUD_50; break;
- case 75: bindex = DIGI_BAUD_75; break;
- case 110: bindex = DIGI_BAUD_110; break;
- case 150: bindex = DIGI_BAUD_150; break;
- case 200: bindex = DIGI_BAUD_200; break;
- case 300: bindex = DIGI_BAUD_300; break;
- case 600: bindex = DIGI_BAUD_600; break;
- case 1200: bindex = DIGI_BAUD_1200; break;
- case 1800: bindex = DIGI_BAUD_1800; break;
- case 2400: bindex = DIGI_BAUD_2400; break;
- case 4800: bindex = DIGI_BAUD_4800; break;
- case 7200: bindex = DIGI_BAUD_7200; break;
- case 9600: bindex = DIGI_BAUD_9600; break;
- case 14400: bindex = DIGI_BAUD_14400; break;
- case 19200: bindex = DIGI_BAUD_19200; break;
- case 28800: bindex = DIGI_BAUD_28800; break;
- case 38400: bindex = DIGI_BAUD_38400; break;
- case 57600: bindex = DIGI_BAUD_57600; break;
- case 76800: bindex = DIGI_BAUD_76800; break;
- case 115200: bindex = DIGI_BAUD_115200; break;
- case 153600: bindex = DIGI_BAUD_153600; break;
- case 230400: bindex = DIGI_BAUD_230400; break;
- case 460800: bindex = DIGI_BAUD_460800; break;
- default:
- dbg( "digi_setbaud: can't handle requested baud rate %d", baud );
- return( -EINVAL );
- break;
- }
-
- digi_send_cmd( "digi_setbaud:", port, DIGI_CMD_SET_BAUD_RATE, 2, bindex );
-
- return( 0 ); /* FIX -- send_cmd should return a value??, return it */
+ // dbg( "digi_rx_unthrottle: usb_submit_urb failed" );
}
@@ -367,167 +455,243 @@ static void digi_set_termios( struct usb_serial_port *port,
{
unsigned int iflag = port->tty->termios->c_iflag;
- unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
- int arg;
+ unsigned char buf[32];
+ int arg,ret;
+ int i = 0;
dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", port->number, iflag, old_iflag, cflag, old_cflag );
/* set baud rate */
- /* if( (cflag&CBAUD) != (old_cflag&CBAUD) ) */ {
+ if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+
+ arg = -1;
+
+ /* reassert DTR and (maybe) RTS on transition from B0 */
+ if( (old_cflag&CBAUD) == B0 ) {
+ /* don't set RTS if using hardware flow control */
+ /* and throttling input -- not implemented yet */
+ digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
+ }
+
switch( (cflag&CBAUD) ) {
- case B50: digi_setbaud(port, 50); break;
- case B75: digi_setbaud(port, 75); break;
- case B110: digi_setbaud(port, 110); break;
- case B150: digi_setbaud(port, 150); break;
- case B200: digi_setbaud(port, 200); break;
- case B300: digi_setbaud(port, 300); break;
- case B600: digi_setbaud(port, 600); break;
- case B1200: digi_setbaud(port, 1200); break;
- case B1800: digi_setbaud(port, 1800); break;
- case B2400: digi_setbaud(port, 2400); break;
- case B4800: digi_setbaud(port, 4800); break;
- case B9600: digi_setbaud(port, 9600); break;
- case B19200: digi_setbaud(port, 19200); break;
- case B38400: digi_setbaud(port, 38400); break;
- case B57600: digi_setbaud(port, 57600); break;
- case B115200: digi_setbaud(port, 115200); break;
- default:
- dbg( "digi_set_termios: can't handle baud rate 0x%x",
- (cflag&CBAUD) );
- break;
+ /* drop DTR and RTS on transition to B0 */
+ case B0: digi_set_modem_signals( port, 0 ); break;
+ case B50: arg = DIGI_BAUD_50; break;
+ case B75: arg = DIGI_BAUD_75; break;
+ case B110: arg = DIGI_BAUD_110; break;
+ case B150: arg = DIGI_BAUD_150; break;
+ case B200: arg = DIGI_BAUD_200; break;
+ case B300: arg = DIGI_BAUD_300; break;
+ case B600: arg = DIGI_BAUD_600; break;
+ case B1200: arg = DIGI_BAUD_1200; break;
+ case B1800: arg = DIGI_BAUD_1800; break;
+ case B2400: arg = DIGI_BAUD_2400; break;
+ case B4800: arg = DIGI_BAUD_4800; break;
+ case B9600: arg = DIGI_BAUD_9600; break;
+ case B19200: arg = DIGI_BAUD_19200; break;
+ case B38400: arg = DIGI_BAUD_38400; break;
+ case B57600: arg = DIGI_BAUD_57600; break;
+ case B115200: arg = DIGI_BAUD_115200; break;
+ case B230400: arg = DIGI_BAUD_230400; break;
+ case B460800: arg = DIGI_BAUD_460800; break;
+ default:
+ dbg( "digi_set_termios: can't handle baud rate 0x%x",
+ (cflag&CBAUD) );
+ break;
+ }
+
+ if( arg != -1 ) {
+ buf[i++] = DIGI_CMD_SET_BAUD_RATE;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
+ }
+
+ }
+
+ /* set parity */
+ if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
+
+ if( (cflag&PARENB) ) {
+ if( (cflag&PARODD) )
+ arg = DIGI_PARITY_ODD;
+ else
+ arg = DIGI_PARITY_EVEN;
+ } else {
+ arg = DIGI_PARITY_NONE;
}
+
+ buf[i++] = DIGI_CMD_SET_PARITY;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
+
+ }
+
+ /* set word size */
+ if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
+
+ arg = -1;
+
+ switch( (cflag&CSIZE) ) {
+ case CS5: arg = DIGI_WORD_SIZE_5; break;
+ case CS6: arg = DIGI_WORD_SIZE_6; break;
+ case CS7: arg = DIGI_WORD_SIZE_7; break;
+ case CS8: arg = DIGI_WORD_SIZE_8; break;
+ default:
+ dbg( "digi_set_termios: can't handle word size %d",
+ (cflag&CSIZE) );
+ break;
+ }
+
+ if( arg != -1 ) {
+ buf[i++] = DIGI_CMD_SET_WORD_SIZE;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
+ }
+
+ }
+
+ /* set stop bits */
+ if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+
+ if( (cflag&CSTOPB) )
+ arg = DIGI_STOP_BITS_2;
+ else
+ arg = DIGI_STOP_BITS_1;
+
+ buf[i++] = DIGI_CMD_SET_STOP_BITS;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
+
}
/* set input flow control */
- /* if( (iflag&IXOFF) != (old_iflag&IXOFF)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+ if( (iflag&IXOFF) != (old_iflag&IXOFF)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
arg = 0;
if( (iflag&IXOFF) )
- arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+ arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
+ else
+ arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
+
if( (cflag&CRTSCTS) )
- arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+ arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
+ else
+ arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
- digi_send_cmd( "digi_termios: set input flow control:", port,
- DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, arg );
+ buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
}
/* set output flow control */
- /* if( (iflag&IXON) != (old_iflag&IXON)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) */ {
+ /*if( (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) )*/ {
arg = 0;
if( (iflag&IXON) )
- arg |= DIGI_ENABLE_IXON_IXOFF_FLOW_CONTROL;
+ arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
+ else
+ arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
+
if( (cflag&CRTSCTS) )
- arg |= DIGI_ENABLE_RTS_CTS_FLOW_CONTROL;
+ arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
+ else
+ arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
- digi_send_cmd( "digi_set_termios: set output flow control:", port,
- DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, arg );
+ buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
}
-}
+ /* set receive enable/disable */
+ if( (cflag&CREAD) != (old_cflag&CREAD) ) {
+ if( (cflag&CREAD) )
+ arg = DIGI_ENABLE;
+ else
+ arg = DIGI_DISABLE;
-static void digi_break_ctl( struct usb_serial_port *port, int break_state )
-{
-dbg( "digi_break_ctl: TOP: port=%d", port->number );
-}
+ buf[i++] = DIGI_CMD_RECEIVE_ENABLE;
+ buf[i++] = port->number;
+ buf[i++] = arg;
+ buf[i++] = 0;
+ }
-/* modem control pins: DTR and RTS are outputs and can be controlled;
- DCD, RI, DSR, CTS are inputs and can be read */
+ if( (ret=digi_write_oob( buf, i )) != 0 )
+ dbg( "digi_set_termios: write oob failed, ret=%d", ret );
-static int digi_get_modem_info( struct usb_serial *serial,
- unsigned char *value )
-{
-dbg( "digi_get_modem_info: TOP" );
- return( 0 );
}
-static int digi_set_modem_info( struct usb_serial *serial,
- unsigned char value )
+static void digi_break_ctl( struct usb_serial_port *port, int break_state )
{
-dbg( "digi_set_modem_info: TOP" );
- return( 0 );
+dbg( "digi_break_ctl: TOP: port=%d", port->number );
}
static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg )
{
- struct usb_serial *serial = port->serial;
- int rc;
- unsigned int value;
- unsigned char status, mask;
+
+ digi_private_t *priv = (digi_private_t *)(port->private);
+ unsigned int val;
+
dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", port->number, cmd );
-return( -ENOIOCTLCMD );
switch (cmd) {
- case TIOCMGET: /* get modem pins state */
- rc = digi_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- value =
- ((status & (1<<7)) ? TIOCM_DTR : 0) |
- ((status & (1<<6)) ? TIOCM_CAR : 0) |
- ((status & (1<<5)) ? TIOCM_RNG : 0) |
- ((status & (1<<4)) ? TIOCM_DSR : 0) |
- ((status & (1<<3)) ? TIOCM_CTS : 0) |
- ((status & (1<<2)) ? TIOCM_RTS : 0);
- if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCMSET: /* set a state as returned by MGET */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- status =
- ((value & TIOCM_DTR) ? (1<<7) : 0) |
- ((value & TIOCM_CAR) ? (1<<6) : 0) |
- ((value & TIOCM_RNG) ? (1<<5) : 0) |
- ((value & TIOCM_DSR) ? (1<<4) : 0) |
- ((value & TIOCM_CTS) ? (1<<3) : 0) |
- ((value & TIOCM_RTS) ? (1<<2) : 0);
- rc = digi_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
- case TIOCMBIS: /* set bits in bitmask <arg> */
- case TIOCMBIC: /* clear bits from bitmask <arg> */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- rc = digi_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- mask =
- ((value & TIOCM_RTS) ? (1<<2) : 0) |
- ((value & TIOCM_DTR) ? (1<<7) : 0);
- if (cmd == TIOCMBIS)
- status |= mask;
- else
- status &= ~mask;
- rc = digi_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
+
+ case TIOCMGET:
+ spin_lock( &priv->dp_port_lock );
+ val = priv->dp_modem_signals;
+ spin_unlock( &priv->dp_port_lock );
+ if( copy_to_user((unsigned int *)arg, &val, sizeof(int)) )
+ return( -EFAULT );
+ return( 0 );
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ if( copy_from_user(&val, (unsigned int *)arg, sizeof(int)) )
+ return( -EFAULT );
+ spin_lock( &priv->dp_port_lock );
+ if( cmd == TIOCMBIS )
+ val = priv->dp_modem_signals | val;
+ else if( cmd == TIOCMBIC )
+ val = priv->dp_modem_signals & ~val;
+ spin_unlock( &priv->dp_port_lock );
+ return( digi_set_modem_signals( port, val ) );
+
case TIOCMIWAIT:
/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
/* TODO */
+ return( 0 );
+
case TIOCGICOUNT:
/* return count of modemline transitions */
- return 0; /* TODO */
+ /* TODO */
+ return 0;
+
}
-
- return -ENOIOCTLCMD;
+
+ return( -ENOIOCTLCMD );
+
}
@@ -535,7 +699,7 @@ static int digi_write( struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count )
{
- int i,ret,data_len,new_len;
+ int ret,data_len,new_len;
digi_private_t *priv = (digi_private_t *)(port->private);
@@ -550,16 +714,18 @@ port->number, count, from_user, in_interrupt() );
/* wait for urb status clear to submit another urb */
if( port->write_urb->status == -EINPROGRESS ) {
-dbg( "digi_write: -EINPROGRESS set" );
-
- /* buffer the data if possible */
- new_len = MIN( count, DIGI_PORT_BUF_LEN-priv->dp_buf_len );
- memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
- priv->dp_buf_len += new_len;
+ /* buffer data if count is 1 (probably put_char) if possible */
+ if( count == 1 ) {
+ new_len = MIN( count,
+ DIGI_PORT_BUF_LEN-priv->dp_buf_len );
+ memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
+ priv->dp_buf_len += new_len;
+ } else {
+ new_len = 0;
+ }
- /* unlock and return number of bytes buffered */
spin_unlock( &priv->dp_port_lock );
-dbg( "digi_write: buffering, return %d", new_len );
+
return( new_len );
}
@@ -569,19 +735,16 @@ dbg( "digi_write: buffering, return %d", new_len );
new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
data_len = new_len + priv->dp_buf_len;
-dbg( "digi_write: counts: new data %d, buf data %d, total data %d (max %d)", new_len, priv->dp_buf_len, data_len, port->bulk_out_size-2 );
-
- /* nothing to send */
if( data_len == 0 ) {
spin_unlock( &priv->dp_port_lock );
return( 0 );
}
- /* set command and length bytes */
- *((u8 *)(port->write_urb->transfer_buffer)) = (u8)DIGI_CMD_SEND_DATA;
- *((u8 *)(port->write_urb->transfer_buffer)+1) = (u8)data_len;
+ *((unsigned char *)(port->write_urb->transfer_buffer))
+ = (unsigned char)DIGI_CMD_SEND_DATA;
+ *((unsigned char *)(port->write_urb->transfer_buffer)+1)
+ = (unsigned char)data_len;
- /* set total transfer buffer length */
port->write_urb->transfer_buffer_length = data_len+2;
/* copy in buffered data first */
@@ -590,33 +753,34 @@ dbg( "digi_write: counts: new data %d, buf data %d, total data %d (max %d)", new
/* copy in new data */
if( from_user ) {
- copy_from_user( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
+ copy_from_user(
+ port->write_urb->transfer_buffer+2+priv->dp_buf_len,
buf, new_len );
- }
- else {
+ } else {
memcpy( port->write_urb->transfer_buffer+2+priv->dp_buf_len,
buf, new_len );
}
-#ifdef DEBUG
- printk( KERN_DEBUG __FILE__ ": digi_write: length=%d, data=",
- port->write_urb->transfer_buffer_length );
+#ifdef DEBUG_DATA
+{
+ int i;
+
+ printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=",
+ port->number, port->write_urb->transfer_buffer_length );
for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
+ ((unsigned char *)port->write_urb->transfer_buffer)[i] );
}
printk( "\n" );
+}
#endif
- /* submit urb */
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- /* submit successful, return length of new data written */
ret = new_len;
- /* clear buffer */
priv->dp_buf_len = 0;
- }
- else {
- dbg( "digi_write: usb_submit_urb(write bulk) failed, ret=%d", ret );
+ } else {
+ dbg( "digi_write: usb_submit_urb failed, ret=%d",
+ ret );
/* no bytes written - should we return the error code or 0? */
ret = 0;
}
@@ -658,28 +822,34 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", port->number );
spin_lock( &priv->dp_port_lock );
if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) {
- /* set command and length bytes */
- *((u8 *)(port->write_urb->transfer_buffer))
- = (u8)DIGI_CMD_SEND_DATA;
- *((u8 *)(port->write_urb->transfer_buffer)+1)
- = (u8)priv->dp_buf_len;
+ *((unsigned char *)(port->write_urb->transfer_buffer))
+ = (unsigned char)DIGI_CMD_SEND_DATA;
+ *((unsigned char *)(port->write_urb->transfer_buffer)+1)
+ = (unsigned char)priv->dp_buf_len;
- /* set total transfer buffer length */
port->write_urb->transfer_buffer_length = priv->dp_buf_len+2;
- /* copy in buffered data */
memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
priv->dp_buf_len );
- /* submit urb */
-dbg( "digi_write_bulk_callback: submit urb to write buffer, data len=%d",
-priv->dp_buf_len );
+#ifdef DEBUG_DATA
+{
+ int i;
+
+ printk( KERN_DEBUG __FILE__ ": digi_write_bulk_callback: port=%d, length=%d, data=",
+ port->number, port->write_urb->transfer_buffer_length );
+ for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
+ printk( "%.2x ",
+ ((unsigned char *)port->write_urb->transfer_buffer)[i] );
+ }
+ printk( "\n" );
+}
+#endif
+
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- /* successful, clear buffer */
priv->dp_buf_len = 0;
- }
- else {
- dbg( "digi_write_bulk_callback: usb_submit_urb(write bulk) failed, ret=%d", ret );
+ } else {
+ dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d", ret );
}
}
@@ -690,7 +860,8 @@ priv->dp_buf_len );
/* wake up line discipline */
tty = port->tty;
- if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup )
+ if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup )
(tty->ldisc.write_wakeup)(tty);
/* wake up other tty processes */
@@ -717,7 +888,7 @@ dbg( "digi_write_room: TOP: port=%d", port->number );
spin_unlock( &priv->dp_port_lock );
-dbg( "digi_write_room: return room=%d", room );
+dbg( "digi_write_room: port=%d, room=%d", port->number, room );
return( room );
}
@@ -732,11 +903,10 @@ static int digi_chars_in_buffer( struct usb_serial_port *port )
dbg( "digi_chars_in_buffer: TOP: port=%d", port->number );
if( port->write_urb->status == -EINPROGRESS ) {
-dbg( "digi_chars_in_buffer: return=%d", port->bulk_out_size );
- return( port->bulk_out_size );
- }
- else {
-dbg( "digi_chars_in_buffer: return=%d", priv->dp_buf_len );
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", port->number, port->bulk_out_size - 2 );
+ return( port->bulk_out_size - 2 );
+ } else {
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", port->number, priv->dp_buf_len );
return( priv->dp_buf_len );
}
@@ -746,61 +916,53 @@ dbg( "digi_chars_in_buffer: return=%d", priv->dp_buf_len );
static int digi_open( struct usb_serial_port *port, struct file *filp )
{
+ int i = 0;
int ret;
+ unsigned char buf[32];
digi_private_t *priv = (digi_private_t *)(port->private);
+ struct termios not_termios;
+
+
+dbg( "digi_open: TOP: port %d, active:%d", port->number, port->active );
+ /* be sure the device is started up */
+ if( digi_startup_device( port->serial ) != 0 )
+ return( -ENXIO );
-dbg( "digi_open: TOP: port %d", port->number );
+ MOD_INC_USE_COUNT;
/* if port is already open, just return */
- /* be sure exactly one open succeeds */
+ /* be sure exactly one open proceeds */
spin_lock( &priv->dp_port_lock );
- if( port->active ) {
+ if( port->active++ ) {
+ spin_unlock( &priv->dp_port_lock );
return( 0 );
}
- port->active = 1;
spin_unlock( &priv->dp_port_lock );
- /* start reading from the out-of-band port for the device */
- /* be sure this happens exactly once */
- spin_lock( &config_lock );
- if( !oob_read_started ) {
- if( (ret=usb_submit_urb(oob_port->read_urb)) != 0 ) {
- dbg( "digi_open: usb_submit_urb(read bulk) for oob failed, ret=%d",
- ret );
- spin_unlock( &config_lock );
- return( -ENXIO );
- }
- else {
-dbg( "digi_open: usb_submit_urb(read bulk) for oob succeeded" );
- oob_read_started = 1;
- }
- }
- spin_unlock( &config_lock );
-
- /* initialize port */
-dbg( "digi_open: init..." );
- /* set 9600, 8N1, DTR, RTS, RX enable, no input or output flow control */
- digi_setbaud( port, 9600 );
- digi_send_cmd( "digi_open: wordsize", port, DIGI_CMD_SET_WORD_SIZE, 2, 3 );
- digi_send_cmd( "digi_open: parity", port, DIGI_CMD_SET_PARITY, 2, 0 );
- digi_send_cmd( "digi_open: stopbits", port, DIGI_CMD_SET_STOP_BITS, 2, 0 );
- digi_send_cmd( "digi_open: DTR on", port, DIGI_CMD_SET_DTR_SIGNAL, 2, 1 );
- digi_send_cmd( "digi_open: RTS on", port, DIGI_CMD_SET_RTS_SIGNAL, 2, 1 );
- digi_send_cmd( "digi_open: RX enable on", port, DIGI_CMD_RECEIVE_ENABLE, 2,
- 1 );
- digi_send_cmd( "digi_open: input flow control off", port,
- DIGI_CMD_SET_INPUT_FLOW_CONTROL, 2, 0 );
- digi_send_cmd( "digi_open: output flow control off", port,
- DIGI_CMD_SET_OUTPUT_FLOW_CONTROL, 2, 0 );
-
- /* start reading from the device */
- if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
- dbg( "digi_open: usb_submit_urb(read bulk) failed, ret=%d", ret );
- return( -ENXIO );
- }
+ /* read modem signals automatically whenever they change */
+ buf[i++] = DIGI_CMD_READ_INPUT_SIGNALS;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_ENABLE;
+ buf[i++] = 0;
+
+ /* flush fifos */
+ buf[i++] = DIGI_CMD_IFLUSH_FIFO;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[i++] = 0;
+
+ if( (ret=digi_write_oob( buf, i )) != 0 )
+ dbg( "digi_open: write oob failed, ret=%d", ret );
+
+ /* set termios settings */
+ not_termios.c_cflag = ~port->tty->termios->c_cflag;
+ not_termios.c_iflag = ~port->tty->termios->c_iflag;
+ digi_set_termios( port, &not_termios );
+
+ /* set DTR and RTS */
+ digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
-dbg( "digi_open: done" );
return( 0 );
}
@@ -809,39 +971,119 @@ dbg( "digi_open: done" );
static void digi_close( struct usb_serial_port *port, struct file *filp )
{
-dbg( "digi_close: TOP: port %d", port->number );
-
- /* Need to change the control lines here */
- /* TODO */
-dbg( "digi_close: wanna clear DTR and RTS..." );
+ int i = 0;
+ int ret;
+ unsigned char buf[32];
+ digi_private_t *priv = (digi_private_t *)(port->private);
-//digi_send_cmd( "digi_close DTR off", port, 6, 2, 0); // clear DTR
-//digi_send_cmd( "digi_close RTS off", port, 7, 2, 0); // clear RTS
-//digi_send_cmd( "digi_close RX disable", port, 10, 2, 0); // Rx Disable
-digi_send_oob( "digi_close RTS off", DIGI_CMD_SET_RTS_SIGNAL,
- port->number, 0, 0 ); // clear RTS
-digi_send_oob( "digi_close DTR off", DIGI_CMD_SET_DTR_SIGNAL,
- port->number, 0, 0 ); // clear DTR
+dbg( "digi_close: TOP: port %d, active:%d", port->number, port->active );
+
+ /* do cleanup only after final close on this port */
+ spin_lock( &priv->dp_port_lock );
+ if( --port->active ) {
+ spin_unlock( &priv->dp_port_lock );
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+ spin_unlock( &priv->dp_port_lock );
+
+ /* drop DTR and RTS */
+ digi_set_modem_signals( port, 0 );
+
+ /* disable input flow control */
+ buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_DISABLE;
+ buf[i++] = 0;
+
+ /* disable output flow control */
+ buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_DISABLE;
+ buf[i++] = 0;
+
+ /* disable reading modem signals automatically */
+ buf[i++] = DIGI_CMD_READ_INPUT_SIGNALS;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_DISABLE;
+ buf[i++] = 0;
+
+ /* flush fifos */
+ buf[i++] = DIGI_CMD_IFLUSH_FIFO;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[i++] = 0;
+
+ /* disable receive */
+ buf[i++] = DIGI_CMD_RECEIVE_ENABLE;
+ buf[i++] = port->number;
+ buf[i++] = DIGI_DISABLE;
+ buf[i++] = 0;
+
+ if( (ret=digi_write_oob( buf, i )) != 0 )
+ dbg( "digi_close: write oob failed, ret=%d", ret );
+
+ /* wait for final commands on oob port to complete */
while( oob_port->write_urb->status == -EINPROGRESS ) {
-dbg ("digi_close: waiting for final writes to complete on oob port %d...", oob_port->number );
- interruptible_sleep_on( &oob_port->write_wait );
+ interruptible_sleep_on_timeout( &oob_port->write_wait,
+ DIGI_RETRY_TIMEOUT );
if( signal_pending(current) ) {
break;
}
}
- /* shutdown our bulk reads and writes */
+ /* shutdown any outstanding bulk writes */
usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
+ MOD_DEC_USE_COUNT;
+
+}
+
+
+/*
+* Digi Startup Device
+*
+* Starts reads on all ports. Must be called AFTER startup, with
+* urbs initialized. Returns 0 if successful, non-zero error otherwise.
+*/
+
+static int digi_startup_device( struct usb_serial *serial )
+{
+
+ int i,ret = 0;
+
+
+ spin_lock( &startup_lock );
+
+ /* be sure this happens exactly once */
+ if( device_startup ) {
+ spin_unlock( &startup_lock );
+ return( 0 );
+ }
+
+ /* start reading from each bulk in endpoint for the device */
+ for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+
+ if( (ret=usb_submit_urb(serial->port[i].read_urb)) != 0 ) {
+ dbg( "digi_startup_device: usb_submit_urb failed, port=%d, ret=%d",
+ i, ret );
+ break;
+ }
+
+ }
+
+ device_startup = 1;
+
+ spin_unlock( &startup_lock );
+
+ return( ret );
}
-static int digi_startup (struct usb_serial *serial)
+static int digi_startup( struct usb_serial *serial )
{
int i;
@@ -850,22 +1092,24 @@ static int digi_startup (struct usb_serial *serial)
dbg( "digi_startup: TOP" );
- /* initialize config lock */
- spin_lock_init( &config_lock );
+ spin_lock_init( &startup_lock );
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ serial->port[i].active = 0;
+
/* allocate private structure */
priv = serial->port[i].private =
- (digi_private_t *)kmalloc( sizeof(struct digi_private),
+ (digi_private_t *)kmalloc( sizeof(digi_private_t),
GFP_KERNEL );
if( priv == (digi_private_t *)0 )
- return( 1 ); /* error */
+ return( 1 ); /* error */
/* initialize private structure */
priv->dp_buf_len = 0;
+ priv->dp_modem_signals = 0;
spin_lock_init( &priv->dp_port_lock );
/* initialize write wait queue for this port */
@@ -876,7 +1120,7 @@ dbg( "digi_startup: TOP" );
/* initialize out of band port info */
oob_port_num = digi_acceleport_device.num_ports;
oob_port = &serial->port[oob_port_num];
- oob_read_started = 0;
+ device_startup = 0;
return( 0 );
@@ -891,10 +1135,13 @@ static void digi_shutdown( struct usb_serial *serial )
dbg( "digi_shutdown: TOP" );
- /* stop writing and reading from the out-of-band port */
- usb_unlink_urb( oob_port->write_urb );
- usb_unlink_urb( oob_port->read_urb );
- oob_read_started = 0;
+ /* stop reads and writes on all ports */
+ for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ usb_unlink_urb (serial->port[i].read_urb);
+ usb_unlink_urb (serial->port[i].write_urb);
+ }
+
+ device_startup = 0;
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
@@ -910,7 +1157,10 @@ static void digi_read_bulk_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
struct tty_struct *tty = port->tty;
- unsigned char *data = urb->transfer_buffer;
+ int opcode = ((unsigned char *)urb->transfer_buffer)[0];
+ int len = ((unsigned char *)urb->transfer_buffer)[1];
+ int status = ((unsigned char *)urb->transfer_buffer)[2];
+ unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
int ret,i;
@@ -918,58 +1168,108 @@ dbg( "digi_read_bulk_callback: TOP: port=%d", port->number );
/* handle oob callback */
if( port->number == oob_port_num ) {
-dbg( "digi_read_bulk_callback: oob_port callback, opcode=%d, line=%d, status=%d, ret=%d", data[0], data[1], data[2], data[3] );
- if( urb->status ) {
- dbg( "digi_read_bulk_callback: nonzero read bulk status on oob: %d",
- urb->status );
- }
- if( (ret=usb_submit_urb(urb)) != 0 ) {
- dbg( "digi_read_bulk_callback: failed resubmitting oob urb, ret=%d",
- ret );
- }
+ digi_read_oob( urb );
return;
}
/* sanity checks */
if( port_paranoia_check( port, "digi_read_bulk_callback" )
|| serial_paranoia_check( serial, "digi_read_bulk_callback" ) ) {
- return;
+ goto resubmit;
}
- /* check status */
if( urb->status ) {
dbg( "digi_read_bulk_callback: nonzero read bulk status: %d",
urb->status );
- return;
+ goto resubmit;
}
-#ifdef DEBUG
- if (urb->actual_length) {
- printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: length=%d, data=",
- urb->actual_length );
- for( i=0; i<urb->actual_length; ++i ) {
- printk( "%.2x ", data[i] );
- }
- printk( "\n" );
+#ifdef DEBUG_DATA
+if( urb->actual_length ) {
+ printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: port=%d, length=%d, data=",
+ port->number, urb->actual_length );
+ for( i=0; i<urb->actual_length; ++i ) {
+ printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] );
}
+ printk( "\n" );
+}
#endif
- /* Digi read packets are: */
- /* 0 1 2 3 4 ... 3+length-1 == 2+length*/
- /* opcode, length, status, data[0], data[1]...data[length-2] */
- if( urb->actual_length > 3 ) {
- for( i=3; i<2+data[1]; ++i ) {
+ if( urb->actual_length != len + 2 )
+ err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", port->number, opcode, len, urb->actual_length, status );
+
+ /* receive data */
+ if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) {
+ len = MIN( len, urb->actual_length-3 );
+ for( i=0; i<len; ++i ) {
tty_insert_flip_char(tty, data[i], 0);
}
tty_flip_buffer_push(tty);
}
- /* Continue trying to read */
+ /* continue read */
+resubmit:
if( (ret=usb_submit_urb(urb)) != 0 )
- dbg( "digi_read_bulk_callback: failed resubmitting read urb, ret=%d",
+ dbg( "digi_read_bulk_callback: failed resubmitting urb, ret=%d",
ret );
}
-#endif /* CONFIG_USB_SERIAL_DIGI_ACCELEPORT */
+
+static void digi_read_oob( struct urb *urb )
+{
+
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+ digi_private_t *priv;
+ int oob_opcode = ((unsigned char *)urb->transfer_buffer)[0];
+ int oob_line = ((unsigned char *)urb->transfer_buffer)[1];
+ int oob_status = ((unsigned char *)urb->transfer_buffer)[2];
+ int oob_ret = ((unsigned char *)urb->transfer_buffer)[3];
+ int ret;
+
+
+dbg( "digi_read_oob: opcode=%d, line=%d, status=%d, ret=%d", oob_opcode, oob_line, oob_status, oob_ret );
+
+ if( urb->status ) {
+ dbg( "digi_read_oob: nonzero read bulk status on oob: %d",
+ urb->status );
+ goto resubmit;
+ }
+
+ if( oob_opcode == DIGI_CMD_READ_INPUT_SIGNALS && oob_status == 0 ) {
+
+ priv = serial->port[oob_line].private;
+
+ spin_lock( &priv->dp_port_lock );
+
+ /* convert from digi flags to termiox flags */
+ if( oob_ret & DIGI_READ_INPUT_SIGNALS_CTS )
+ priv->dp_modem_signals |= TIOCM_CTS;
+ else
+ priv->dp_modem_signals &= ~TIOCM_CTS;
+ if( oob_ret & DIGI_READ_INPUT_SIGNALS_DSR )
+ priv->dp_modem_signals |= TIOCM_DSR;
+ else
+ priv->dp_modem_signals &= ~TIOCM_DSR;
+ if( oob_ret & DIGI_READ_INPUT_SIGNALS_RI )
+ priv->dp_modem_signals |= TIOCM_RI;
+ else
+ priv->dp_modem_signals &= ~TIOCM_RI;
+ if( oob_ret & DIGI_READ_INPUT_SIGNALS_DCD )
+ priv->dp_modem_signals |= TIOCM_CD;
+ else
+ priv->dp_modem_signals &= ~TIOCM_CD;
+
+ spin_unlock( &priv->dp_port_lock );
+
+ }
+
+resubmit:
+ if( (ret=usb_submit_urb(urb)) != 0 ) {
+ dbg( "digi_read_oob: failed resubmitting oob urb, ret=%d",
+ ret );
+ }
+
+}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index cdad3cabe..8aec73569 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -32,9 +32,6 @@
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -723,6 +720,3 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
return 0;
} /* ftdi_sio_ioctl */
-#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
-
-
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index f91e1b592..c18137ffa 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -18,9 +18,6 @@
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -700,4 +697,3 @@ struct usb_serial_device_type keyspan_pda_device = {
shutdown: keyspan_pda_shutdown,
};
-#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 9eb6767f0..2e5e50849 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -13,9 +13,6 @@
*/
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_OMNINET
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -336,6 +333,3 @@ static void omninet_write_bulk_callback (struct urb *urb)
return;
}
-#endif /* CONFIG_USB_SERIAL_OMNINET */
-
-
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 9fe65ae8d..b2e18bd8e 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (05/22/2000) gkh
+ * Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
+ * removed from the individual device source files.
+ *
* (05/03/2000) gkh
* Added the Digi Acceleport driver from Al Borchers and Peter Berger.
*
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 979a56f01..5cfb4c42a 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -20,9 +20,6 @@
*/
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -207,7 +204,3 @@ static int visor_startup (struct usb_serial *serial)
return (0);
}
-
-#endif /* CONFIG_USB_SERIAL_VISOR*/
-
-
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 58f761fbf..c168efa02 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -21,9 +21,6 @@
*/
#include <linux/config.h>
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -407,6 +404,3 @@ static void whiteheat_shutdown (struct usb_serial *serial)
return;
}
-#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
-
-
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 2eaab47ef..a3d8d3d42 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -821,6 +821,7 @@ status_phase:
/* Control status phase */
status = uhci_status_bits(td->status);
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
/* APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of the amount */
/* we requested */
@@ -828,6 +829,7 @@ status_phase:
status & TD_CTRL_ACTIVE &&
status & TD_CTRL_NAK)
return 0;
+#endif
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -2325,31 +2327,30 @@ static int found_uhci(struct pci_dev *dev)
{
int i;
+ /* disable legacy emulation */
+ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+ if (pci_enable_device(dev) < 0)
+ return -1;
+
+ if (!dev->irq) {
+ err("found UHCI device with no IRQ assigned. check BIOS settings!");
+ return -1;
+ }
+
/* Search for the IO base address.. */
for (i = 0; i < 6; i++) {
- unsigned int io_addr = dev->resource[i].start;
- unsigned int io_size =
- dev->resource[i].end - dev->resource[i].start + 1;
+ unsigned int io_addr = pci_resource_start(dev, i);
+ unsigned int io_size = pci_resource_len(dev, i);
/* IO address? */
- if (!(dev->resource[i].flags & IORESOURCE_IO))
+ if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
continue;
/* Is it already in use? */
if (check_region(io_addr, io_size))
break;
- if (!dev->irq) {
- err("found UHCI device with no IRQ assigned. check BIOS settings!");
- continue;
- }
-
- /* disable legacy emulation */
- pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
- if (pci_enable_device(dev) < 0)
- continue;
-
return setup_uhci(dev, dev->irq, io_addr, io_size);
}
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 50388dccf..a37e805f0 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -92,7 +92,6 @@ static void urb_rm_priv (urb_t * urb)
kfree (urb->hcpriv);
urb->hcpriv = NULL;
- wake_up (&op_wakeup);
}
/*-------------------------------------------------------------------------*/
@@ -493,16 +492,16 @@ static int sohci_submit_urb (urb_t * urb)
urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1):
(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
}
+ urb->status = USB_ST_URB_PENDING;
+ urb->actual_length = 0;
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed);
+ urb->status = USB_ST_URB_PENDING;
td_submit_urb (urb); /* fill the TDs and link it to the ed */
spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- urb->status = USB_ST_URB_PENDING;
- // queue_urb(s, &urb->urb_list);
return 0;
}
@@ -529,6 +528,8 @@ static int sohci_unlink_urb (urb_t * urb)
urb_print (urb, "UNLINK", 1);
#endif
+ usb_dec_dev_use (urb->dev);
+
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
@@ -546,19 +547,23 @@ static int sohci_unlink_urb (urb_t * urb)
ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- add_wait_queue (&op_wakeup, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
- err("unlink URB timeout!");
- remove_wait_queue (&op_wakeup, &wait);
- } else
+ if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ add_wait_queue (&op_wakeup, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+ err("unlink URB timeout!");
+ remove_wait_queue (&op_wakeup, &wait);
+ urb->status = -ENOENT;
+ } else
+ urb->status = -EINPROGRESS;
+ } else {
urb_rm_priv (urb);
-
- urb->status = -ENOENT; // mark urb as killed
- if (urb->complete)
- urb->complete ((struct urb *) urb);
- usb_dec_dev_use (urb->dev);
+ if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ urb->complete (urb);
+ urb->status = 0;
+ } else
+ urb->status = -ENOENT;
+ }
}
return 0;
}
@@ -967,7 +972,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
/* prepare a TD */
-static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type, int index)
+static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index)
{
volatile td_t * td, * td_pt;
urb_priv_t * urb_priv = urb->hcpriv;
@@ -984,7 +989,6 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int t
td->index = index;
td->urb = urb;
td->hwINFO = cpu_to_le32 (info);
- td->type = type;
if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
td->hwCBP = cpu_to_le32 (((!data || !len)?
0 : virt_to_bus (data)) & 0xFFFFF000);
@@ -1031,12 +1035,12 @@ static void td_submit_urb (urb_t * urb)
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
while(data_len > 4096) {
- td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
data += 4096; data_len -= 4096; cnt++;
}
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
cnt++;
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break;
@@ -1044,20 +1048,20 @@ static void td_submit_urb (urb_t * urb)
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
- td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
+ td_fill (info, data, data_len, urb, cnt++);
break;
case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++);
+ td_fill (info, ctrl, 8, urb, cnt++);
if (data_len > 0) {
info = usb_pipeout (urb->pipe)?
TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
- td_fill (info, data, data_len, urb, ADD_LEN, cnt++);
+ td_fill (info, data, data_len, urb, cnt++);
}
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
- td_fill (info, NULL, 0, urb, 0, cnt++);
+ td_fill (info, NULL, 0, urb, cnt++);
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break;
@@ -1065,7 +1069,7 @@ static void td_submit_urb (urb_t * urb)
for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
(__u8 *) data + urb->iso_frame_desc[cnt].offset,
- urb->iso_frame_desc[cnt].length, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ urb->iso_frame_desc[cnt].length, urb, cnt);
}
break;
}
@@ -1076,7 +1080,55 @@ static void td_submit_urb (urb_t * urb)
/*-------------------------------------------------------------------------*
* Done List handling functions
*-------------------------------------------------------------------------*/
-
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ __u16 tdPSW;
+ urb_t * urb = td->urb;
+ urb_priv_t * urb_priv = urb->hcpriv;
+ int dlen = 0;
+ int cc = 0;
+
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ tdBE = le32_to_cpup (&td->hwBE);
+ tdCBP = le32_to_cpup (&td->hwCBP);
+
+
+ if (tdINFO & TD_ISO) {
+ tdPSW = le16_to_cpu (td->hwPSW[0]);
+ cc = (tdPSW >> 12) & 0xF;
+ if (cc < 0xE) {
+ if (usb_pipeout(urb->pipe)) {
+ dlen = urb->iso_frame_desc[td->index].length;
+ } else {
+ dlen = tdPSW & 0x3ff;
+ }
+ urb->actual_length += dlen;
+ urb->iso_frame_desc[td->index].actual_length = dlen;
+ if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ urb->iso_frame_desc[td->index].status = cc_to_error[cc];
+ }
+ } else { /* BULK, INT, CONTROL DATA */
+ if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
+ ((td->index == 0) || (td->index == urb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
+ else
+ urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
/* replies to the request have to be on a FIFO basis so
* we reverse the reversed done-list */
@@ -1130,6 +1182,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
unsigned long flags;
ed_t * ed;
__u32 edINFO;
+ __u32 tdINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
__u32 * td_p;
int ctrl = 0, bulk = 0;
@@ -1141,16 +1194,25 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP;
-
+
for (td = tdHeadP; td != tdTailP; td = td_next) {
urb_t * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv;
td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+ tdINFO = le32_to_cpup (&td->hwINFO);
+ if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
if(++ (urb_priv->td_cnt) == urb_priv->length)
urb_rm_priv (urb);
+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+ usb_dec_dev_use (urb->dev);
+ urb->status = -ECONNRESET;
+ urb->complete (urb);
+ } else {
+ wake_up (&op_wakeup);
+ }
} else {
td_p = &td->hwNextTD;
}
@@ -1167,7 +1229,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
}
else {
ed->state &= ~ED_URB_DEL;
- ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
+ ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
}
if ((ed->type & 3) == CTRL) ctrl |= 1;
@@ -1185,6 +1247,8 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
+
+
/*-------------------------------------------------------------------------*/
/* td done list */
@@ -1193,12 +1257,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
{
td_t * td_list_next = NULL;
ed_t * ed;
- int dlen = 0;
int cc = 0;
urb_t * urb;
urb_priv_t * urb_priv;
- __u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
- __u16 tdPSW;
+ __u32 tdINFO, edHeadP, edTailP;
+
unsigned long flags;
while (td_list) {
@@ -1207,40 +1270,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
urb = td_list->urb;
urb_priv = urb->hcpriv;
tdINFO = le32_to_cpup (&td_list->hwINFO);
- tdBE = le32_to_cpup (&td_list->hwBE);
- tdCBP = le32_to_cpup (&td_list->hwCBP);
ed = td_list->ed;
- if (td_list->type & ST_ADDR)
- urb->actual_length = 0;
-
- if (td_list->type & ADD_LEN) { /* accumulate length of multi td transfers */
- if (tdINFO & TD_ISO) {
- tdPSW = le16_to_cpu (td_list->hwPSW[0]);
- cc = (tdPSW >> 12) & 0xF;
- if (cc < 0xE) {
- if (usb_pipeout(urb->pipe)) {
- dlen = urb->iso_frame_desc[td_list->index].length;
- } else {
- dlen = tdPSW & 0x3ff;
- }
- urb->actual_length += dlen;
- urb->iso_frame_desc[td_list->index].actual_length = dlen;
- if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- urb->iso_frame_desc[td_list->index].status = cc_to_error[cc];
- }
- } else {
- if (tdBE != 0) {
- if (td_list->hwCBP == 0)
- urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
- else
- urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
- }
- }
- }
+ dl_transfer_length(td_list);
+
/* error code of transfer */
cc = TD_CC_GET (tdINFO);
if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
@@ -1936,11 +1970,11 @@ static int hc_start_ohci (struct pci_dev * dev)
{
unsigned long mem_base;
- mem_base = dev->resource[0].start;
if (pci_enable_device(dev) < 0)
return -ENODEV;
pci_set_master (dev);
+ mem_base = dev->resource[0].start;
mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
if (!mem_base) {
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index e854e0c1d..3ac5dafb2 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -432,7 +432,7 @@ static int ep_unlink(ohci_t * ohci, ed_t * ed);
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
/* td */
-static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type, int index);
+static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index);
static void td_submit_urb(urb_t * urb);
/* root hub */
static int rh_submit_urb(urb_t * urb);
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index 42157dbab..b9cead4fe 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -1,7 +1,10 @@
/* Driver for USB Mass Storage compliant devices
*
- * (c) 1999 Michael Gee (michael@linuxspecific.com)
- * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
@@ -16,6 +19,9 @@
*
* Also, for certain devices, the interrupt endpoint is used to convey
* status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
*/
#include <linux/module.h>
@@ -111,10 +117,15 @@ struct us_data {
struct semaphore ip_waitq; /* for CBI interrupts */
int ip_wanted; /* is an IRQ expected? */
+ /* interrupt communications data */
struct semaphore irq_urb_sem; /* to protect irq_urb */
struct urb *irq_urb; /* for USB int requests */
unsigned char irqbuf[2]; /* buffer for USB IRQ */
+ /* control and bulk communications data */
+ struct semaphore current_urb_sem; /* to protect irq_urb */
+ struct urb *current_urb; /* non-int USB requests */
+
/* mutual exclusion structures */
struct semaphore notify; /* thread begin/end */
struct semaphore sleeper; /* to sleep the thread on */
@@ -147,6 +158,155 @@ static struct usb_driver storage_driver = {
* Data transfer routines
***********************************************************************/
+/* This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+static void usb_stor_blocking_completion(urb_t *urb)
+{
+ api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+ if (waitqueue_active(awd->wakeup))
+ wake_up(awd->wakeup);
+}
+
+/* This is our function to emulate usb_control_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAIT_QUEUE_HEAD(wqh);
+ api_wrapper_data awd;
+ int status;
+ devrequest *dr;
+
+ /* allocate the device request structure */
+ dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ /* fill in the structure */
+ dr->requesttype = requesttype;
+ dr->request = request;
+ dr->value = cpu_to_le16(value);
+ dr->index = cpu_to_le16(index);
+ dr->length = cpu_to_le16(size);
+
+ /* set up data structures for the wakeup system */
+ awd.wakeup = &wqh;
+ awd.handler = 0;
+ init_waitqueue_head(&wqh);
+ add_wait_queue(&wqh, &wait);
+
+ /* lock the URB */
+ down(&(us->current_urb_sem));
+
+ /* fill the URB */
+ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
+ (unsigned char*) dr, data, size,
+ usb_stor_blocking_completion, &awd);
+
+ /* submit the URB */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ status = usb_submit_urb(us->current_urb);
+ if (status) {
+ /* something went wrong */
+ up(&(us->current_urb_sem));
+ remove_wait_queue(&wqh, &wait);
+ kfree(dr);
+ return status;
+ }
+
+ /* wait for the completion of the URB */
+ up(&(us->current_urb_sem));
+ if (us->current_urb->status == -EINPROGRESS)
+ schedule_timeout(10*HZ);
+ down(&(us->current_urb_sem));
+
+ /* we either timed out or got woken up -- clean up either way */
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wqh, &wait);
+
+ /* did we time out? */
+ if (us->current_urb->status == -EINPROGRESS) {
+ US_DEBUGP("usb_stor_control_msg() timeout\n");
+ usb_unlink_urb(us->current_urb);
+ status = -ETIMEDOUT;
+ } else
+ status = us->current_urb->status;
+
+ /* return the actual length of the data transferred if no error*/
+ if (status >= 0)
+ status = us->current_urb->actual_length;
+
+ /* release the lock and return status */
+ up(&(us->current_urb_sem));
+ kfree(dr);
+ return status;
+}
+
+/* This is our function to emulate usb_bulk_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+ unsigned int len, unsigned int *act_len)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAIT_QUEUE_HEAD(wqh);
+ api_wrapper_data awd;
+ int status;
+
+ /* set up data structures for the wakeup system */
+ awd.wakeup = &wqh;
+ awd.handler = 0;
+ init_waitqueue_head(&wqh);
+ add_wait_queue(&wqh, &wait);
+
+ /* lock the URB */
+ down(&(us->current_urb_sem));
+
+ /* fill the URB */
+ FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
+ usb_stor_blocking_completion, &awd);
+
+ /* submit the URB */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ status = usb_submit_urb(us->current_urb);
+ if (status) {
+ /* something went wrong */
+ up(&(us->current_urb_sem));
+ remove_wait_queue(&wqh, &wait);
+ return status;
+ }
+
+ /* wait for the completion of the URB */
+ up(&(us->current_urb_sem));
+ if (us->current_urb->status == -EINPROGRESS)
+ schedule_timeout(10*HZ);
+ down(&(us->current_urb_sem));
+
+ /* we either timed out or got woken up -- clean up either way */
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wqh, &wait);
+
+ /* did we time out? */
+ if (us->current_urb->status == -EINPROGRESS) {
+ US_DEBUGP("usb_stor_bulk_msg() timeout\n");
+ usb_unlink_urb(us->current_urb);
+ status = -ETIMEDOUT;
+ } else
+ status = us->current_urb->status;
+
+ /* return the actual length of the data transferred */
+ *act_len = us->current_urb->actual_length;
+
+ /* release the lock and return status */
+ up(&(us->current_urb_sem));
+ return status;
+}
+
/*
* Transfer one SCSI scatter-gather buffer via bulk transfer
*
@@ -158,26 +318,33 @@ static struct usb_driver storage_driver = {
* timeout limit. Thus we don't have to worry about it for individual
* packets.
*/
-static int us_transfer_partial(struct us_data *us, int pipe,
- char *buf, int length)
+static int us_transfer_partial(struct us_data *us, char *buf, int length)
{
int result;
int partial;
+ int pipe;
+
+ /* calculate the appropriate pipe information */
+ if (US_DIRECTION(us->srb->cmnd[0]))
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
/* 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, 5*HZ);
- US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
+ US_DEBUGP("us_transfer_partial(): xfer %d bytes\n", length);
+ result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
+ US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
result, partial, length);
-
+
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
usb_clear_halt(us->pusb_dev, pipe);
}
-
+
/* did we send all the data? */
if (partial == length) {
+ US_DEBUGP("us_transfer_partial(): transfer complete\n");
return US_BULK_TRANSFER_GOOD;
}
@@ -186,7 +353,17 @@ static int us_transfer_partial(struct us_data *us, int pipe,
/* NAK - that means we've retried a few times allready */
if (result == -ETIMEDOUT) {
US_DEBUGP("us_transfer_partial(): device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
}
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ /* the catch-all case */
+ US_DEBUGP("us_transfer_partial(): unknown error\n");
return US_BULK_TRANSFER_FAILED;
}
@@ -203,21 +380,12 @@ static int us_transfer_partial(struct us_data *us, int pipe,
* function simply determines if we're going to use scatter-gather or not,
* and acts appropriately. For now, it also re-interprets the error codes.
*/
-static void us_transfer(Scsi_Cmnd *srb, int dir_in)
+static void us_transfer(Scsi_Cmnd *srb, struct us_data* us, int dir_in)
{
- struct us_data *us;
int i;
int result = -1;
- unsigned int pipe;
struct scatterlist *sg;
- /* calculate the appropriate pipe information */
- us = (struct us_data*) srb->host_scribble;
- if (dir_in)
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
- else
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
/* are we scatter-gathering? */
if (srb->use_sg) {
@@ -226,7 +394,7 @@ 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_transfer_partial(us, pipe, sg[i].address,
+ result = us_transfer_partial(us, sg[i].address,
sg[i].length);
if (result)
break;
@@ -234,7 +402,7 @@ static void us_transfer(Scsi_Cmnd *srb, int dir_in)
}
else
/* no scatter-gather, just make the request */
- result = us_transfer_partial(us, pipe, srb->request_buffer,
+ result = us_transfer_partial(us, srb->request_buffer,
srb->request_bufflen);
/* return the result in the data structure itself */
@@ -433,6 +601,8 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/*
* Control/Bulk/Interrupt transport
*/
+
+/* The interrupt handler for CBI devices */
static void CBI_irq(struct urb *urb)
{
struct us_data *us = (struct us_data *)urb->context;
@@ -465,13 +635,13 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* COMMAND STAGE */
/* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
+ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len);
/* check the return code for the command */
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
if (result < 0) {
/* STALL must be cleared when they are detected */
if (result == -EPIPE) {
@@ -493,7 +663,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, us)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
}
@@ -561,15 +731,14 @@ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* COMMAND STAGE */
/* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
+ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len);
/* check the return code for the command */
+ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
if (result < 0) {
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
-
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
@@ -587,7 +756,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, us)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
}
@@ -602,6 +771,39 @@ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/*
* Bulk only transport
*/
+
+/* Determine what the maximum LUN supported is */
+static int Bulk_max_lun(struct us_data *us)
+{
+ unsigned char data;
+ int result;
+ int pipe;
+
+ /* issue the command */
+ pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+ result = usb_control_msg(us->pusb_dev, pipe,
+ US_BULK_GET_MAX_LUN,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ 0, us->ifnum, &data, sizeof(data), HZ);
+
+ US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
+ result, data);
+
+ /* if we have a successful request, return the result */
+ if (!result)
+ return data;
+
+ /* if we get a STALL, clear the stall */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ /* return the default -- no LUNs */
+ return 0;
+}
+
static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap bcb;
@@ -629,8 +831,8 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun,
bcb.DataTransferLength, bcb.Flags, bcb.Length);
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
- US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+ result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN,
+ &partial);
US_DEBUGP("Bulk command transfer result=%d\n", result);
/* if we stall, we need to clear it before we go on */
@@ -643,7 +845,7 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result == 0) {
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
- us_transfer(srb, bcb.Flags);
+ us_transfer(srb, us, bcb.Flags);
US_DEBUGP("Bulk data transfer result 0x%x\n",
srb->result);
}
@@ -658,8 +860,8 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* 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*2);
+ result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN,
+ &partial);
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
@@ -668,8 +870,8 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* 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*2);
+ result = usb_stor_bulk_msg(us, &bcs, pipe,
+ US_BULK_CS_WRAP_LEN, &partial);
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
@@ -1025,9 +1227,9 @@ static int Bulk_reset(struct us_data *us)
result = usb_control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
- US_BULK_RESET,
+ US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- US_BULK_RESET_HARD, us->ifnum, NULL, 0, HZ*5);
+ 0, us->ifnum, NULL, 0, HZ*5);
if (result < 0)
US_DEBUGP("Bulk hard reset failed %d\n", result);
@@ -1049,7 +1251,7 @@ static int Bulk_reset(struct us_data *us)
static const char* us_info(struct Scsi_Host *host)
{
- return "SCSI emulation for USB Mass Storage devices\n";
+ return "SCSI emulation for USB Mass Storage devices";
}
/* detect a virtual adapter (always works) */
@@ -1109,6 +1311,7 @@ static int us_release(struct Scsi_Host *psh)
/* free the data structure we were using */
US_DEBUGP("-- freeing private host data structure\n");
+ kfree(us->current_urb);
kfree(us);
(struct us_data*)psh->hostdata[0] = NULL;
@@ -1289,22 +1492,11 @@ static Scsi_Host_Template my_host_template = {
};
static unsigned char sense_notready[] = {
- 0x70, /* current error */
- 0x00,
- 0x02, /* not ready */
- 0x00,
- 0x00,
- 0x0a, /* additional length */
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x04, /* not ready */
- 0x03, /* manual intervention */
- 0x00,
- 0x00,
- 0x00,
- 0x00
+ [0] = 0x70, /* current error */
+ [2] = 0x02, /* not ready */
+ [5] = 0x0a, /* additional length */
+ [10] = 0x04, /* not ready */
+ [11] = 0x03 /* manual intervention */
};
static int usb_stor_control_thread(void * __us)
@@ -1429,25 +1621,31 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
+/* This is the list of devices we recognize, along with their flag data */
static struct us_unusual_dev us_unusual_dev_list[] = {
+ { 0x03f0, 0x0107, 0x0200,
+ "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0},
+ { 0x04e6, 0x0001, 0x0200,
+ "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x04e6, 0x0002, 0x0100,
+ "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x04e6, 0x0006, 0x0100,
+ "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
{ 0x057b, 0x0000, 0x0114,
- "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN },
+ "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
{ 0x059b, 0x0030, 0x0100,
- "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN },
+ "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN},
+ { 0x0693, 0x0002, 0x0100,
+ "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK,
+ US_FL_ALT_LENGTH},
{ 0x0781, 0x0001, 0x0200,
- "Sandisk ImageMate (w/eject button)", US_SC_SCSI, US_PR_CB,
- US_FL_SINGLE_LUN | US_FL_START_STOP },
+ "Sandisk ImageMate (SDDR-01)", 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 | US_FL_IGNORE_SER },
+ "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK,
+ US_FL_SINGLE_LUN | US_FL_IGNORE_SER},
{ 0x07af, 0x0005, 0x0100,
"Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0002, 0x0100,
- "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0006, 0x0100,
- "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x03f0, 0x0107, 0x0200,
- "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0},
{ 0x0000, 0x0000, 0x0,
"", 0, 0, 0}
};
@@ -1713,12 +1911,20 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
memset(ss, 0, sizeof(struct us_data));
+ /* allocate the URB we're going to use */
+ ss->current_urb = usb_alloc_urb(0);
+ if (!ss->current_urb) {
+ kfree(ss);
+ return NULL;
+ }
+
/* Initialize the mutexes only when the struct is new */
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX_LOCKED(&(ss->ip_waitq));
init_MUTEX(&(ss->queue_exclusion));
init_MUTEX(&(ss->irq_urb_sem));
+ init_MUTEX(&(ss->current_urb_sem));
init_MUTEX(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */
@@ -1774,11 +1980,14 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->transport_name = "Bulk";
ss->transport = Bulk_transport;
ss->transport_reset = Bulk_reset;
+ /* FIXME: for testing purposes only */
+ Bulk_max_lun(ss);
break;
default:
ss->transport_name = "Unknown";
up(&us_list_semaphore);
+ kfree(ss->current_urb);
kfree(ss);
return NULL;
break;
@@ -1802,6 +2011,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
US_DEBUGP("if you see this message.\n");
up(&us_list_semaphore);
+ kfree(ss->current_urb);
kfree(ss);
return NULL;
break;
@@ -1824,6 +2034,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
default:
ss->protocol_name = "Unknown";
up(&us_list_semaphore);
+ kfree(ss->current_urb);
kfree(ss);
return NULL;
break;
@@ -1859,6 +2070,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
if (ss->pid < 0) {
printk(KERN_WARNING USB_STORAGE
"Unable to start control thread\n");
+ kfree(ss->current_urb);
kfree(ss);
return NULL;
}
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 0d5152e36..6e54b059b 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -77,16 +77,17 @@ struct bulk_cs_wrap {
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
-#define US_BULK_RESET 0xff
-#define US_BULK_RESET_SOFT 1
-#define US_BULK_RESET_HARD 0
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST 0xff
+#define US_BULK_GET_MAX_LUN 0xfe
/*
* us_bulk_transfer() return codes
*/
-#define US_BULK_TRANSFER_GOOD 0
-#define US_BULK_TRANSFER_SHORT 1
-#define US_BULK_TRANSFER_FAILED 2
+#define US_BULK_TRANSFER_GOOD 0 /* good transfer */
+#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */
+#define US_BULK_TRANSFER_FAILED 2 /* transfer died in the middle */
+#define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */
/*
* Transport return codes
@@ -95,6 +96,7 @@ struct bulk_cs_wrap {
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
+#define USB_STOR_TRANSPORT_ABORTED 3 /* Transport aborted */
/*
* CBI accept device specific command
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 8a3318612..f2c51f205 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
+ * $Id: usb-uhci.c,v 1.231 2000/05/13 15:34:17 acher Exp $
*/
#include <linux/config.h>
@@ -48,7 +48,7 @@
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
-#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.231 $ time " __TIME__ " " __DATE__
#include <linux/usb.h>
#include "usb-uhci.h"
@@ -109,10 +109,10 @@ void clean_descs(uhci_t *s, int force)
while (q != &s->free_desc) {
qh = list_entry (q, uhci_desc_t, horizontal);
+ q=qh->horizontal.prev;
+
if ((qh->last_used!=now) || force)
delete_qh(s,qh);
-
- q=qh->horizontal.prev;
}
}
/*-------------------------------------------------------------------*/
@@ -1142,6 +1142,12 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
urb->status = -ENOENT; // now the urb is really dead
+ switch (usb_pipetype (pipe)) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ uhci_clean_iso_step2(s, urb_priv);
+ break;
+ }
usb_dec_dev_use (dev);
#ifdef DEBUG_SLAB
@@ -1149,12 +1155,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
#else
kfree (urb_priv);
#endif
- switch (usb_pipetype (pipe)) {
- case PIPE_ISOCHRONOUS:
- case PIPE_INTERRUPT:
- uhci_clean_iso_step2(s, urb_priv);
- break;
- }
+
list_del (&urb->urb_list);
}
}
@@ -1168,7 +1169,9 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
async_dbg("unlink_urb_async called %p",urb);
- if (urb->status == -EINPROGRESS) {
+ if ((urb->status == -EINPROGRESS) ||
+ ((usb_pipetype (urb->pipe) == PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+ {
((urb_priv_t*)urb->hcpriv)->started = ~0;
dequeue_urb (s, urb);
@@ -1560,7 +1563,7 @@ _static int uhci_submit_urb (urb_t *urb)
urb->hcpriv = urb_priv;
INIT_LIST_HEAD (&urb_priv->desc_list);
- urb_priv->short_control_packet = 0;
+ urb_priv->flags = 0;
dbg("submit_urb: scheduling %p", urb);
urb_priv->next_queued_urb = NULL;
urb_priv->prev_queued_urb = NULL;
@@ -2151,7 +2154,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
status stage is completed
*/
- if (urb_priv->short_control_packet &&
+ if (urb_priv->flags &&
((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE))))
goto transfer_finished;
@@ -2199,7 +2202,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
//uhci_show_td (desc);
//uhci_show_td (last_desc);
- urb_priv->short_control_packet=1;
+ urb_priv->flags = 1; // mark as short control packet
return 0;
}
}
@@ -2280,35 +2283,43 @@ _static int process_interrupt (uhci_t *s, urb_t *urb)
if (urb->complete) {
//dbg("process_interrupt: calling completion, status %i",status);
urb->status = status;
-
+ ((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
+
spin_unlock(&s->urb_list_lock);
urb->complete ((struct urb *) urb);
spin_lock(&s->urb_list_lock);
-
- urb->status = -EINPROGRESS;
+
+ ((urb_priv_t*)urb->hcpriv)->flags=0;
}
+
+ if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+ (urb->status != -ENOENT)) {
+
+ urb->status = -EINPROGRESS;
- // Recycle INT-TD if interval!=0, else mark TD as one-shot
- if (urb->interval) {
-
- desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
- if (status==0) {
- ((urb_priv_t*)urb->hcpriv)->started=jiffies;
- desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
- usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
- usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
- } else {
- desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
- usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+ // Recycle INT-TD if interval!=0, else mark TD as one-shot
+ if (urb->interval) {
+
+ desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
+ if (status==0) {
+ ((urb_priv_t*)urb->hcpriv)->started=jiffies;
+ desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+ } else {
+ desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+ usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+ }
+ desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+ (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+ mb();
+ }
+ else {
+ uhci_unlink_urb_async(s, urb);
+ desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
}
- desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
- (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
- mb();
- }
- else {
- desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
}
}
@@ -2334,7 +2345,7 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode)
dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
urb->number_of_packets,mode,desc->hw.td.status);
- for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) {
+ for (i = 0; p != &urb_priv->desc_list; i++) {
desc = list_entry (p, uhci_desc_t, desc_list);
//uhci_show_td(desc);
@@ -2378,8 +2389,9 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode)
dbg("process_iso: %i: len:%d %08x status:%x",
i, urb->iso_frame_desc[i].actual_length, desc->hw.td.status,urb->iso_frame_desc[i].status);
- delete_desc (desc);
list_del (p);
+ p = p->next;
+ delete_desc (desc);
}
dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
@@ -2824,7 +2836,6 @@ int __init uhci_init (void)
if (type != 0)
continue;
-
if (pci_enable_device (dev) < 0)
continue;
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
index 3c5717d1e..67eb4d210 100644
--- a/drivers/usb/usb-uhci.h
+++ b/drivers/usb/usb-uhci.h
@@ -2,7 +2,7 @@
#define __LINUX_UHCI_H
/*
- $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
+ $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $
*/
#define MODNAME "usb-uhci"
#define UHCI_LATENCY_TIMER 0
@@ -160,7 +160,7 @@ typedef struct {
uhci_desc_t *bottom_qh;
uhci_desc_t *next_qh; // next helper QH
char use_loop;
- char short_control_packet;
+ char flags;
} urb_priv_t, *purb_priv_t;
struct virt_root_hub {
diff --git a/drivers/usb/wacom.c b/drivers/usb/wacom.c
index cb77f0717..3fa4a2d35 100644
--- a/drivers/usb/wacom.c
+++ b/drivers/usb/wacom.c
@@ -104,8 +104,8 @@ struct wacom_features {
int distance_max;
void (*irq)(struct urb *urb);
unsigned long evbit;
- unsigned long relbit;
unsigned long absbit;
+ unsigned long relbit;
unsigned long btnbit;
unsigned long digibit;
};