summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/usb/sn9c102.txt122
-rw-r--r--drivers/usb/core/hcd-pci.c151
-rw-r--r--drivers/usb/core/hcd.c42
-rw-r--r--drivers/usb/core/hub.c26
-rw-r--r--drivers/usb/core/usb.c8
-rw-r--r--drivers/usb/gadget/file_storage.c4
-rw-r--r--drivers/usb/gadget/rndis.c4
-rw-r--r--drivers/usb/host/ehci-hcd.c39
-rw-r--r--drivers/usb/host/ehci-hub.c44
-rw-r--r--drivers/usb/host/ehci-sched.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c12
-rw-r--r--drivers/usb/host/ohci-hub.c56
-rw-r--r--drivers/usb/host/ohci-pci.c5
-rw-r--r--drivers/usb/host/ohci.h12
-rw-r--r--drivers/usb/media/sn9c102.h14
-rw-r--r--drivers/usb/media/sn9c102_core.c324
-rw-r--r--drivers/usb/media/sn9c102_pas106b.c113
-rw-r--r--drivers/usb/media/sn9c102_pas202bcb.c95
-rw-r--r--drivers/usb/media/sn9c102_sensor.h25
-rw-r--r--drivers/usb/media/sn9c102_tas5110c1b.c4
-rw-r--r--drivers/usb/media/sn9c102_tas5130d1b.c8
-rw-r--r--drivers/usb/misc/rio500.c14
-rw-r--r--drivers/usb/misc/tiglusb.c4
-rw-r--r--drivers/usb/misc/usbtest.c6
-rw-r--r--drivers/usb/net/Kconfig25
-rw-r--r--drivers/usb/serial/io_edgeport.c254
-rw-r--r--drivers/usb/serial/io_fw_boot.h6
-rw-r--r--drivers/usb/serial/io_fw_boot2.h6
-rw-r--r--drivers/usb/serial/io_fw_down.h6
-rw-r--r--drivers/usb/serial/io_fw_down2.h6
-rw-r--r--drivers/usb/serial/io_tables.h9
-rw-r--r--drivers/usb/serial/io_ti.c812
-rw-r--r--drivers/usb/serial/io_usbvend.h2
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/serial/mct_u232.c2
-rw-r--r--drivers/usb/serial/usb-serial.c65
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/storage/freecom.c2
-rw-r--r--drivers/usb/storage/unusual_devs.h15
-rw-r--r--include/linux/videodev2.h1
40 files changed, 1600 insertions, 748 deletions
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
index 40c2f73a707f..18ceabdb36e4 100644
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -9,28 +9,32 @@
Index
=====
1. Copyright
-2. License
-3. Overview
-4. Module dependencies
-5. Module loading
-6. Module parameters
-7. Optional device control through "sysfs"
-8. Supported devices
-9. How to add support for new image sensors
-10. Notes for V4L2 application developers
-11. Contact information
-12. Credits
+2. Disclaimer
+3. License
+4. Overview
+5. Driver installation
+6. Module loading
+7. Module parameters
+8. Optional device control through "sysfs"
+9. Supported devices
+10. How to add support for new image sensors
+11. Notes for V4L2 application developers
+12. Contact information
+13. Credits
1. Copyright
============
Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+2. Disclaimer
+=============
SONiX is a trademark of SONiX Technology Company Limited, inc.
-This driver is not sponsored or developed by SONiX.
+This software is not sponsored or developed by SONiX.
-2. License
+3. License
==========
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -47,29 +51,52 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-3. Overview
+4. Overview
===========
This driver attempts to support the video and audio streaming capabilities of
the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC
Camera Controllers.
-- It's worth to note that SONiX has never collaborated with me during the
+It's worth to note that SONiX has never collaborated with the author during the
development of this project, despite several requests for enough detailed
specifications of the register tables, compression engine and video data format
-of the above chips -
-
-Up to 64 cameras can be handled at the same time. They can be connected and
-disconnected from the host many times without turning off the computer, if
-your system supports hotplugging.
+of the above chips.
The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well.
The latest version of the SN9C10x driver can be found at the following URL:
-http://go.lamarinapunto.com/
-
-
-4. Module dependencies
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+ application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+ data transfers;
+- automatic detection of image sensor;
+- support for any window resolutions and optional panning within the maximum
+ pixel area of image sensor;
+- image downscaling with arbitrary scaling factors from 1, 2 and 4 in both
+ directions (see "Notes for V4L2 application developers" paragraph);
+- two different video formats for uncompressed or compressed data (see also
+ "Notes for V4L2 application developers" paragraph);
+- full support for the capabilities of many of the possible image sensors that
+ can be connected to the SN9C10x bridges, including, for istance, red, green,
+ blue and global gain adjustments and exposure (see "Supported devices"
+ paragraph for details);
+- use of default color settings for sunlight conditions;
+- dynamic I/O interface for both SN9C10x and image sensor control (see
+ "Optional device control through 'sysfs'" paragraph);
+- dynamic driver control thanks to various module parameters (see "Module
+ parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+ disconnected from the host many times without turning off the computer, if
+ your system supports hotplugging;
+- no known bugs.
+
+
+5. Module dependencies
======================
For it to work properly, the driver needs kernel support for Video4Linux and
USB.
@@ -101,7 +128,7 @@ And finally:
CONFIG_USB_SN9C102=m
-5. Module loading
+6. Module loading
=================
To use the driver, it is necessary to load the "sn9c102" module into memory
after every other module required: "videodev", "usbcore" and, depending on
@@ -109,7 +136,6 @@ the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
Loading can be done as shown below:
- [root@localhost home]# modprobe usbcore
[root@localhost home]# modprobe sn9c102
At this point the devices should be recognized. You can invoke "dmesg" to
@@ -118,7 +144,7 @@ analyze kernel messages and verify that the loading process has gone well:
[user@localhost home]$ dmesg
-6. Module parameters
+7. Module parameters
====================
Module parameters are listed below:
-------------------------------------------------------------------------------
@@ -144,12 +170,14 @@ Description: Debugging information level, from 0 to 3:
2 = significant informations
3 = more verbose messages
Level 3 is useful for testing only, when only one device
- is used.
+ is used. It also shows some more informations about the
+ hardware being detected. This parameter can be changed at
+ runtime thanks to the /sys filesystem.
Default: 2
-------------------------------------------------------------------------------
-7. Optional device control through "sysfs"
+8. Optional device control through "sysfs"
==========================================
It is possible to read and write both the SN9C10x and the image sensor
registers by using the "sysfs" filesystem interface.
@@ -191,10 +219,10 @@ Note that the SN9C10x always returns 0 when some of its registers are read.
To avoid race conditions, all the I/O accesses to the files are serialized.
-8. Supported devices
+9. Supported devices
====================
-- I won't mention any of the names of the companies as well as their products
-here. They have never collaborated with me, so no advertising -
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
From the point of view of a driver, what unambiguously identify a device are
its vendor and product USB identifiers. Below is a list of known identifiers of
@@ -241,7 +269,7 @@ Vendor ID Product ID
0x0c45 0x60bc
0x0c45 0x60be
-The list above does NOT imply that all those devices work with this driver: up
+The list above does not imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported;
kernel messages will always tell you whether this is the case:
@@ -259,16 +287,16 @@ If you think your camera is based on the above hardware and is not actually
listed in the above table, you may try to add the specific USB VendorID and
ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
then compile, load the module again and look at the kernel output.
-If this works, please send an email to me reporting the kernel messages, so
-that I can add a new entry in the list of supported devices.
+If this works, please send an email to the author reporting the kernel
+messages, so that a new entry in the list of supported devices can be added.
Donations of new models for further testing and support would be much
-appreciated. I won't add official support for hardware that I don't actually
-have.
+appreciated. Non-available hardware won't be supported by the author of this
+driver.
-9. How to add support for new image sensors
-===========================================
+10. How to add support for new image sensors
+============================================
It should be easy to write code for new sensors by using the small API that I
have created for this purpose, which is present in "sn9c102_sensor.h"
(documentation is included there). As an example, have a look at the code in
@@ -278,7 +306,7 @@ At the moment, possible unsupported image sensors are: HV7131x series (VGA),
MI03x series (VGA), OV7620 (VGA), OV7630 (VGA), CIS-VF10 (VGA).
-10. Notes for V4L2 application developers
+11. Notes for V4L2 application developers
=========================================
This driver follows the V4L2 API specifications. In particular, it enforces two
rules:
@@ -301,8 +329,18 @@ factor can be chosen arbitrarily by the "negotiation" of the "source" and
that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1.
+This driver supports two different video formats: the first one is the "8-bit
+Sequential Bayer" format and can be used to obtain uncompressed video data
+from the device through the current I/O method, while the second one provides
+"raw" compressed video data (without the initial and final frame headers). The
+compression quality may vary from 0 to 1 and can be selected or queried thanks
+to the VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP V4L2 ioctl's. For maximum
+flexibility, the default active video format depends on how the image sensor
+being used is initialized (as described in the documentation of the API for the
+image sensors supplied by this driver).
+
-11. Contact information
+12. Contact information
=======================
I may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
@@ -311,7 +349,7 @@ My public 1024-bit key should be available at any keyserver; the fingerprint
is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
-12. Credits
+13. Credits
===========
I would thank the following persons:
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index bd5c7498d9ba..0a273a8fe121 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -71,12 +71,14 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
if (pci_enable_device (dev) < 0)
return -ENODEV;
dev->current_state = 0;
+ dev->dev.power.power_state = 0;
if (!dev->irq) {
dev_err (&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
- return -ENODEV;
+ retval = -ENODEV;
+ goto done;
}
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
@@ -85,7 +87,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
len = pci_resource_len (dev, 0);
if (!request_mem_region (resource, len, driver->description)) {
dev_dbg (&dev->dev, "controller already in use\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
base = ioremap_nocache (resource, len);
if (base == NULL) {
@@ -95,7 +98,7 @@ clean_1:
release_mem_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- return retval;
+ goto done;
}
} else { // UHCI
@@ -112,7 +115,8 @@ clean_1:
}
if (region == PCI_ROM_RESOURCE) {
dev_dbg (&dev->dev, "no i/o regions available\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
base = (void __iomem *) resource;
}
@@ -132,7 +136,7 @@ clean_2:
release_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- return retval;
+ goto done;
}
}
// hcd zeroed everything
@@ -200,6 +204,9 @@ clean_3:
usb_hcd_pci_remove (dev);
}
+done:
+ if (retval != 0)
+ pci_disable_device (dev);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -297,82 +304,78 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
state = 4;
switch (hcd->state) {
- case USB_STATE_HALT:
- dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
- break;
- case HCD_STATE_SUSPENDED:
- dev_dbg (hcd->self.controller, "PCI %s --> %s\n",
- pci_state(dev->current_state),
- pci_state(has_pci_pm ? state : 0));
- if (state > 3)
- state = 3;
- if (state == dev->current_state)
- break;
- else if (state < dev->current_state)
- retval = -EIO;
- else if (has_pci_pm)
- retval = pci_set_power_state (dev, state);
-
- if (retval == 0)
- dev->dev.power.power_state = state;
- else
- dev_dbg (hcd->self.controller,
- "re-suspend fail, %d\n", retval);
- break;
- default:
+ /* entry if root hub wasn't yet suspended ... from sysfs,
+ * without autosuspend, or if USB_SUSPEND isn't configured.
+ */
+ case USB_STATE_RUNNING:
+ hcd->state = USB_STATE_QUIESCING;
retval = hcd->driver->suspend (hcd, state);
- if (retval)
+ if (retval) {
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
- else {
- hcd->state = HCD_STATE_SUSPENDED;
- pci_save_state (dev);
+ break;
+ }
+ hcd->state = HCD_STATE_SUSPENDED;
+ /* FALLTHROUGH */
+
+ /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
+ * controller and/or root hub will already have been suspended,
+ * but it won't be ready for a PCI resume call.
+ *
+ * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
+ * have been called, otherwise root hub timers still run ...
+ */
+ case HCD_STATE_SUSPENDED:
+ if (state <= dev->current_state)
+ break;
- /* no DMA or IRQs except in D0 */
+ /* no DMA or IRQs except in D0 */
+ if (!dev->current_state) {
+ pci_save_state (dev);
pci_disable_device (dev);
free_irq (hcd->irq, hcd);
-
- if (has_pci_pm) {
- retval = pci_set_power_state (dev, state);
-
- /* POLICY: ignore D1/D2/D3hot differences;
- * we know D3hot will always work.
- */
- if (retval < 0 && state < 3) {
- retval = pci_set_power_state (dev, 3);
- if (retval == 0)
- state = 3;
- }
- if (retval == 0) {
- dev->dev.power.power_state = state;
+ }
+
+ if (!has_pci_pm) {
+ dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
+ break;
+ }
+
+ /* POLICY: ignore D1/D2/D3hot differences;
+ * we know D3hot will always work.
+ */
+ retval = pci_set_power_state (dev, state);
+ if (retval < 0 && state < 3) {
+ retval = pci_set_power_state (dev, 3);
+ if (retval == 0)
+ state = 3;
+ }
+ if (retval == 0) {
+ dev_dbg (hcd->self.controller, "--> PCI %s\n",
+ pci_state(dev->current_state));
#ifdef CONFIG_USB_SUSPEND
- pci_enable_wake (dev, state,
- hcd->remote_wakeup);
- pci_enable_wake (dev, 4,
- hcd->remote_wakeup);
+ pci_enable_wake (dev, state, hcd->remote_wakeup);
+ pci_enable_wake (dev, 4, hcd->remote_wakeup);
#endif
- }
- } else {
- if (state > 3)
- state = 3;
- dev->dev.power.power_state = state;
- }
- if (retval < 0) {
- dev_dbg (&dev->dev,
- "PCI %s suspend fail, %d\n",
- pci_state(state),
- retval);
- (void) usb_hcd_pci_resume (dev);
- } else {
- dev_dbg(hcd->self.controller,
- "suspended to PCI %s%s\n",
- pci_state(dev->current_state),
- has_pci_pm ? "" : " (legacy)");
- }
+ } else if (retval < 0) {
+ dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
+ pci_state(state), retval);
+ (void) usb_hcd_pci_resume (dev);
+ break;
}
+ break;
+ default:
+ dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
+ hcd->state);
+ retval = -EINVAL;
+ break;
}
+
+ /* update power_state **ONLY** to make sysfs happier */
+ if (retval == 0)
+ dev->dev.power.power_state = state;
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -390,6 +393,11 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int has_pci_pm;
hcd = pci_get_drvdata(dev);
+ if (hcd->state != HCD_STATE_SUSPENDED) {
+ dev_dbg (hcd->self.controller,
+ "can't resume, not suspended!\n");
+ return 0;
+ }
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
/* D3cold resume isn't usually reported this way... */
@@ -397,11 +405,6 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
pci_state(dev->current_state),
has_pci_pm ? "" : " (legacy)");
- if (hcd->state != HCD_STATE_SUSPENDED) {
- dev_dbg (hcd->self.controller,
- "can't resume, not suspended!\n");
- return -EL3HLT;
- }
hcd->state = USB_STATE_RESUMING;
if (has_pci_pm)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 04bb2b5d5f20..dc67f3ddf425 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -479,6 +479,11 @@ error:
/*
* Root Hub interrupt transfers are synthesized with a timer.
* Completions are called in_interrupt() but not in_irq().
+ *
+ * Note: some root hubs (including common UHCI based designs) can't
+ * correctly issue port change IRQs. They're the ones that _need_ a
+ * timer; most other root hubs don't. Some systems could save a
+ * lot of battery power by eliminating these root hub timer IRQs.
*/
static void rh_report_status (unsigned long ptr);
@@ -488,10 +493,7 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
/* rh_timer protected by hcd_data_lock */
- if (hcd->rh_timer.data
- || urb->status != -EINPROGRESS
- || urb->transfer_buffer_length < len
- || !HCD_IS_RUNNING (hcd->state)) {
+ if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller,
"not queuing rh status urb, stat %d\n",
urb->status);
@@ -530,19 +532,19 @@ static void rh_report_status (unsigned long ptr)
return;
}
- if (!HCD_IS_SUSPENDED (hcd->state))
- length = hcd->driver->hub_status_data (
- hcd, urb->transfer_buffer);
-
/* complete the status urb, or retrigger the timer */
spin_lock (&hcd_data_lock);
- if (length > 0) {
- hcd->rh_timer.data = 0;
- urb->actual_length = length;
- urb->status = 0;
- urb->hcpriv = NULL;
- } else if (!urb->dev->dev.power.power_state)
- mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+ if (urb->dev->state == USB_STATE_CONFIGURED) {
+ length = hcd->driver->hub_status_data (
+ hcd, urb->transfer_buffer);
+ if (length > 0) {
+ hcd->rh_timer.data = 0;
+ urb->actual_length = length;
+ urb->status = 0;
+ urb->hcpriv = NULL;
+ } else
+ mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+ }
spin_unlock (&hcd_data_lock);
spin_unlock (&urb->lock);
@@ -1103,13 +1105,17 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
spin_lock_irqsave (&hcd_data_lock, flags);
if (unlikely (urb->reject))
status = -EPERM;
- else if (HCD_IS_RUNNING (hcd->state) &&
- hcd->state != USB_STATE_QUIESCING) {
+ else switch (hcd->state) {
+ case USB_STATE_RUNNING:
+ case USB_STATE_RESUMING:
usb_get_dev (urb->dev);
list_add_tail (&urb->urb_list, &dev->urb_list);
status = 0;
- } else
+ break;
+ default:
status = -ESHUTDOWN;
+ break;
+ }
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 72a7341bfb0a..161c52f2e42a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1373,7 +1373,10 @@ static int hub_port_reset(struct usb_device *hdev, int port,
status = hub_port_wait_reset(hdev, port, udev, delay);
/* return on disconnect or reset */
- if (status == -ENOTCONN || status == 0) {
+ switch (status) {
+ case 0:
+ case -ENOTCONN:
+ case -ENODEV:
clear_port_feature(hdev,
port + 1, USB_PORT_FEAT_C_RESET);
/* FIXME need disconnect() for NOTATTACHED device */
@@ -1524,7 +1527,7 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
if (port < 0)
return port;
- if (udev->dev.power.power_state
+ if (udev->state == USB_STATE_SUSPENDED
|| udev->state == USB_STATE_NOTATTACHED) {
return 0;
}
@@ -1595,16 +1598,16 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
*/
if (!udev->parent) {
struct usb_bus *bus = udev->bus;
- if (bus && bus->op->hub_suspend)
+ if (bus && bus->op->hub_suspend) {
status = bus->op->hub_suspend (bus);
- else
+ if (status == 0)
+ usb_set_device_state(udev,
+ USB_STATE_SUSPENDED);
+ } else
status = -EOPNOTSUPP;
} else
status = hub_port_suspend(udev->parent, port);
- if (status == 0)
- udev->dev.power.power_state = PM_SUSPEND_MEM;
- up(&udev->serialize);
return status;
}
EXPORT_SYMBOL(__usb_suspend_device);
@@ -1652,7 +1655,6 @@ static int finish_port_resume(struct usb_device *udev)
/* caller owns the udev device lock */
dev_dbg(&udev->dev, "usb resume\n");
- udev->dev.power.power_state = PM_SUSPEND_ON;
/* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the
@@ -1809,14 +1811,15 @@ int usb_resume_device(struct usb_device *udev)
*/
if (!udev->parent) {
struct usb_bus *bus = udev->bus;
- if (bus && bus->op->hub_resume)
+ if (bus && bus->op->hub_resume) {
status = bus->op->hub_resume (bus);
- else
+ } else
status = -EOPNOTSUPP;
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
- status = hub_resume (bus->root_hub
+ usb_set_device_state (udev, USB_STATE_CONFIGURED);
+ status = hub_resume (udev
->actconfig->interface[0]);
}
} else if (udev->state == USB_STATE_SUSPENDED) {
@@ -1824,7 +1827,6 @@ int usb_resume_device(struct usb_device *udev)
status = hub_port_resume(udev->parent, port);
} else {
status = 0;
- udev->dev.power.power_state = PM_SUSPEND_ON;
}
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n",
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8743ccba52dd..5953b352122d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1395,10 +1395,6 @@ static int usb_generic_suspend(struct device *dev, u32 state)
struct usb_interface *intf;
struct usb_driver *driver;
- /* there's only one USB suspend state */
- if (dev->power.power_state)
- return 0;
-
if (dev->driver == &usb_generic_driver)
return usb_suspend_device (to_usb_device(dev), state);
@@ -1409,6 +1405,10 @@ static int usb_generic_suspend(struct device *dev, u32 state)
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
+ /* there's only one USB suspend state */
+ if (intf->dev.power.power_state)
+ return 0;
+
if (driver->suspend)
return driver->suspend(intf, state);
return 0;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 3f447086b318..8d8259d23c95 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -3579,7 +3579,7 @@ static ssize_t show_file(struct device *dev, char *buf)
}
-ssize_t store_ro(struct device *dev, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@@ -3603,7 +3603,7 @@ ssize_t store_ro(struct device *dev, const char *buf, size_t count)
return rc;
}
-ssize_t store_file(struct device *dev, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index fa40ed4cdfc2..c3d064b09ef1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1275,7 +1275,7 @@ int rndis_rm_hdr (u8 *buf, u32 *length)
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
+static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
void *data)
{
char *out = page;
@@ -1320,7 +1320,7 @@ int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
return len;
}
-int rndis_proc_write (struct file *file, const char __user *buffer,
+static int rndis_proc_write (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
rndis_params *p = data;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ba0579fbb97a..9c85f3d0ae36 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -172,13 +172,6 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
return -ETIMEDOUT;
}
-/*
- * hc states include: unknown, halted, ready, running
- * transitional states are messy just now
- * trying to avoid "running" unless urbs are active
- * a "ready" hc can be finishing prefetched work
- */
-
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
@@ -480,8 +473,8 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->async->hw_qtd_next = EHCI_LIST_END;
ehci->async->qh_state = QH_STATE_LINKED;
ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
- writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
}
+ writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
@@ -540,7 +533,6 @@ done2:
}
udev->speed = USB_SPEED_HIGH;
udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
- udev->dev.power.power_state = PM_SUSPEND_ON;
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
@@ -663,20 +655,19 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- if (hcd->self.root_hub->dev.power.power_state)
- return 0;
-
- while (time_before (jiffies, ehci->next_statechange))
+ if (time_before (jiffies, ehci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub, state);
#else
- /* FIXME lock root hub */
+ usb_lock_device (hcd->self.root_hub);
(void) ehci_hub_suspend (hcd);
+ usb_unlock_device (hcd->self.root_hub);
#endif
// save (PCI) FLADJ in case of Vaux power loss
+ // ... we'd only use it to handle clock skew
return 0;
}
@@ -687,10 +678,11 @@ static int ehci_resume (struct usb_hcd *hcd)
unsigned port;
struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL;
+ int powerup = 0;
// maybe restore (PCI) FLADJ
- while (time_before (jiffies, ehci->next_statechange))
+ if (time_before (jiffies, ehci->next_statechange))
msleep (100);
/* If any port is suspended, we know we can/must resume the HC. */
@@ -704,6 +696,8 @@ static int ehci_resume (struct usb_hcd *hcd)
up (&hcd->self.root_hub->serialize);
break;
}
+ if ((status & PORT_POWER) == 0)
+ powerup = 1;
if (!root->children [port])
continue;
dbg_port (ehci, __FUNCTION__, port + 1, status);
@@ -728,9 +722,20 @@ static int ehci_resume (struct usb_hcd *hcd)
/* restart; khubd will disconnect devices */
retval = ehci_start (hcd);
+
+ /* here we "know" root ports should always stay powered;
+ * but some controllers may lost all power.
+ */
+ if (powerup) {
+ ehci_dbg (ehci, "...powerup ports...\n");
+ for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+ (void) ehci_hub_control(hcd,
+ SetPortFeature, USB_PORT_FEAT_POWER,
+ port--, NULL, 0);
+ msleep(20);
+ }
}
- if (retval == 0)
- hcd->self.controller->power.power_state = 0;
+
return retval;
}
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 796f8805f0ea..330b4b0902ce 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -33,24 +33,19 @@
static int ehci_hub_suspend (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
int port;
- if (root->dev.power.power_state != 0)
- return 0;
if (time_before (jiffies, ehci->next_statechange))
- return -EAGAIN;
+ msleep(5);
port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock);
- /* for hcd->state HCD_STATE_SUSPENDED, also stop the non-USB side */
- root->dev.power.power_state = 3;
- root->state = USB_STATE_SUSPENDED;
-
/* stop schedules, clean any completed work */
- if (HCD_IS_RUNNING(hcd->state))
+ if (HCD_IS_RUNNING(hcd->state)) {
ehci_quiesce (ehci);
+ ehci->hcd.state = USB_STATE_QUIESCING;
+ }
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
@@ -78,6 +73,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
/* turn off now-idle HC */
ehci_halt (ehci);
+ ehci->hcd.state = HCD_STATE_SUSPENDED;
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
@@ -89,27 +85,27 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
static int ehci_hub_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
u32 temp;
int i;
+ int intr_enable;
- if (!root->dev.power.power_state)
- return 0;
if (time_before (jiffies, ehci->next_statechange))
- return -EAGAIN;
+ msleep(5);
+ spin_lock_irq (&ehci->lock);
/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
- temp = 1;
- writel (INTR_MASK, &ehci->regs->intr_enable);
+ /* at least some APM implementations will try to deliver
+ * IRQs right away, so delay them until we're ready.
+ */
+ intr_enable = 1;
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
- /* FIXME will this work even if (pci) vAUX was lost? */
} else
- temp = 0;
+ intr_enable = 0;
ehci_dbg(ehci, "resume root hub%s\n",
- temp ? " after power loss" : "");
+ intr_enable ? " after power loss" : "");
/* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command);
@@ -148,9 +144,14 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
writel (ehci->command, &ehci->regs->command);
}
- root->dev.power.power_state = 0;
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
ehci->hcd.state = USB_STATE_RUNNING;
+
+ /* Now we can safely re-enable irqs */
+ if (intr_enable)
+ writel (INTR_MASK, &ehci->regs->intr_enable);
+
+ spin_unlock_irq (&ehci->lock);
return 0;
}
@@ -210,6 +211,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
int ports, i, retval = 1;
unsigned long flags;
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HCD_IS_RUNNING(ehci->hcd.state))
+ return 0;
+
/* init status to no-changes */
buf [0] = 0;
ports = HCS_N_PORTS (ehci->hcs_params);
@@ -246,6 +251,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
status = STS_PCD;
}
}
+ /* FIXME autosuspend idle root hubs */
spin_unlock_irqrestore (&ehci->lock, flags);
return status ? retval : 0;
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index ecb990c84986..31ec1597f49f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -908,6 +908,7 @@ itd_urb_transaction (
if (unlikely (0 == itd)) {
iso_sched_free (stream, sched);
+ spin_unlock_irqrestore (&ehci->lock, flags);
return -ENOMEM;
}
memset (itd, 0, sizeof *itd);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 05e78d954ed5..a4d99857062a 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -109,7 +109,7 @@
#include <asm/byteorder.h>
-#define DRIVER_VERSION "2004 Feb 02"
+#define DRIVER_VERSION "2004 Nov 08"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -657,8 +657,6 @@ retry:
udev = hcd_to_bus (&ohci->hcd)->root_hub;
if (udev) {
- udev->dev.power.power_state = 0;
- usb_set_device_state (udev, USB_STATE_CONFIGURED);
return 0;
}
@@ -799,6 +797,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
int temp;
int i;
struct urb_priv *priv;
+ struct usb_device *root = ohci->hcd.self.root_hub;
/* mark any devices gone, so they do nothing till khubd disconnects.
* recycle any "live" eds/tds (and urbs) right away.
@@ -807,7 +806,11 @@ static int ohci_restart (struct ohci_hcd *ohci)
*/
spin_lock_irq(&ohci->lock);
disable (ohci);
- usb_set_device_state (ohci->hcd.self.root_hub, USB_STATE_NOTATTACHED);
+ for (i = 0; i < root->maxchild; i++) {
+ if (root->children [i])
+ usb_set_device_state (root->children[i],
+ USB_STATE_NOTATTACHED);
+ }
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {
@@ -864,7 +867,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
ohci_writel (ohci, RH_PS_PSS,
&ohci->regs->roothub.portstatus [temp]);
ohci_dbg (ohci, "restart complete\n");
- ohci->hcd.state = USB_STATE_RUNNING;
}
return 0;
}
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 743bc39329f5..d5747e974cfb 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -48,15 +48,10 @@ static int ohci_restart (struct ohci_hcd *ohci);
static int ohci_hub_suspend (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
int status = 0;
+ unsigned long flags;
- if (root->dev.power.power_state != 0)
- return 0;
- if (time_before (jiffies, ohci->next_statechange))
- return -EAGAIN;
-
- spin_lock_irq (&ohci->lock);
+ spin_lock_irqsave (&ohci->lock, flags);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
@@ -72,8 +67,8 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
ohci_dbg (ohci, "needs reinit!\n");
goto done;
case OHCI_USB_SUSPEND:
- ohci_dbg (ohci, "already suspended?\n");
- goto succeed;
+ ohci_dbg (ohci, "already suspended\n");
+ goto done;
}
ohci_dbg (ohci, "suspend root hub\n");
@@ -122,14 +117,10 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
/* no resumes until devices finish suspending */
ohci->next_statechange = jiffies + msecs_to_jiffies (5);
-succeed:
- /* it's not HCD_STATE_SUSPENDED unless access to this
- * hub from the non-usb side (PCI, SOC, etc) stopped
- */
- root->dev.power.power_state = 3;
- usb_set_device_state (root, USB_STATE_SUSPENDED);
done:
- spin_unlock_irq (&ohci->lock);
+ if (status == 0)
+ ohci->hcd.state = HCD_STATE_SUSPENDED;
+ spin_unlock_irqrestore (&ohci->lock, flags);
return status;
}
@@ -145,22 +136,26 @@ static inline struct ed *find_head (struct ed *ed)
static int ohci_hub_resume (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
u32 temp, enables;
int status = -EINPROGRESS;
- if (!root->dev.power.power_state)
- return 0;
if (time_before (jiffies, ohci->next_statechange))
- return -EAGAIN;
+ msleep(5);
spin_lock_irq (&ohci->lock);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
/* this can happen after suspend-to-disk */
- ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
- ohci->hc_control);
- status = -EBUSY;
+ if (hcd->state == USB_STATE_RESUMING) {
+ ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
+ ohci->hc_control);
+ status = -EBUSY;
+ /* this happens when pmcore resumes HC then root */
+ } else {
+ ohci_dbg (ohci, "duplicate resume\n");
+ status = 0;
+ }
} else switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_SUSPEND:
ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
@@ -175,7 +170,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
break;
case OHCI_USB_OPER:
ohci_dbg (ohci, "odd resume\n");
- root->dev.power.power_state = 0;
status = 0;
break;
default: /* RESET, we lost power */
@@ -245,8 +239,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
/* TRSMRCY */
msleep (10);
- root->dev.power.power_state = 0;
- usb_set_device_state (root, USB_STATE_CONFIGURED);
/* keep it alive for ~5x suspend + resume costs */
ohci->next_statechange = jiffies + msecs_to_jiffies (250);
@@ -315,10 +307,12 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
int ports, i, changed = 0, length = 1;
int can_suspend = 1;
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HCD_IS_RUNNING(ohci->hcd.state))
+ return 0;
+
ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) {
- if (!HCD_IS_RUNNING(ohci->hcd.state))
- return -ESHUTDOWN;
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */
@@ -362,6 +356,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
#ifdef CONFIG_PM
/* save power by suspending idle root hubs;
* INTR_RD wakes us when there's work
+ * NOTE: if we can do this, we don't need a root hub timer!
*/
if (can_suspend
&& !changed
@@ -369,6 +364,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
& ohci->hc_control)
== OHCI_USB_OPER
+ && time_after (jiffies, ohci->next_statechange)
&& usb_trylock_device (hcd->self.root_hub)
) {
ohci_vdbg (ohci, "autosuspend\n");
@@ -409,7 +405,7 @@ ohci_hub_descriptor (
temp |= 0x0010;
else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
temp |= 0x0008;
- desc->wHubCharacteristics = cpu_to_hc16 (ohci, temp);
+ desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp);
/* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
rh = roothub_b (ohci);
@@ -475,7 +471,7 @@ static void start_hnp(struct ohci_hcd *ohci);
/* called from some task, normally khubd */
static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
- u32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
+ __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
u32 temp;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 4b78c9570306..debe1034fd49 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -106,7 +106,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
/* suspend root hub, hoping it keeps power during suspend */
- while (time_before (jiffies, ohci->next_statechange))
+ if (time_before (jiffies, ohci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
@@ -154,7 +154,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#endif
/* resume root hub */
- while (time_before (jiffies, ohci->next_statechange))
+ if (time_before (jiffies, ohci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
/* get extra cleanup even if remote wakeup isn't in use */
@@ -166,7 +166,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#endif
if (retval == 0) {
- hcd->self.controller->power.power_state = 0;
#ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac)
enable_irq (to_pci_dev(hcd->self.controller)->irq);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 3b7f7d342e95..9c384302523a 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -510,7 +510,7 @@ static inline void ohci_writel (const struct ohci_hcd *ohci,
/* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
{
- return big_endian(ohci) ? cpu_to_be16(x) : cpu_to_le16(x);
+ return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
}
static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
@@ -520,7 +520,7 @@ static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
{
- return big_endian(ohci) ? cpu_to_be32(x) : cpu_to_le32(x);
+ return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
}
static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
@@ -531,22 +531,22 @@ static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
/* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
{
- return big_endian(ohci) ? be16_to_cpu(x) : le16_to_cpu(x);
+ return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
}
static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
{
- return big_endian(ohci) ? be16_to_cpup(x) : le16_to_cpup(x);
+ return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
}
static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
{
- return big_endian(ohci) ? be32_to_cpu(x) : le32_to_cpu(x);
+ return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
{
- return big_endian(ohci) ? be32_to_cpup(x) : le32_to_cpup(x);
+ return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index a682dfc2f747..a58ff2e9efa3 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -27,6 +27,7 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <linux/time.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/param.h>
@@ -45,7 +46,8 @@
#define SN9C102_URBS 2
#define SN9C102_ISO_PACKETS 7
#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_CTRL_TIMEOUT 10*HZ
+#define SN9C102_URB_TIMEOUT msecs_to_jiffies(3)
+#define SN9C102_CTRL_TIMEOUT msecs_to_jiffies(100)
/*****************************************************************************/
@@ -53,8 +55,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.12"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 12)
+#define SN9C102_MODULE_VERSION "1:1.19"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 19)
enum sn9c102_bridge {
BRIDGE_SN9C101 = 0x01,
@@ -100,7 +102,7 @@ enum sn9c102_stream_state {
};
struct sn9c102_sysfs_attr {
- u8 reg, val, i2c_reg, i2c_val;
+ u8 reg, i2c_reg;
};
static DECLARE_MUTEX(sn9c102_sysfs_lock);
@@ -121,11 +123,13 @@ struct sn9c102_device {
struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
struct list_head inqueue, outqueue;
- u32 frame_count, nbuffers;
+ u32 frame_count, nbuffers, nreadbuffers;
enum sn9c102_io_method io;
enum sn9c102_stream_state stream;
+ struct v4l2_jpegcompression compression;
+
struct sn9c102_sysfs_attr sysfs;
u16 reg[32];
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index dee36973f0b6..e4c44fa873f4 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -28,7 +28,6 @@
#include <linux/string.h>
#include <linux/device.h>
#include <linux/fs.h>
-#include <linux/time.h>
#include <linux/delay.h>
#include <linux/stddef.h>
#include <linux/compiler.h>
@@ -100,6 +99,7 @@ static sn9c102_eof_header_t sn9c102_eof_header[] = {
};
/*****************************************************************************/
+
static void* rvmalloc(size_t size)
{
void* mem;
@@ -424,7 +424,8 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
/*****************************************************************************/
-static void* sn9c102_find_sof_header(void* mem, size_t len)
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
size_t soflen = sizeof(sn9c102_sof_header_t), i;
u8 j, n = sizeof(sn9c102_sof_header) / soflen;
@@ -440,11 +441,15 @@ static void* sn9c102_find_sof_header(void* mem, size_t len)
}
-static void* sn9c102_find_eof_header(void* mem, size_t len)
+static void*
+sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
size_t eoflen = sizeof(sn9c102_eof_header_t), i;
unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+ if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ return NULL; /* EOF header does not exist in compressed data */
+
for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
for (j = 0; j < n; j++)
if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
@@ -509,9 +514,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
*/
redo:
- sof = sn9c102_find_sof_header(pos, len);
+ sof = sn9c102_find_sof_header(cam, pos, len);
if (!sof) {
- eof = sn9c102_find_eof_header(pos, len);
+ eof = sn9c102_find_eof_header(cam, pos, len);
if ((*f)->state == F_GRABBING) {
end_of_frame:
img = len;
@@ -539,7 +544,9 @@ end_of_frame:
(*f)->buf.bytesused += img;
- if ((*f)->buf.bytesused == (*f)->buf.length) {
+ if ((*f)->buf.bytesused == (*f)->buf.length ||
+ (cam->sensor->pix_format.pixelformat ==
+ V4L2_PIX_FMT_SN9C10X && eof)) {
u32 b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
(*f)->buf.sequence= ++cam->frame_count;
@@ -592,14 +599,20 @@ start_of_frame:
goto redo;
} else if ((*f)->state == F_GRABBING) {
- eof = sn9c102_find_eof_header(pos, len);
+ eof = sn9c102_find_eof_header(cam, pos, len);
if (eof && eof < sof)
goto end_of_frame; /* (1) */
else {
- DBG(3, "SOF before expected EOF after %lu "
- "bytes of image data",
- (unsigned long)((*f)->buf.bytesused))
- goto start_of_frame;
+ if (cam->sensor->pix_format.pixelformat ==
+ V4L2_PIX_FMT_SN9C10X) {
+ eof = sof-sizeof(sn9c102_sof_header_t);
+ goto end_of_frame;
+ } else {
+ DBG(3, "SOF before expected EOF after "
+ "%lu bytes of image data",
+ (unsigned long)((*f)->buf.bytesused))
+ goto start_of_frame;
+ }
}
}
}
@@ -723,6 +736,29 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
return err;
}
+
+int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ cam->stream = STREAM_INTERRUPT;
+ err = wait_event_timeout(cam->wait_stream,
+ (cam->stream == STREAM_OFF) ||
+ (cam->state & DEV_DISCONNECTED),
+ SN9C102_URB_TIMEOUT);
+ if (err) {
+ cam->state |= DEV_MISCONFIGURED;
+ DBG(1, "The camera is misconfigured. To use "
+ "it, close and open /dev/video%d "
+ "again.", cam->v4ldev->minor)
+ return err;
+ }
+ if (cam->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ return 0;
+}
+
/*****************************************************************************/
static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
@@ -1127,6 +1163,35 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
/*****************************************************************************/
+static int
+sn9c102_set_format(struct sn9c102_device* cam, struct v4l2_pix_format* fmt)
+{
+ int err = 0;
+
+ if (fmt->pixelformat == V4L2_PIX_FMT_SN9C10X)
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
+ else
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+
+ return err ? -EIO : 0;
+}
+
+
+static int
+sn9c102_set_compression(struct sn9c102_device* cam,
+ struct v4l2_jpegcompression* compression)
+{
+ int err = 0;
+
+ if (compression->quality == 0)
+ err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+ else if (compression->quality == 1)
+ err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+
+ return err ? -EIO : 0;
+}
+
+
static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
{
u8 r = 0;
@@ -1204,6 +1269,20 @@ static int sn9c102_init(struct sn9c102_device* cam)
}
}
+ if (!(cam->state & DEV_INITIALIZED))
+ cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1;
+ else
+ err += sn9c102_set_compression(cam, &cam->compression);
+ err += sn9c102_set_format(cam, &s->pix_format);
+ if (err)
+ return err;
+
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ DBG(3, "Compressed video format is active, quality %d",
+ cam->compression.quality)
+ else
+ DBG(3, "Uncompressed video format is active")
+
if (s->set_crop)
if ((err = s->set_crop(cam, rect))) {
DBG(3, "set_crop() failed")
@@ -1219,9 +1298,12 @@ static int sn9c102_init(struct sn9c102_device* cam)
ctrl.value = qctrl[i].default_value;
err = s->set_ctrl(cam, &ctrl);
if (err) {
- DBG(3, "Set control failed")
+ DBG(3, "Set %s control failed",
+ s->qctrl[i].name)
return err;
}
+ DBG(3, "Image sensor supports '%s' control",
+ s->qctrl[i].name)
}
}
@@ -1230,6 +1312,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
spin_lock_init(&cam->queue_lock);
init_waitqueue_head(&cam->wait_frame);
init_waitqueue_head(&cam->wait_stream);
+ cam->nreadbuffers = 2;
memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
memcpy(&(s->_rect), &(s->cropcap.defrect),
sizeof(struct v4l2_rect));
@@ -1387,7 +1470,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
}
if (cam->io == IO_NONE) {
- if (!sn9c102_request_buffers(cam, 2)) {
+ if (!sn9c102_request_buffers(cam, cam->nreadbuffers)) {
DBG(1, "read() failed, not enough memory")
up(&cam->fileop_sem);
return -ENOMEM;
@@ -1431,8 +1514,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
sn9c102_queue_unusedframes(cam);
- if (count > f->buf.length)
- count = f->buf.length;
+ if (count > f->buf.bytesused)
+ count = f->buf.bytesused;
if (copy_to_user(buf, f->bufmem, count)) {
up(&cam->fileop_sem);
@@ -1553,11 +1636,15 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
return -EINVAL;
}
+ /* VM_IO is eventually going to replace PageReserved altogether */
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
pos = (unsigned long)cam->frame[i].bufmem;
while (size > 0) { /* size is page-aligned */
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE,
- vma->vm_page_prot)) {
+ vma->vm_page_prot)) {
up(&cam->fileop_sem);
return -EAGAIN;
}
@@ -1567,8 +1654,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
}
vma->vm_ops = &sn9c102_vm_ops;
- vma->vm_flags &= ~VM_IO; /* not I/O memory */
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
vma->vm_private_data = &cam->frame[i];
sn9c102_vm_open(vma);
@@ -1593,11 +1678,14 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
.version = SN9C102_MODULE_VERSION_CODE,
.capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
+ V4L2_CAP_STREAMING,
};
strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
- strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));
+ if (usb_make_path(cam->usbdev, cap.bus_info,
+ sizeof(cap.bus_info)) < 0)
+ strlcpy(cap.bus_info, cam->dev.bus_id,
+ sizeof(cap.bus_info));
if (copy_to_user(arg, &cap, sizeof(cap)))
return -EFAULT;
@@ -1707,6 +1795,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
s->_qctrl[i].default_value = ctrl.value;
+ PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+ (unsigned long)ctrl.id, (unsigned long)ctrl.value)
+
return 0;
}
@@ -1803,22 +1894,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
} else
scale = 1;
- if (cam->stream == STREAM_ON) {
- cam->stream = STREAM_INTERRUPT;
- err = wait_event_interruptible
- ( cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED) );
- if (err) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "The camera is misconfigured. To use "
- "it, close and open /dev/video%d "
- "again.", cam->v4ldev->minor)
+ if (cam->stream == STREAM_ON)
+ if ((err = sn9c102_stream_interrupt(cam)))
return err;
- }
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
if (copy_to_user(arg, &crop, sizeof(crop))) {
cam->stream = stream;
@@ -1859,20 +1937,23 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
case VIDIOC_ENUM_FMT:
{
- struct sn9c102_sensor* s = cam->sensor;
struct v4l2_fmtdesc fmtd;
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
- if (fmtd.index != 0)
+ if (fmtd.index == 0) {
+ strcpy(fmtd.description, "bayer rgb");
+ fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ } else if (fmtd.index == 1) {
+ strcpy(fmtd.description, "compressed");
+ fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+ fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+ } else
return -EINVAL;
- memset(&fmtd, 0, sizeof(fmtd));
-
fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmtd.description, "bayer rgb");
- fmtd.pixelformat = s->pix_format.pixelformat;
+ memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
return -EFAULT;
@@ -1891,8 +1972,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- pfmt->bytesperline = (pfmt->width * pfmt->priv) / 8;
- pfmt->sizeimage = pfmt->height * pfmt->bytesperline;
+ pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+ ? 0 : (pfmt->width * pfmt->priv) / 8;
+ pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
pfmt->field = V4L2_FIELD_NONE;
memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
@@ -1961,15 +2043,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
pix->width = rect.width / scale;
pix->height = rect.height / scale;
- pix->pixelformat = pfmt->pixelformat;
+ if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+ pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+ pix->pixelformat = pfmt->pixelformat;
pix->priv = pfmt->priv; /* bpp */
pix->colorspace = pfmt->colorspace;
- pix->bytesperline = (pix->width * pix->priv) / 8;
- pix->sizeimage = pix->height * pix->bytesperline;
+ pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+ ? 0 : (pix->width * pix->priv) / 8;
+ pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
pix->field = V4L2_FIELD_NONE;
- if (cmd == VIDIOC_TRY_FMT)
+ if (cmd == VIDIOC_TRY_FMT) {
+ if (copy_to_user(arg, &format, sizeof(format)))
+ return -EFAULT;
return 0;
+ }
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
@@ -1978,22 +2066,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return -EINVAL;
}
- if (cam->stream == STREAM_ON) {
- cam->stream = STREAM_INTERRUPT;
- err = wait_event_interruptible
- ( cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED) );
- if (err) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "The camera is misconfigured. To use "
- "it, close and open /dev/video%d "
- "again.", cam->v4ldev->minor)
+ if (cam->stream == STREAM_ON)
+ if ((err = sn9c102_stream_interrupt(cam)))
return err;
- }
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
if (copy_to_user(arg, &format, sizeof(format))) {
cam->stream = stream;
@@ -2002,7 +2077,8 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
sn9c102_release_buffers(cam);
- err = sn9c102_set_crop(cam, &rect);
+ err += sn9c102_set_format(cam, pix);
+ err += sn9c102_set_crop(cam, &rect);
if (s->set_crop)
err += s->set_crop(cam, &rect);
err += sn9c102_set_scale(cam, scale);
@@ -2031,6 +2107,47 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return 0;
}
+ case VIDIOC_G_JPEGCOMP:
+ {
+ if (copy_to_user(arg, &cam->compression,
+ sizeof(cam->compression)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression jc;
+ const enum sn9c102_stream_state stream = cam->stream;
+ int err = 0;
+
+ if (copy_from_user(&jc, arg, sizeof(jc)))
+ return -EFAULT;
+
+ if (jc.quality != 0 && jc.quality != 1)
+ return -EINVAL;
+
+ if (cam->stream == STREAM_ON)
+ if ((err = sn9c102_stream_interrupt(cam)))
+ return err;
+
+ err += sn9c102_set_compression(cam, &jc);
+ if (err) { /* atomic, no rollback in ioctl() */
+ cam->state |= DEV_MISCONFIGURED;
+ DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+ "problems. To use the camera, close and open "
+ "/dev/video%d again.", cam->v4ldev->minor)
+ return -EIO;
+ }
+
+ cam->compression.quality = jc.quality;
+
+ cam->stream = stream;
+
+ return 0;
+ }
+
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers rb;
@@ -2057,22 +2174,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return -EINVAL;
}
- if (cam->stream == STREAM_ON) {
- cam->stream = STREAM_INTERRUPT;
- err = wait_event_interruptible
- ( cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED) );
- if (err) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "The camera is misconfigured. To use "
- "it, close and open /dev/video%d "
- "again.", cam->v4ldev->minor)
+ if (cam->stream == STREAM_ON)
+ if ((err = sn9c102_stream_interrupt(cam)))
return err;
- }
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
sn9c102_empty_framequeues(cam);
@@ -2222,22 +2326,9 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (cam->stream == STREAM_ON) {
- cam->stream = STREAM_INTERRUPT;
- err = wait_event_interruptible
- ( cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED) );
- if (err) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "The camera is misconfigured. To use "
- "it, close and open /dev/video%d "
- "again.", cam->v4ldev->minor)
+ if (cam->stream == STREAM_ON)
+ if ((err = sn9c102_stream_interrupt(cam)))
return err;
- }
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
sn9c102_empty_framequeues(cam);
@@ -2246,13 +2337,56 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return 0;
}
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm sp;
+
+ if (copy_from_user(&sp, arg, sizeof(sp)))
+ return -EFAULT;
+
+ if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ sp.parm.capture.extendedmode = 0;
+ sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+ if (copy_to_user(arg, &sp, sizeof(sp)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm sp;
+
+ if (copy_from_user(&sp, arg, sizeof(sp)))
+ return -EFAULT;
+
+ if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ sp.parm.capture.extendedmode = 0;
+
+ if (sp.parm.capture.readbuffers == 0)
+ sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+ if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+ sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+
+ if (copy_to_user(arg, &sp, sizeof(sp)))
+ return -EFAULT;
+
+ cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+ return 0;
+ }
+
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
- case VIDIOC_G_PARM:
- case VIDIOC_S_PARM:
return -EINVAL;
default:
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c
index 8453409ea125..54942d607a93 100644
--- a/drivers/usb/media/sn9c102_pas106b.c
+++ b/drivers/usb/media/sn9c102_pas106b.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Driver for PAS106B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -38,14 +38,9 @@ static int pas106b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x09, 0x18);
err += sn9c102_i2c_write(cam, 0x02, 0x0c);
- err += sn9c102_i2c_write(cam, 0x03, 0x12);
- err += sn9c102_i2c_write(cam, 0x04, 0x05);
err += sn9c102_i2c_write(cam, 0x05, 0x5a);
err += sn9c102_i2c_write(cam, 0x06, 0x88);
err += sn9c102_i2c_write(cam, 0x07, 0x80);
- err += sn9c102_i2c_write(cam, 0x08, 0x01);
- err += sn9c102_i2c_write(cam, 0x0a, 0x01);
- err += sn9c102_i2c_write(cam, 0x0b, 0x00);
err += sn9c102_i2c_write(cam, 0x10, 0x06);
err += sn9c102_i2c_write(cam, 0x11, 0x06);
err += sn9c102_i2c_write(cam, 0x12, 0x00);
@@ -62,6 +57,15 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ {
+ int r1 = sn9c102_i2c_read(cam, 0x03),
+ r2 = sn9c102_i2c_read(cam, 0x04);
+ if (r1 < 0 || r2 < 0)
+ return -EIO;
+ ctrl->value = (r1 << 4) | (r2 & 0x0f);
+ }
+ return 0;
case V4L2_CID_RED_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
return -EIO;
@@ -77,16 +81,26 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
return -EIO;
ctrl->value &= 0x1f;
return 0;
- case V4L2_CID_BRIGHTNESS:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
case V4L2_CID_CONTRAST:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
return -EIO;
ctrl->value &= 0x07;
return 0;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x1f) << 1;
+ return 0;
+ case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+ return -EIO;
+ ctrl->value &= 0xf8;
+ return 0;
+ case SN9C102_V4L2_CID_DAC_SIGN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ return 0;
default:
return -EINVAL;
}
@@ -99,6 +113,10 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
int err = 0;
switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
+ err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
+ break;
case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
break;
@@ -108,12 +126,23 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
break;
- case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x0d, 0x1f - ctrl->value);
- break;
case V4L2_CID_CONTRAST:
err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
+ err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
+ break;
+ case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+ err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
+ break;
+ case SN9C102_V4L2_CID_DAC_SIGN:
+ {
+ int r;
+ err += (r = sn9c102_i2c_read(cam, 0x07)) < 0 ? r : 0;
+ err += sn9c102_i2c_write(cam, 0x07, r | ctrl->value);
+ }
+ break;
default:
return -EINVAL;
}
@@ -148,6 +177,36 @@ static struct sn9c102_sensor pas106b = {
.init = &pas106b_init,
.qctrl = {
{
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x125,
+ .maximum = 0xfff,
+ .step = 0x01,
+ .default_value = 0x140,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "global gain",
+ .minimum = 0x00,
+ .maximum = 0x1f,
+ .step = 0x01,
+ .default_value = 0x0d,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "contrast",
+ .minimum = 0x00,
+ .maximum = 0x07,
+ .step = 0x01,
+ .default_value = 0x00, /* 0x00~0x03 have same effect */
+ .flags = 0,
+ },
+ {
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
@@ -168,33 +227,33 @@ static struct sn9c102_sensor pas106b = {
.flags = 0,
},
{
- .id = V4L2_CID_GAIN,
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
+ .name = "green balance",
.minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0d,
+ .maximum = 0x3e,
+ .step = 0x02,
+ .default_value = 0x02,
.flags = 0,
},
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
+ .name = "DAC magnitude",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
- .default_value = 0x1f,
+ .default_value = 0x01,
.flags = 0,
},
{
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "contrast",
+ .id = SN9C102_V4L2_CID_DAC_SIGN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "DAC sign",
.minimum = 0x00,
- .maximum = 0x07,
+ .maximum = 0x01,
.step = 0x01,
- .default_value = 0x00, /* 0x00~0x03 have same effect */
+ .default_value = 0x00,
.flags = 0,
},
},
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
index 72063e885871..3e2fd5a6f281 100644
--- a/drivers/usb/media/sn9c102_pas202bcb.c
+++ b/drivers/usb/media/sn9c102_pas202bcb.c
@@ -1,11 +1,14 @@
/***************************************************************************
- * Driver for PAS202BCB image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ *
* *
+ * DAC Magnitude, DAC sign, exposure and green gain controls added by *
+ * Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
@@ -41,14 +44,10 @@ static int pas202bcb_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x02, 0x14);
err += sn9c102_i2c_write(cam, 0x03, 0x40);
- err += sn9c102_i2c_write(cam, 0x04, 0x07);
- err += sn9c102_i2c_write(cam, 0x05, 0x25);
err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
err += sn9c102_i2c_write(cam, 0x0e, 0x01);
err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
err += sn9c102_i2c_write(cam, 0x10, 0x08);
- err += sn9c102_i2c_write(cam, 0x0b, 0x01);
- err += sn9c102_i2c_write(cam, 0x0c, 0x04);
err += sn9c102_i2c_write(cam, 0x13, 0x63);
err += sn9c102_i2c_write(cam, 0x15, 0x70);
err += sn9c102_i2c_write(cam, 0x11, 0x01);
@@ -63,6 +62,15 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ {
+ int r1 = sn9c102_i2c_read(cam, 0x04),
+ r2 = sn9c102_i2c_read(cam, 0x05);
+ if (r1 < 0 || r2 < 0)
+ return -EIO;
+ ctrl->value = (r1 << 6) | (r2 & 0x3f);
+ }
+ return 0;
case V4L2_CID_RED_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
return -EIO;
@@ -78,11 +86,20 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
return -EIO;
ctrl->value &= 0x1f;
return 0;
- case V4L2_CID_BRIGHTNESS:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0)
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
+ case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ return -EIO;
+ return 0;
+ case SN9C102_V4L2_CID_DAC_SIGN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0b)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ return 0;
default:
return -EINVAL;
}
@@ -95,6 +112,10 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
int err = 0;
switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+ err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+ break;
case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
break;
@@ -104,8 +125,18 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
- case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x06, 0x0f - ctrl->value);
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+ break;
+ case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+ err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+ break;
+ case SN9C102_V4L2_CID_DAC_SIGN:
+ {
+ int r;
+ err += (r = sn9c102_i2c_read(cam, 0x0b)) < 0 ? r : 0;
+ err += sn9c102_i2c_write(cam, 0x0b, r | ctrl->value);
+ }
break;
default:
return -EINVAL;
@@ -142,6 +173,26 @@ static struct sn9c102_sensor pas202bcb = {
.init = &pas202bcb_init,
.qctrl = {
{
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x01e5,
+ .maximum = 0x3fff,
+ .step = 0x01,
+ .default_value = 0x01e5,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "global gain",
+ .minimum = 0x00,
+ .maximum = 0x1f,
+ .step = 0x01,
+ .default_value = 0x0c,
+ .flags = 0,
+ },
+ {
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
@@ -162,23 +213,33 @@ static struct sn9c102_sensor pas202bcb = {
.flags = 0,
},
{
- .id = V4L2_CID_GAIN,
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
+ .name = "green balance",
.minimum = 0x00,
- .maximum = 0x1f,
+ .maximum = 0x0f,
.step = 0x01,
- .default_value = 0x0c,
+ .default_value = 0x00,
.flags = 0,
},
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
+ .name = "DAC magnitude",
.minimum = 0x00,
- .maximum = 0x0f,
+ .maximum = 0xff,
.step = 0x01,
- .default_value = 0x0f,
+ .default_value = 0x04,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_DAC_SIGN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "DAC sign",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x01,
.flags = 0,
},
},
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
index 01bcad14ca6d..ebafc280911d 100644
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -98,7 +98,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \
{ USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
{ USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
{ USB_DEVICE(0x0c45, 0x602a), }, /* HV7131[D|E1] */ \
- { USB_DEVICE(0x0c45, 0x602b), }, \
+ { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
{ USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \
{ USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
{ USB_DEVICE(0x0c45, 0x6080), }, \
@@ -292,21 +292,25 @@ struct sn9c102_sensor {
NOTE: in case, you must program the SN9C10X chip to get rid of
blank pixels or blank lines at the _start_ of each line or
frame after each HSYNC or VSYNC, so that the image starts with
- real RGB data (see regs 0x12,0x13) (having set H_SIZE and,
+ real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
V_SIZE you don't have to care about blank pixels or blank
lines at the end of each line or frame).
*/
struct v4l2_pix_format pix_format;
/*
- What you have to define here are: initial 'width' and 'height' of
- the target rectangle, the bayer 'pixelformat' and 'priv' which we'll
- be used to indicate the number of bits per pixel, 8 or 9.
- Nothing more.
+ What you have to define here are: 1) initial 'width' and 'height' of
+ the target rectangle 2) the initial 'pixelformat', which can be
+ either V4L2_PIX_FMT_SN9C10X (for compressed video) or
+ V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
+ number of bits per pixel for uncompressed video, 8 or 9 (despite the
+ current value of 'pixelformat').
NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
of cropcap.defrect.width and cropcap.defrect.height. I
suggest 1/1.
- NOTE 2: as said above, you have to program the SN9C10X chip to get
+ NOTE 2: The initial compression quality is defined by the first bit
+ of reg 0x17 during the initialization of the image sensor.
+ NOTE 3: as said above, you have to program the SN9C10X chip to get
rid of any blank pixels, so that the output of the sensor
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
*/
@@ -333,4 +337,11 @@ struct sn9c102_sensor {
struct v4l2_rect _rect;
};
+/*****************************************************************************/
+
+/* Private ioctl's for control settings supported by some image sensors */
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define SN9C102_V4L2_CID_DAC_SIGN V4L2_CID_PRIVATE_BASE + 1
+#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 2
+
#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
index ce8b47b59a75..03153cae2db3 100644
--- a/drivers/usb/media/sn9c102_tas5110c1b.c
+++ b/drivers/usb/media/sn9c102_tas5110c1b.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Driver for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -150,7 +150,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5110c1b);
- /* At the moment, sensor detection is based on USB pid/vid */
+ /* Sensor detection is based on USB pid/vid */
if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 &&
tas5110c1b.usbdev->descriptor.idProduct != 0x6005 &&
tas5110c1b.usbdev->descriptor.idProduct != 0x60ab)
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
index 0048e9c20d80..36b00d12a6e5 100644
--- a/drivers/usb/media/sn9c102_tas5130d1b.c
+++ b/drivers/usb/media/sn9c102_tas5130d1b.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Driver for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -96,8 +96,8 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam,
err += sn9c102_write_reg(cam, v_start, 0x13);
/* Do NOT change! */
- err += sn9c102_write_reg(cam, 0x1d, 0x1a);
- err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x1f, 0x1a);
+ err += sn9c102_write_reg(cam, 0x1a, 0x1b);
err += sn9c102_write_reg(cam, 0xf3, 0x19);
return err;
@@ -165,7 +165,7 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5130d1b);
- /* At the moment, sensor detection is based on USB pid/vid */
+ /* Sensor detection is based on USB pid/vid */
if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025 &&
tas5130d1b.usbdev->descriptor.idProduct != 0x60aa)
return -ENODEV;
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index e90a334f7287..6a6e3de91a0a 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -170,13 +170,11 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d",
- le32_to_cpu(result));
+ err("Error executing ioctrl. code = %d", result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d (data=%04x)",
- le32_to_cpu(result),
- le32_to_cpu(*((long *) buffer)));
+ dbg("Executed ioctl. Result = %d (data=%02x)",
+ result, buffer[0]);
if (copy_to_user(rio_cmd.buffer, buffer,
rio_cmd.length)) {
free_page((unsigned long) buffer);
@@ -239,12 +237,10 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d",
- le32_to_cpu(result));
+ err("Error executing ioctrl. code = %d", result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d",
- le32_to_cpu(result));
+ dbg("Executed ioctl. Result = %d", result);
retries = 0;
}
diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
index e6e9caa1243d..4a5d2b002190 100644
--- a/drivers/usb/misc/tiglusb.c
+++ b/drivers/usb/misc/tiglusb.c
@@ -310,11 +310,11 @@ tiglusb_ioctl (struct inode *inode, struct file *filp,
ret = -EIO;
break;
case IOCTL_TIUSB_GET_MAXPS:
- if (copy_to_user((int *) arg, &s->max_ps, sizeof(int)))
+ if (copy_to_user((int __user *) arg, &s->max_ps, sizeof(int)))
return -EFAULT;
break;
case IOCTL_TIUSB_GET_DEVID:
- if (copy_to_user((int *) arg, &s->dev->descriptor.idProduct,
+ if (copy_to_user((int __user *) arg, &s->dev->descriptor.idProduct,
sizeof(int)))
return -EFAULT;
break;
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index a03b8d44a782..d630edfacad5 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1355,7 +1355,7 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs)
"iso test, %lu errors\n",
ctx->errors);
complete (&ctx->done);
- } else
+ }
done:
spin_unlock(&ctx->lock);
}
@@ -1457,8 +1457,10 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
status = usb_submit_urb (urbs [i], SLAB_ATOMIC);
if (status < 0) {
ERROR (dev, "submit iso[%d], error %d\n", i, status);
- if (i == 0)
+ if (i == 0) {
+ spin_unlock_irq (&context.lock);
goto fail;
+ }
simple_free_urb (urbs [i]);
context.pending--;
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index dd1af41784df..d64409e85472 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -1,15 +1,15 @@
#
# USB Network devices configuration
#
-comment "USB Network adaptors"
- depends on USB
-
-comment "Networking support is needed for USB Networking device support"
+comment "Networking support is needed for USB Network Adapter support"
depends on USB && !NET
+menu "USB Network Adapters"
+ depends on USB && NET
+
config USB_CATC
tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
- depends on USB && NET && EXPERIMENTAL
+ depends on EXPERIMENTAL
select CRC32
---help---
Say Y if you want to use one of the following 10Mbps USB Ethernet
@@ -29,7 +29,6 @@ config USB_CATC
config USB_KAWETH
tristate "USB KLSI KL5USB101-based ethernet device support"
- depends on USB && NET
---help---
Say Y here if you want to use one of the following 10Mbps only
USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
@@ -69,7 +68,6 @@ config USB_KAWETH
config USB_PEGASUS
tristate "USB Pegasus/Pegasus-II based ethernet device support"
- depends on USB && NET
select MII
---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter.
@@ -85,7 +83,7 @@ config USB_PEGASUS
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
- depends on USB && NET && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
Send me <petkan@users.sourceforge.net> any comments you may have.
@@ -96,7 +94,6 @@ config USB_RTL8150
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
- depends on USB && NET
---help---
This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core
@@ -206,6 +203,9 @@ config USB_ARMLINUX
such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities
in some PXA versions of the "blob" boot loader.
+ Linux-based "Gumstix" PXA-25x based systems use this protocol
+ to talk with other Linux systems.
+
Although the ROMs shipped with Sharp Zaurus products use a
different link level framing protocol, you can have them use
this simpler protocol by installing a different kernel.
@@ -266,17 +266,20 @@ config USB_AX8817X
select MII
default y
help
-
This option adds support for ASIX AX88172 based USB 2.0
10/100 Ethernet devices.
This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
+ * Billionton Systems, USB2AR
+ * Buffalo LUA-U2-KTX
+ * Corega FEther USB2-TX
* D-Link DUB-E100
* Hawking UF200
* Linksys USB200M
* Netgear FA120
+ * Sitecom LN-029
* Intellinet USB 2.0 Ethernet
* ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100
@@ -284,4 +287,4 @@ config USB_AX8817X
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
-
+endmenu
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 34c70c1a4f5a..57d4c2164425 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -23,6 +23,10 @@
* Edgeport/4D8
* Edgeport/8i
*
+ * For questions or problems with this driver, contact Inside Out
+ * Networks technical support, or Peter Berger <pberger@brimson.com>,
+ * or Al Borchers <alborchers@steinerpoint.com>.
+ *
* Version history:
*
* 2003_04_03 al borchers
@@ -267,7 +271,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v2.7"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -297,8 +301,6 @@
#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */
-static int debug;
-
/* receive port state */
enum RXSTATE {
EXPECT_HDR1 = 0, /* Expect header byte 1 */
@@ -329,6 +331,7 @@ struct edgeport_port {
struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */
struct urb *write_urb; /* write URB for this port */
char write_in_progress; /* TRUE while a write URB is outstanding */
+ spinlock_t ep_lock;
__u8 shadowLCR; /* last LCR value received */
__u8 shadowMCR; /* last MCR value received */
@@ -370,6 +373,8 @@ struct edgeport_serial {
__u8 bulk_in_endpoint; /* the bulk in endpoint handle */
unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
struct urb * read_urb; /* our bulk read urb */
+ int read_in_progress;
+ spinlock_t es_lock;
__u8 bulk_out_endpoint; /* the bulk out endpoint handle */
@@ -420,7 +425,11 @@ static struct divisor_table_entry divisor_table[] = {
};
/* local variables */
-static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */
+static int debug;
+
+static int low_latency = 1; /* tty low latency flag, on by default */
+
+static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */
/* local function prototypes */
@@ -459,8 +468,9 @@ static struct usb_driver io_driver = {
};
/* function prototypes for all of our local functions */
-static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
+static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
+static void edge_tty_recv (struct device *dev, struct tty_struct *tty, unsigned char *data, int length);
static void handle_new_msr (struct edgeport_port *edge_port, __u8 newMsr);
static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data);
static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param);
@@ -478,13 +488,9 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial);
static void get_boot_desc (struct edgeport_serial *edge_serial);
static void load_application_firmware (struct edgeport_serial *edge_serial);
-
static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size);
-
-
-
// ************************************************************************
// ************************************************************************
// ************************************************************************
@@ -784,20 +790,24 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
if (length > 1) {
bytes_avail = data[0] | (data[1] << 8);
if (bytes_avail) {
+ spin_lock(&edge_serial->es_lock);
edge_serial->rxBytesAvail += bytes_avail;
- dbg("%s - bytes_avail = %d, rxBytesAvail %d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail);
+ dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);
- if ((edge_serial->rxBytesAvail > 0) &&
- (edge_serial->read_urb->status != -EINPROGRESS)) {
- dbg(" --- Posting a read");
+ if (edge_serial->rxBytesAvail > 0 &&
+ !edge_serial->read_in_progress) {
+ dbg("%s - posting a read", __FUNCTION__);
+ edge_serial->read_in_progress = TRUE;
/* we have pending bytes on the bulk in pipe, send a request */
edge_serial->read_urb->dev = edge_serial->serial->dev;
result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
if (result) {
- dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result);
+ dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result);
+ edge_serial->read_in_progress = FALSE;
}
}
+ spin_unlock(&edge_serial->es_lock);
}
}
/* grab the txcredits for the ports if available */
@@ -809,12 +819,14 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
port = edge_serial->serial->port[portNumber];
edge_port = usb_get_serial_port_data(port);
if (edge_port->open) {
+ spin_lock(&edge_port->ep_lock);
edge_port->txCredits += txCredits;
+ spin_unlock(&edge_port->ep_lock);
dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits);
/* tell the tty driver that something has changed */
if (edge_port->port->tty)
- wake_up_interruptible(&edge_port->port->tty->write_wait);
+ tty_wakeup(edge_port->port->tty);
// Since we have more credit, check if more data can be sent
send_more_port_data(edge_serial, edge_port);
@@ -849,34 +861,43 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ edge_serial->read_in_progress = FALSE;
return;
}
- if (urb->actual_length) {
- raw_data_length = urb->actual_length;
+ if (urb->actual_length == 0) {
+ dbg("%s - read bulk callback with no data", __FUNCTION__);
+ edge_serial->read_in_progress = FALSE;
+ return;
+ }
- usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data);
+ raw_data_length = urb->actual_length;
- /* decrement our rxBytes available by the number that we just got */
- edge_serial->rxBytesAvail -= raw_data_length;
+ usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data);
- dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
+ spin_lock(&edge_serial->es_lock);
- process_rcvd_data (edge_serial, data, urb->actual_length);
+ /* decrement our rxBytes available by the number that we just got */
+ edge_serial->rxBytesAvail -= raw_data_length;
- /* check to see if there's any more data for us to read */
- if ((edge_serial->rxBytesAvail > 0) &&
- (edge_serial->read_urb->status != -EINPROGRESS)) {
- dbg(" --- Posting a read");
+ dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
- /* there is, so resubmit our urb */
- edge_serial->read_urb->dev = edge_serial->serial->dev;
- status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
- if (status) {
- dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
- }
+ process_rcvd_data (edge_serial, data, urb->actual_length);
+
+ /* check to see if there's any more data for us to read */
+ if (edge_serial->rxBytesAvail > 0) {
+ dbg("%s - posting a read", __FUNCTION__);
+ edge_serial->read_urb->dev = edge_serial->serial->dev;
+ status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
+ edge_serial->read_in_progress = FALSE;
}
+ } else {
+ edge_serial->read_in_progress = FALSE;
}
+
+ spin_unlock(&edge_serial->es_lock);
}
@@ -946,7 +967,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
/* tell the tty driver that something has changed */
if (tty && edge_port->open)
- wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
/* we have completed the command */
edge_port->commandPending = FALSE;
@@ -977,11 +998,8 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
if (edge_port == NULL)
return -ENODEV;
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
if (port->tty)
- port->tty->low_latency = 1;
+ port->tty->low_latency = low_latency;
/* see if we've set up our endpoint info yet (can't set it up in edge_startup
as the structures were not set up at that time.) */
@@ -1019,6 +1037,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
port0->bulk_in_buffer,
edge_serial->read_urb->transfer_buffer_length,
edge_bulk_in_callback, edge_serial);
+ edge_serial->read_in_progress = FALSE;
/* start interrupt read for this edgeport
* this interrupt will continue as long as the edgeport is connected */
@@ -1081,6 +1100,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* Allocate a URB for the write */
edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+ edge_port->write_in_progress = FALSE;
if (!edge_port->write_urb) {
dbg("%s - no memory", __FUNCTION__);
@@ -1247,9 +1267,11 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
kfree(edge_port->write_urb->transfer_buffer);
}
usb_free_urb (edge_port->write_urb);
+ edge_port->write_urb = NULL;
}
if (edge_port->txfifo.fifo) {
kfree(edge_port->txfifo.fifo);
+ edge_port->txfifo.fifo = NULL;
}
dbg("%s exited", __FUNCTION__);
@@ -1264,12 +1286,13 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
*****************************************************************************/
static int edge_write (struct usb_serial_port *port, const unsigned char *data, int count)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct TxFifo *fifo;
int copySize;
int bytesleft;
int firsthalf;
int secondhalf;
+ unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1279,6 +1302,8 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
// get a pointer to the Tx fifo
fifo = &edge_port->txfifo;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
// calculate number of bytes to put in fifo
copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));
@@ -1288,7 +1313,7 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
/* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
if (copySize == 0) {
dbg("%s - copySize = Zero", __FUNCTION__);
- return 0;
+ goto finish_write;
}
// queue the data
@@ -1326,6 +1351,9 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
// No need to check for wrap since we can not get to end of fifo in this part
}
+finish_write:
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
send_more_port_data((struct edgeport_serial *)usb_get_serial_data(port->serial), edge_port);
dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count);
@@ -1357,14 +1385,17 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
int bytesleft;
int firsthalf;
int secondhalf;
+ unsigned long flags;
dbg("%s(%d)", __FUNCTION__, edge_port->port->number);
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
if (edge_port->write_in_progress ||
!edge_port->open ||
(fifo->count == 0)) {
dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
- return;
+ goto exit_send;
}
// since the amount of data in the fifo will always fit into the
@@ -1376,7 +1407,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
// write.
if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) {
dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
- return;
+ goto exit_send;
}
// lock this write
@@ -1397,7 +1428,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
if (buffer == NULL) {
dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__);
edge_port->write_in_progress = FALSE;
- return;
+ goto exit_send;
}
buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count);
buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number - edge_port->port->serial->minor, count);
@@ -1435,7 +1466,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
/* something went wrong */
- dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status);
edge_port->write_in_progress = FALSE;
/* revert the credits as something bad happened. */
@@ -1443,6 +1474,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
edge_port->icount.tx -= count;
}
dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
+
+exit_send:
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
}
@@ -1456,8 +1490,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
*****************************************************************************/
static int edge_write_room (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int room;
+ unsigned long flags;
dbg("%s", __FUNCTION__);
@@ -1474,7 +1509,9 @@ static int edge_write_room (struct usb_serial_port *port)
}
// total of both buffers is still txCredit
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
room = edge_port->txCredits - edge_port->txfifo.count;
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dbg("%s - returns %d", __FUNCTION__, room);
return room;
@@ -1492,8 +1529,9 @@ static int edge_write_room (struct usb_serial_port *port)
*****************************************************************************/
static int edge_chars_in_buffer (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int num_chars;
+ unsigned long flags;
dbg("%s", __FUNCTION__);
@@ -1507,7 +1545,9 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
return -EINVAL;
}
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars);
}
@@ -1523,7 +1563,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
*****************************************************************************/
static void edge_throttle (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty;
int status;
@@ -1572,7 +1612,7 @@ static void edge_throttle (struct usb_serial_port *port)
*****************************************************************************/
static void edge_unthrottle (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty;
int status;
@@ -1620,7 +1660,7 @@ static void edge_unthrottle (struct usb_serial_port *port)
*****************************************************************************/
static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
unsigned int cflag;
@@ -1632,20 +1672,18 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
cflag = tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ if (cflag == old_termios->c_cflag &&
+ tty->termios->c_iflag == old_termios->c_iflag) {
dbg("%s - nothing to change", __FUNCTION__);
return;
}
}
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
- tty->termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios->c_cflag, tty->termios->c_iflag);
if (old_termios) {
dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag,
- RELEVANT_IFLAG(old_termios->c_iflag));
+ old_termios->c_cflag, old_termios->c_iflag);
}
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1678,12 +1716,15 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
static int get_lsr_info(struct edgeport_port *edge_port, unsigned int __user *value)
{
unsigned int result = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
if (edge_port->maxTxCredits == edge_port->txCredits &&
edge_port->txfifo.count == 0) {
dbg("%s -- Empty", __FUNCTION__);
result = TIOCSER_TEMT;
}
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -1709,7 +1750,7 @@ static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int
static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int mcr;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1738,7 +1779,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int result = 0;
unsigned int msr;
unsigned int mcr;
@@ -1795,7 +1836,7 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct
*****************************************************************************/
static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct async_icount cnow;
struct async_icount cprev;
struct serial_icounter_struct icount;
@@ -1877,7 +1918,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
*****************************************************************************/
static void edge_break (struct usb_serial_port *port, int break_state)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int status;
/* flush and chase */
@@ -1911,14 +1952,13 @@ static void edge_break (struct usb_serial_port *port, int break_state)
* process_rcvd_data
* this function handles the data received on the bulk in pipe.
*****************************************************************************/
-static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength)
+static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength)
{
struct usb_serial_port *port;
struct edgeport_port *edge_port;
struct tty_struct *tty;
__u16 lastBufferLength;
__u16 rxLen;
- int i;
dbg("%s", __FUNCTION__);
@@ -1973,7 +2013,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
// We have all the header bytes, process the status now
process_rcvd_status (edge_serial, edge_serial->rxHeader2, 0);
-
edge_serial->rxState = EXPECT_HDR1;
break;
} else {
@@ -2014,15 +2053,7 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
tty = edge_port->port->tty;
if (tty) {
dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort);
- for (i = 0; i < rxLen ; ++i) {
- /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
- if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
- tty_flip_buffer_push(tty);
- }
- /* this doesn't actually push the data through unless tty->low_latency is set */
- tty_insert_flip_char(tty, buffer[i], 0);
- }
- tty_flip_buffer_push(tty);
+ edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
}
edge_port->icount.rx += rxLen;
}
@@ -2043,8 +2074,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char
}
}
-
- return 0;
}
@@ -2060,7 +2089,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
/* switch the port pointer to the one being currently talked about */
port = edge_serial->serial->port[edge_serial->rxPort];
- edge_port = usb_get_serial_port_data(port);
+ edge_port = usb_get_serial_port_data(port);
if (edge_port == NULL) {
dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __FUNCTION__, edge_serial->rxPort);
return;
@@ -2150,6 +2179,37 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
/*****************************************************************************
+ * edge_tty_recv
+ * this function passes data on to the tty flip buffer
+ *****************************************************************************/
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length)
+{
+ int cnt;
+
+ do {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ __FUNCTION__, length);
+ return;
+ }
+ }
+ cnt = min(length, TTY_FLIPBUF_SIZE - tty->flip.count);
+ memcpy(tty->flip.char_buf_ptr, data, cnt);
+ memset(tty->flip.flag_buf_ptr, 0, cnt);
+ tty->flip.char_buf_ptr += cnt;
+ tty->flip.flag_buf_ptr += cnt;
+ tty->flip.count += cnt;
+ data += cnt;
+ length -= cnt;
+ } while (length > 0);
+
+ tty_flip_buffer_push(tty);
+}
+
+
+/*****************************************************************************
* handle_new_msr
* this function handles any change to the msr register for a port.
*****************************************************************************/
@@ -2208,10 +2268,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 l
}
/* Place LSR data byte into Rx buffer */
- if (lsrData && edge_port->port->tty) {
- tty_insert_flip_char(edge_port->port->tty, data, 0);
- tty_flip_buffer_push(edge_port->port->tty);
- }
+ if (lsrData && edge_port->port->tty)
+ edge_tty_recv(&edge_port->port->dev, edge_port->port->tty, &data, 1);
/* update input line counters */
icount = &edge_port->icount;
@@ -2432,9 +2490,10 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
if (status) {
/* something went wrong */
- dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status);
usb_kill_urb(urb);
usb_free_urb(urb);
+ CmdUrbs--;
return status;
}
@@ -2514,8 +2573,6 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
{
int i;
__u16 custom;
- __u16 round1;
- __u16 round;
dbg("%s - %d", __FUNCTION__, baudrate);
@@ -2530,16 +2587,10 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
// We have tried all of the standard baud rates
// lets try to calculate the divisor for this baud rate
// Make sure the baud rate is reasonable
- if (baudrate < 230400) {
+ if (baudrate > 50 && baudrate < 230400) {
// get divisor
- custom = (__u16)(230400L / baudrate);
+ custom = (__u16)((230400L + baudrate/2) / baudrate);
- // Check for round off
- round1 = (__u16)(2304000L / baudrate);
- round = (__u16)(round1 - (custom * 10));
- if (round > 4) {
- custom++;
- }
*divisor = custom;
dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom);
@@ -2631,7 +2682,15 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
lParity = LCR_PAR_NONE;
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & CMSPAR) {
+ if (cflag & PARODD) {
+ lParity = LCR_PAR_MARK;
+ dbg("%s - parity = mark", __FUNCTION__);
+ } else {
+ lParity = LCR_PAR_SPACE;
+ dbg("%s - parity = space", __FUNCTION__);
+ }
+ } else if (cflag & PARODD) {
lParity = LCR_PAR_ODD;
dbg("%s - parity = odd", __FUNCTION__);
} else {
@@ -2858,7 +2917,7 @@ static void load_application_firmware (struct edgeport_serial *edge_serial)
record = (struct edge_firmware_image_record *)firmware;
response = sram_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]);
if (response < 0) {
- dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), record->Len);
+ dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len));
break;
}
firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len);
@@ -2877,8 +2936,6 @@ static void load_application_firmware (struct edgeport_serial *edge_serial)
}
-
-
/****************************************************************************
* edge_startup
****************************************************************************/
@@ -2894,10 +2951,11 @@ static int edge_startup (struct usb_serial *serial)
/* create our private serial structure */
edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
memset (edge_serial, 0, sizeof(struct edgeport_serial));
+ spin_lock_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
@@ -2950,12 +3008,13 @@ static int edge_startup (struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
if (edge_port == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
usb_set_serial_data(serial, NULL);
kfree(edge_serial);
return -ENOMEM;
}
memset (edge_port, 0, sizeof(struct edgeport_port));
+ spin_lock_init(&edge_port->ep_lock);
edge_port->port = serial->port[i];
usb_set_serial_port_data(serial->port[i], edge_port);
}
@@ -2964,7 +3023,6 @@ static int edge_startup (struct usb_serial *serial)
}
-
/****************************************************************************
* edge_shutdown
* This function is called whenever the device is removed from the usb bus.
@@ -2992,6 +3050,7 @@ static void edge_shutdown (struct usb_serial *serial)
static int __init edgeport_init(void)
{
int retval;
+
retval = usb_serial_register(&edgeport_2port_device);
if (retval)
goto failed_2port_device_register;
@@ -3006,6 +3065,7 @@ static int __init edgeport_init(void)
goto failed_usb_register;
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
+
failed_usb_register:
usb_serial_deregister(&edgeport_8port_device);
failed_8port_device_register:
@@ -3017,7 +3077,6 @@ failed_2port_device_register:
}
-
/****************************************************************************
* edgeport_exit
* Called when the driver is about to be unloaded.
@@ -3040,3 +3099,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(low_latency, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Low latency enabled or not");
diff --git a/drivers/usb/serial/io_fw_boot.h b/drivers/usb/serial/io_fw_boot.h
index acbf0110089b..099fafaf52bb 100644
--- a/drivers/usb/serial/io_fw_boot.h
+++ b/drivers/usb/serial/io_fw_boot.h
@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record {
- unsigned short ExtAddr;
- unsigned short Addr;
- unsigned short Len;
+ __le16 ExtAddr;
+ __le16 Addr;
+ __le16 Len;
unsigned char Data[0];
} __attribute__ ((packed));
diff --git a/drivers/usb/serial/io_fw_boot2.h b/drivers/usb/serial/io_fw_boot2.h
index 3691fa54e722..c7c3a3c305fe 100644
--- a/drivers/usb/serial/io_fw_boot2.h
+++ b/drivers/usb/serial/io_fw_boot2.h
@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record {
- unsigned short ExtAddr;
- unsigned short Addr;
- unsigned short Len;
+ __le16 ExtAddr;
+ __le16 Addr;
+ __le16 Len;
unsigned char Data[0];
} __attribute__ ((packed));
diff --git a/drivers/usb/serial/io_fw_down.h b/drivers/usb/serial/io_fw_down.h
index d01ec7b223d4..5a61d809a46e 100644
--- a/drivers/usb/serial/io_fw_down.h
+++ b/drivers/usb/serial/io_fw_down.h
@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record {
- unsigned short ExtAddr;
- unsigned short Addr;
- unsigned short Len;
+ __le16 ExtAddr;
+ __le16 Addr;
+ __le16 Len;
unsigned char Data[0];
} __attribute__ ((packed));
diff --git a/drivers/usb/serial/io_fw_down2.h b/drivers/usb/serial/io_fw_down2.h
index bbd5dccc29e1..067277efd3b2 100644
--- a/drivers/usb/serial/io_fw_down2.h
+++ b/drivers/usb/serial/io_fw_down2.h
@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record {
- unsigned short ExtAddr;
- unsigned short Addr;
- unsigned short Len;
+ __le16 ExtAddr;
+ __le16 Addr;
+ __le16 Len;
unsigned char Data[0];
} __attribute__ ((packed));
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index d43b9e6cd7a4..e7ffe02408bd 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -98,6 +98,9 @@ static struct usb_serial_device_type edgeport_2port_device = {
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
};
static struct usb_serial_device_type edgeport_4port_device = {
@@ -123,6 +126,9 @@ static struct usb_serial_device_type edgeport_4port_device = {
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
};
static struct usb_serial_device_type edgeport_8port_device = {
@@ -148,6 +154,9 @@ static struct usb_serial_device_type edgeport_8port_device = {
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
};
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 78f7373c3fd6..bd86f7e7c357 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -10,7 +10,11 @@
* (at your option) any later version.
*
* Supports the following devices:
- * EP/1 EP/2 EP/4
+ * EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT
+ *
+ * For questions or problems with this driver, contact Inside Out
+ * Networks technical support, or Peter Berger <pberger@brimson.com>,
+ * or Al Borchers <alborchers@steinerpoint.com>.
*
* Version history:
*
@@ -34,18 +38,18 @@
#include <linux/serial.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
+#include <asm/semaphore.h>
#include <linux/usb.h>
+
#include "usb-serial.h"
#include "io_16654.h"
#include "io_usbvend.h"
#include "io_ti.h"
-static int debug;
-
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.2"
+#define DRIVER_VERSION "v0.7"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -73,6 +77,16 @@ struct edgeport_uart_buf_desc {
#define TI_MODE_DOWNLOAD 2 // Made it to download mode
#define TI_MODE_TRANSITIONING 3 // Currently in boot mode but transitioning to download mode
+/* read urb state */
+#define EDGE_READ_URB_RUNNING 0
+#define EDGE_READ_URB_STOPPING 1
+#define EDGE_READ_URB_STOPPED 2
+
+#define EDGE_LOW_LATENCY 1
+#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */
+
+#define EDGE_OUT_BUF_SIZE 1024
+
/* Product information read from the Edgeport */
struct product_info
@@ -81,6 +95,13 @@ struct product_info
__u8 hardware_type; // Type of hardware
} __attribute__((packed));
+/* circular buffer */
+struct edge_buf {
+ unsigned int buf_size;
+ char *buf_buf;
+ char *buf_get;
+ char *buf_put;
+};
struct edgeport_port {
__u16 uart_base;
@@ -102,12 +123,18 @@ struct edgeport_port {
happen */
struct edgeport_serial *edge_serial;
struct usb_serial_port *port;
+ __u8 bUartMode; /* Port type, 0: RS232, etc. */
+ spinlock_t ep_lock;
+ int ep_read_urb_state;
+ int ep_write_urb_in_use;
+ struct edge_buf *ep_out_buf;
};
struct edgeport_serial {
struct product_info product_info;
u8 TI_I2C_Type; // Type of I2C in UMP
u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode
+ struct semaphore es_sem;
int num_ports_open;
struct usb_serial *serial;
};
@@ -116,6 +143,21 @@ struct edgeport_serial {
/* Devices that this driver supports */
static struct usb_device_id edgeport_1port_id_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
{ }
};
@@ -129,12 +171,32 @@ static struct usb_device_id edgeport_2port_id_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
+// The 4-port shows up as two 2-port devices
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
{ }
};
/* Devices that this driver supports */
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
@@ -144,6 +206,10 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
{ }
};
@@ -160,12 +226,33 @@ static struct usb_driver io_driver = {
static struct EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion;
+static int debug;
+
static int TIStayInBootMode = 0;
+static int low_latency = EDGE_LOW_LATENCY;
+static int closing_wait = EDGE_CLOSING_WAIT;
static int ignore_cpu_rev = 0;
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length);
+
+static void stop_read(struct edgeport_port *edge_port);
+static int restart_read(struct edgeport_port *edge_port);
static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void edge_send(struct usb_serial_port *port);
+
+/* circular buffer */
+static struct edge_buf *edge_buf_alloc(unsigned int size);
+static void edge_buf_free(struct edge_buf *eb);
+static void edge_buf_clear(struct edge_buf *eb);
+static unsigned int edge_buf_data_avail(struct edge_buf *eb);
+static unsigned int edge_buf_space_avail(struct edge_buf *eb);
+static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+ unsigned int count);
+static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+ unsigned int count);
+
static int TIReadVendorRequestSync (struct usb_device *dev,
__u8 request,
@@ -241,7 +328,6 @@ static int TIWriteCommandSync (struct usb_device *dev, __u8 command,
}
-
/* clear tx/rx buffers and fifo in TI UMP */
static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
{
@@ -291,7 +377,7 @@ static int TIReadDownloadMemory(struct usb_device *dev, int start_address,
status = TIReadVendorRequestSync (dev,
UMPC_MEMORY_READ, // Request
(__u16)address_type, // wValue (Address type)
- be_start_address, // wIndex (Address to read)
+ (__force __u16)be_start_address, // wIndex (Address to read)
buffer, // TransferBuffer
read_length); // TransferBufferLength
@@ -405,7 +491,7 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
status = TISendVendorRequestSync (serial->serial->dev,
UMPC_MEMORY_WRITE, // Request
(__u16)address_type, // wValue
- be_start_address, // wIndex
+ (__force __u16)be_start_address, // wIndex
buffer, // TransferBuffer
write_length);
if (status) {
@@ -432,11 +518,11 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
status = TISendVendorRequestSync (serial->serial->dev,
UMPC_MEMORY_WRITE, // Request
(__u16)address_type, // wValue
- be_start_address, // wIndex
+ (__force __u16)be_start_address, // wIndex
buffer, // TransferBuffer
write_length); // TransferBufferLength
if (status) {
- dbg ("%s - ERROR %d", __FUNCTION__, status);
+ dev_err (&serial->serial->dev->dev, "%s - ERROR %d\n", __FUNCTION__, status);
return status;
}
@@ -510,74 +596,54 @@ exit_is_tx_active:
return bytes_left;
}
-static void TIChasePort(struct edgeport_port *port)
+static void TIChasePort(struct edgeport_port *port, unsigned long timeout, int flush)
{
- int loops;
- int last_count;
- int write_size;
-
-restart_tx_loop:
- // Base the LoopTime on the baud rate
- if (port->baud_rate == 0)
- port->baud_rate = 1200;
-
- write_size = port->tx.count;
- loops = max(100, (100*write_size)/(port->baud_rate/10));
- dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__,
- write_size, port->baud_rate, loops);
-
- while (1) {
- // Save Last count
- last_count = port->tx.count;
-
- dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__,
- last_count, loops);
-
- /* Is the Edgeport Buffer empty? */
- if (port->tx.count == 0)
+ int baud_rate;
+ struct tty_struct *tty = port->port->tty;
+ wait_queue_t wait;
+ unsigned long flags;
+
+ if (!timeout)
+ timeout = (HZ*EDGE_CLOSING_WAIT)/100;
+
+ /* wait for data to drain from the buffer */
+ spin_lock_irqsave(&port->ep_lock, flags);
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (edge_buf_data_avail(port->ep_out_buf) == 0
+ || timeout == 0 || signal_pending(current)
+ || !usb_get_intfdata(port->port->serial->interface)) /* disconnect */
+ break;
+ spin_unlock_irqrestore(&port->ep_lock, flags);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irqsave(&port->ep_lock, flags);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&tty->write_wait, &wait);
+ if (flush)
+ edge_buf_clear(port->ep_out_buf);
+ spin_unlock_irqrestore(&port->ep_lock, flags);
+
+ /* wait for data to drain from the device */
+ timeout += jiffies;
+ while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
+ && usb_get_intfdata(port->port->serial->interface)) { /* not disconnected */
+ if (!TIIsTxActive(port))
break;
-
- /* Block the thread for 10ms */
msleep(10);
-
- if (last_count == port->tx.count) {
- /* No activity.. count down. */
- --loops;
- if (loops == 0) {
- dbg ("%s - Wait for TxEmpty - TIMEOUT",
- __FUNCTION__);
- return;
- }
- } else {
- /* Reset timeout value back to a minimum of 1 second */
- dbg ("%s - Wait for TxEmpty Reset Count", __FUNCTION__);
- goto restart_tx_loop;
- }
}
- dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO",
- __FUNCTION__);
-
- write_size = TIIsTxActive (port);
- loops = max(50, (100*write_size)/(port->baud_rate/10));
- dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__,
- write_size, port->baud_rate, loops);
-
- while (1) {
- /* This function takes 4 ms; */
- if (!TIIsTxActive (port)) {
- /* Delay a few char times */
- msleep(50);
- dbg ("%s - Empty", __FUNCTION__);
- return;
- }
+ /* disconnected */
+ if (!usb_get_intfdata(port->port->serial->interface))
+ return;
- --loops;
- if (loops == 0) {
- dbg ("%s - TIMEOUT", __FUNCTION__);
- return;
- }
- }
+ /* wait one more character time, based on baud rate */
+ /* (TIIsTxActive doesn't seem to wait for the last byte) */
+ if ((baud_rate=port->baud_rate) == 0)
+ baud_rate = 50;
+ msleep(max(1,(10000+baud_rate-1)/baud_rate));
}
static int TIChooseConfiguration (struct usb_device *dev)
@@ -688,6 +754,7 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
struct ti_i2c_desc *rom_desc;
int start_address = 2;
__u8 *buffer;
+ __u16 ttype;
rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
if (!rom_desc) {
@@ -701,12 +768,12 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
return -ENOMEM;
}
- // Read the first byte (Signature0) must be 0x52
+ // Read the first byte (Signature0) must be 0x52 or 0x10
status = TIReadRom (serial, 0, 1, buffer);
if (status)
goto ExitTiValidateI2cImage;
- if (*buffer != 0x52) {
+ if (*buffer != UMP5152 && *buffer != UMP3410) {
dev_err (dev, "%s - invalid buffer signature\n", __FUNCTION__);
status = -ENODEV;
goto ExitTiValidateI2cImage;
@@ -730,7 +797,9 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type);
// Skip type 2 record
- if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) {
+ ttype = rom_desc->Type & 0x0f;
+ if ( ttype != I2C_DESC_TYPE_FIRMWARE_BASIC
+ && ttype != I2C_DESC_TYPE_FIRMWARE_AUTO ) {
// Read the descriptor data
status = TIReadRom(serial,
start_address+sizeof(struct ti_i2c_desc),
@@ -840,7 +909,7 @@ static int BuildI2CFirmwareHeader (__u8 *header, struct device *dev)
memcpy (buffer + sizeof(struct ti_i2c_firmware_rec),
&PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)],
- img_header->Length);
+ le16_to_cpu(img_header->Length));
for (i=0; i < buffer_size; i++) {
cs = (__u8)(cs + buffer[i]);
@@ -878,7 +947,7 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
dbg ("%s - read 2 status error = %d", __FUNCTION__, status);
else
dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
- if ((!status) && data == 0x52) {
+ if ((!status) && (data == UMP5152 || data == UMP3410)) {
dbg ("%s - ROM_TYPE_II", __FUNCTION__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
return 0;
@@ -895,7 +964,7 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
dbg ("%s - read 3 status error = %d", __FUNCTION__, status);
else
dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
- if ((!status) && data == 0x52) {
+ if ((!status) && (data == UMP5152 || data == UMP3410)) {
dbg ("%s - ROM_TYPE_III", __FUNCTION__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
return 0;
@@ -983,7 +1052,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
interface = &serial->serial->interface->cur_altsetting->desc;
if (!interface) {
- dev_err (&serial->serial->dev->dev, "%s - no interface set, error!", __FUNCTION__);
+ dev_err (dev, "%s - no interface set, error!\n", __FUNCTION__);
return -ENODEV;
}
@@ -1249,7 +1318,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
dbg ("%s - Update complete 0x%x", __FUNCTION__, status);
if (status) {
- dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__);
+ dev_err (dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", __FUNCTION__);
kfree (rom_desc);
kfree (ti_manuf_desc);
return status;
@@ -1356,7 +1425,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
header = (struct ti_i2c_image_header *)buffer;
// update length and checksum after padding
- header->Length = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header));
+ header->Length = cpu_to_le16((__u16)(buffer_size - sizeof(struct ti_i2c_image_header)));
header->CheckSum = cs;
// Download the operational code
@@ -1560,6 +1629,7 @@ static __u8 MapLineStatus (__u8 ti_lsr)
static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
{
struct async_icount *icount;
+ struct tty_struct *tty;
dbg ("%s - %02x", __FUNCTION__, msr);
@@ -1581,6 +1651,17 @@ static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
/* Save the new modem status */
edge_port->shadow_msr = msr & 0xf0;
+ tty = edge_port->port->tty;
+ /* handle CTS flow control */
+ if (tty && C_CRTSCTS(tty)) {
+ if (msr & EDGEPORT_MSR_CTS) {
+ tty->hw_stopped = 0;
+ tty_wakeup(tty);
+ } else {
+ tty->hw_stopped = 1;
+ }
+ }
+
return;
}
@@ -1602,10 +1683,8 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
}
/* Place LSR data byte into Rx buffer */
- if (lsr_data && edge_port->port->tty) {
- tty_insert_flip_char(edge_port->port->tty, data, 0);
- tty_flip_buffer_push(edge_port->port->tty);
- }
+ if (lsr_data && edge_port->port->tty)
+ edge_tty_recv(&edge_port->port->dev, edge_port->port->tty, &data, 1);
/* update input line counters */
icount = &edge_port->icount;
@@ -1646,7 +1725,7 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
goto exit;
}
@@ -1715,21 +1794,31 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
- int status;
- int i;
+ int status = 0;
int port_number;
dbg("%s", __FUNCTION__);
- if (urb->status) {
- dbg ("%s - nonzero read bulk status received: %d",
- __FUNCTION__, urb->status);
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dev_err (&urb->dev->dev,"%s - nonzero read bulk status received: %d\n",
+ __FUNCTION__, urb->status );
+ }
- if (urb->status == -EPIPE) {
- /* clear any problem that might have happened on this pipe */
- usb_clear_halt (edge_port->port->serial->dev, urb->pipe);
- goto exit;
- }
+ if (urb->status == -EPIPE)
+ goto exit;
+
+ if (urb->status) {
+ dev_err(&urb->dev->dev,"%s - stopping read!\n", __FUNCTION__);
return;
}
@@ -1752,52 +1841,78 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
if (edge_port->close_pending) {
dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__);
} else {
- for (i = 0; i < urb->actual_length ; ++i) {
- /* if we insert more than TTY_FLIPBUF_SIZE characters,
- * we drop them. */
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- tty_flip_buffer_push(tty);
- }
- /* this doesn't actually push the data through unless
- * tty->low_latency is set */
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
+ edge_tty_recv(&edge_port->port->dev, tty, data, urb->actual_length);
}
edge_port->icount.rx += urb->actual_length;
}
exit:
- /* continue always trying to read */
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ /* continue read unless stopped */
+ spin_lock(&edge_port->ep_lock);
+ if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) {
+ urb->dev = edge_port->port->serial->dev;
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ } else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) {
+ edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
+ }
+ spin_unlock(&edge_port->ep_lock);
if (status)
dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, status);
}
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length)
+{
+ int cnt;
+
+ do {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ __FUNCTION__, length);
+ return;
+ }
+ }
+ cnt = min(length, TTY_FLIPBUF_SIZE - tty->flip.count);
+ memcpy(tty->flip.char_buf_ptr, data, cnt);
+ memset(tty->flip.flag_buf_ptr, 0, cnt);
+ tty->flip.char_buf_ptr += cnt;
+ tty->flip.flag_buf_ptr += cnt;
+ tty->flip.count += cnt;
+ data += cnt;
+ length -= cnt;
+ } while (length > 0);
+
+ tty_flip_buffer_push(tty);
+}
+
static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct tty_struct *tty;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
dbg ("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg ("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ edge_port->ep_write_urb_in_use = 0;
- if (urb->status == -EPIPE) {
- /* clear any problem that might have happened on this pipe */
- usb_clear_halt (port->serial->dev, urb->pipe);
- }
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
+ default:
+ dev_err (&urb->dev->dev,"%s - nonzero write bulk status received: %d\n",
+ __FUNCTION__, urb->status);
}
- tty = port->tty;
- if (tty) {
- /* let the tty driver wakeup if it has a special write_wakeup function */
- tty_wakeup(tty);
- }
+ /* send any buffered data */
+ edge_send(port);
}
static int edge_open (struct usb_serial_port *port, struct file * filp)
@@ -1816,11 +1931,8 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
if (edge_port == NULL)
return -ENODEV;
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
if (port->tty)
- port->tty->low_latency = 1;
+ port->tty->low_latency = low_latency;
port_number = port->number - port->serial->minor;
switch (port_number) {
@@ -1847,8 +1959,11 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* turn off loopback */
status = TIClearLoopBack (edge_port);
- if (status)
+ if (status) {
+ dev_err(&port->dev,"%s - cannot send clear loopback command, %d\n",
+ __FUNCTION__, status);
return status;
+ }
/* set up the port settings */
edge_set_termios (port, NULL);
@@ -1874,8 +1989,10 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
open_settings,
NULL,
0);
- if (status)
+ if (status) {
+ dev_err(&port->dev,"%s - cannot send open command, %d\n", __FUNCTION__, status);
return status;
+ }
/* Start the DMA? */
status = TIWriteCommandSync (dev,
@@ -1884,13 +2001,17 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
0,
NULL,
0);
- if (status)
+ if (status) {
+ dev_err(&port->dev,"%s - cannot send start DMA command, %d\n", __FUNCTION__, status);
return status;
+ }
/* Clear TX and RX buffers in UMP */
status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN);
- if (status)
+ if (status) {
+ dev_err(&port->dev,"%s - cannot send clear buffers command, %d\n", __FUNCTION__, status);
return status;
+ }
/* Read Initial MSR */
status = TIReadVendorRequestSync (dev,
@@ -1899,18 +2020,27 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
(__u16)(UMPM_UART1_PORT + port_number), // wIndex (Address)
&edge_port->shadow_msr, // TransferBuffer
1); // TransferBufferLength
- if (status)
+ if (status) {
+ dev_err(&port->dev,"%s - cannot send read MSR command, %d\n", __FUNCTION__, status);
return status;
+ }
dbg ("ShadowMSR 0x%X", edge_port->shadow_msr);
+ /* Set Initial MCR */
+ edge_port->shadow_mcr = MCR_RTS | MCR_DTR;
+ dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
+
edge_serial = edge_port->edge_serial;
+ if (down_interruptible(&edge_serial->es_sem))
+ return -ERESTARTSYS;
if (edge_serial->num_ports_open == 0) {
/* we are the first port to be opened, let's post the interrupt urb */
urb = edge_serial->serial->port[0]->interrupt_in_urb;
if (!urb) {
dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
- return -EINVAL;
+ status = -EINVAL;
+ goto up_es_sem;
}
urb->complete = edge_interrupt_callback;
urb->context = edge_serial;
@@ -1918,7 +2048,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
- return status;
+ goto up_es_sem;
}
}
@@ -1933,25 +2063,34 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
urb = port->read_urb;
if (!urb) {
dev_err (&port->dev, "%s - no read urb present, exiting\n", __FUNCTION__);
- return -EINVAL;
+ status = -EINVAL;
+ goto unlink_int_urb;
}
+ edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
urb->complete = edge_bulk_in_callback;
urb->context = edge_port;
urb->dev = dev;
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
dev_err (&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
- return status;
+ goto unlink_int_urb;
}
++edge_serial->num_ports_open;
dbg("%s - exited", __FUNCTION__);
- return 0;
+ goto up_es_sem;
+
+unlink_int_urb:
+ if (edge_port->edge_serial->num_ports_open == 0)
+ usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+up_es_sem:
+ up(&edge_serial->es_sem);
+ return status;
}
-static void edge_close (struct usb_serial_port *port, struct file * filp)
+static void edge_close (struct usb_serial_port *port, struct file *filp)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
@@ -1969,10 +2108,12 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
* this flag and dump add read data */
edge_port->close_pending = 1;
- /* chase the port close */
- TIChasePort (edge_port);
+ /* chase the port close and flush */
+ TIChasePort (edge_port, (HZ*closing_wait)/100, 1);
usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->write_urb);
+ edge_port->ep_write_urb_in_use = 0;
/* assuming we can still talk to the device,
* send a close port command to it */
@@ -1984,12 +2125,14 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
0,
NULL,
0);
+ down(&edge_serial->es_sem);
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
/* last port is now closed, let's shut down our interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
edge_port->edge_serial->num_ports_open = 0;
}
+ up(&edge_serial->es_sem);
edge_port->close_pending = 0;
dbg("%s - exited", __FUNCTION__);
@@ -1998,7 +2141,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
static int edge_write (struct usb_serial_port *port, const unsigned char *data, int count)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int result;
+ unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2011,15 +2154,45 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
return -ENODEV;
if (edge_port->close_pending == 1)
return -ENODEV;
-
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
- return 0;
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+ count = edge_buf_put(edge_port->ep_out_buf, data, count);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+ edge_send(port);
+
+ return count;
+}
+
+static void edge_send(struct usb_serial_port *port)
+{
+ int count, result;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct tty_struct *tty = port->tty;
+ unsigned long flags;
+
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+ if (edge_port->ep_write_urb_in_use) {
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+ return;
}
- count = min (count, port->bulk_out_size);
+ count = edge_buf_get(edge_port->ep_out_buf,
+ port->write_urb->transfer_buffer,
+ port->bulk_out_size);
- memcpy (port->write_urb->transfer_buffer, data, count);
+ if (count == 0) {
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+ return;
+ }
+
+ edge_port->ep_write_urb_in_use = 1;
+
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
@@ -2033,33 +2206,38 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
- result = count;
-
- if (result > 0)
+ edge_port->ep_write_urb_in_use = 0;
+ // TODO: reschedule edge_send
+ } else {
edge_port->icount.tx += count;
+ }
- return result;
+ /* wakeup any process waiting for writes to complete */
+ /* there is now more room in the buffer for new writes */
+ if (tty) {
+ /* let the tty driver wakeup if it has a special write_wakeup function */
+ tty_wakeup(tty);
+ }
}
static int edge_write_room (struct usb_serial_port *port)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int room = 0;
+ unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (edge_port == NULL)
return -ENODEV;
if (edge_port->close_pending == 1)
return -ENODEV;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
- if (port->write_urb->status != -EINPROGRESS)
- room = port->bulk_out_size;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+ room = edge_buf_space_avail(edge_port->ep_out_buf);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dbg("%s - returns %d", __FUNCTION__, room);
return room;
@@ -2069,18 +2247,18 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int chars = 0;
+ unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (edge_port == NULL)
return -ENODEV;
if (edge_port->close_pending == 1)
return -ENODEV;
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (port->write_urb->status == -EINPROGRESS)
- chars = port->write_urb->transfer_buffer_length;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+ chars = edge_buf_data_avail(edge_port->ep_out_buf);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dbg ("%s - returns %d", __FUNCTION__, chars);
return chars;
@@ -2102,21 +2280,21 @@ static void edge_throttle (struct usb_serial_port *port)
dbg ("%s - no tty available", __FUNCTION__);
return;
}
+
/* if we are implementing XON/XOFF, send the stop character */
if (I_IXOFF(tty)) {
unsigned char stop_char = STOP_CHAR(tty);
status = edge_write (port, &stop_char, 1);
if (status <= 0) {
- return;
+ dev_err(&port->dev, "%s - failed to write stop character, %d\n", __FUNCTION__, status);
}
}
- /* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
- status = TIClearRts (edge_port);
- }
+ /* if we are implementing RTS/CTS, stop reads */
+ /* and the Edgeport will clear the RTS line */
+ if (C_CRTSCTS(tty))
+ stop_read(edge_port);
- usb_kill_urb(port->read_urb);
}
static void edge_unthrottle (struct usb_serial_port *port)
@@ -2141,29 +2319,61 @@ static void edge_unthrottle (struct usb_serial_port *port)
unsigned char start_char = START_CHAR(tty);
status = edge_write (port, &start_char, 1);
if (status <= 0) {
- return;
+ dev_err(&port->dev, "%s - failed to write start character, %d\n", __FUNCTION__, status);
}
}
- /* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
- status = TISetRts (edge_port);
+ /* if we are implementing RTS/CTS, restart reads */
+ /* are the Edgeport will assert the RTS line */
+ if (C_CRTSCTS(tty)) {
+ status = restart_read(edge_port);
+ if (status)
+ dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
}
- port->read_urb->dev = port->serial->dev;
- status = usb_submit_urb (port->read_urb, GFP_ATOMIC);
- if (status) {
- dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
- }
}
+static void stop_read(struct edgeport_port *edge_port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+ if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
+ edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPING;
+ edge_port->shadow_mcr &= ~MCR_RTS;
+
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+}
+
+static int restart_read(struct edgeport_port *edge_port)
+{
+ struct urb *urb;
+ int status = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
+ if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) {
+ urb = edge_port->port->read_urb;
+ urb->complete = edge_bulk_in_callback;
+ urb->context = edge_port;
+ urb->dev = edge_port->port->serial->dev;
+ status = usb_submit_urb(urb, GFP_KERNEL);
+ }
+ edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
+ edge_port->shadow_mcr |= MCR_RTS;
+
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+ return status;
+}
static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
{
struct ump_uart_config *config;
struct tty_struct *tty;
int baud;
- int round;
unsigned cflag;
int status;
int port_number = edge_port->port->number - edge_port->port->serial->minor;
@@ -2190,7 +2400,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
/* These flags must be set */
config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
- config->bUartMode = 0;
+ config->bUartMode = (__u8)(edge_port->bUartMode);
switch (cflag & CSIZE) {
case CS5:
@@ -2242,6 +2452,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
dbg("%s - RTS/CTS is enabled", __FUNCTION__);
} else {
dbg("%s - RTS/CTS is disabled", __FUNCTION__);
+ tty->hw_stopped = 0;
+ restart_read(edge_port);
}
/* if we are implementing XON/XOFF, set the start and stop character in the device */
@@ -2274,10 +2486,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
/* pick a default, any default... */
baud = 9600;
}
- config->wBaudRate = (__u16)(461550L / baud);
- round = 4615500L / baud;
- if ((round - (config->wBaudRate * 10)) >= 5)
- config->wBaudRate++;
+ edge_port->baud_rate = baud;
+ config->wBaudRate = (__u16)((461550L + baud/2) / baud);
dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
@@ -2324,20 +2534,18 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
cflag = tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ if (cflag == old_termios->c_cflag &&
+ tty->termios->c_iflag == old_termios->c_iflag) {
dbg ("%s - nothing to change", __FUNCTION__);
return;
}
}
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
- tty->termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios->c_cflag, tty->termios->c_iflag);
if (old_termios) {
dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag,
- RELEVANT_IFLAG(old_termios->c_iflag));
+ old_termios->c_cflag, old_termios->c_iflag);
}
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2353,7 +2561,7 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int mcr;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2382,7 +2590,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int result = 0;
unsigned int msr;
unsigned int mcr;
@@ -2421,7 +2629,7 @@ static int get_serial_info (struct edgeport_port *edge_port, struct serial_struc
tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
+ tmp.closing_wait = closing_wait;
// tmp.custom_divisor = state->custom_divisor;
// tmp.hub6 = state->hub6;
// tmp.io_type = state->io_type;
@@ -2502,7 +2710,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
dbg ("%s - state = %d", __FUNCTION__, break_state);
/* chase the port close */
- TIChasePort (edge_port);
+ TIChasePort (edge_port, 0, 0);
if (break_state == -1) {
status = TISetBreak (edge_port);
@@ -2532,6 +2740,7 @@ static int edge_startup (struct usb_serial *serial)
return -ENOMEM;
}
memset (edge_serial, 0, sizeof(struct edgeport_serial));
+ sema_init(&edge_serial->es_sem, 1);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
@@ -2546,25 +2755,49 @@ static int edge_startup (struct usb_serial *serial)
edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
if (edge_port == NULL) {
dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
- return -ENOMEM;
+ goto cleanup;
}
memset (edge_port, 0, sizeof(struct edgeport_port));
+ spin_lock_init(&edge_port->ep_lock);
+ edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
+ if (edge_port->ep_out_buf == NULL) {
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ kfree(edge_port);
+ goto cleanup;
+ }
edge_port->port = serial->port[i];
edge_port->edge_serial = edge_serial;
usb_set_serial_port_data(serial->port[i], edge_port);
+ edge_port->bUartMode = 0; /* Default is RS232 */
}
return 0;
+
+cleanup:
+ for (--i; i>=0; --i) {
+ edge_port = usb_get_serial_port_data(serial->port[i]);
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ kfree (edge_serial);
+ usb_set_serial_data(serial, NULL);
+ return -ENOMEM;
}
static void edge_shutdown (struct usb_serial *serial)
{
int i;
+ struct edgeport_port *edge_port;
dbg ("%s", __FUNCTION__);
for (i=0; i < serial->num_ports; ++i) {
- kfree (usb_get_serial_port_data(serial->port[i]));
+ edge_port = usb_get_serial_port_data(serial->port[i]);
+ if (edge_port) {
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
+ }
usb_set_serial_port_data(serial->port[i], NULL);
}
kfree (usb_get_serial_data(serial));
@@ -2572,6 +2805,185 @@ static void edge_shutdown (struct usb_serial *serial)
}
+/* Circular Buffer */
+
+/*
+ * edge_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+
+static struct edge_buf *edge_buf_alloc(unsigned int size)
+{
+ struct edge_buf *eb;
+
+
+ if (size == 0)
+ return NULL;
+
+ eb = (struct edge_buf *)kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
+ if (eb == NULL)
+ return NULL;
+
+ eb->buf_buf = kmalloc(size, GFP_KERNEL);
+ if (eb->buf_buf == NULL) {
+ kfree(eb);
+ return NULL;
+ }
+
+ eb->buf_size = size;
+ eb->buf_get = eb->buf_put = eb->buf_buf;
+
+ return eb;
+}
+
+
+/*
+ * edge_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+
+void edge_buf_free(struct edge_buf *eb)
+{
+ if (eb != NULL) {
+ if (eb->buf_buf != NULL)
+ kfree(eb->buf_buf);
+ kfree(eb);
+ }
+}
+
+
+/*
+ * edge_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+
+static void edge_buf_clear(struct edge_buf *eb)
+{
+ if (eb != NULL)
+ eb->buf_get = eb->buf_put;
+ /* equivalent to a get of all data available */
+}
+
+
+/*
+ * edge_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+
+static unsigned int edge_buf_data_avail(struct edge_buf *eb)
+{
+ if (eb != NULL)
+ return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size);
+ else
+ return 0;
+}
+
+
+/*
+ * edge_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+
+static unsigned int edge_buf_space_avail(struct edge_buf *eb)
+{
+ if (eb != NULL)
+ return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size);
+ else
+ return 0;
+}
+
+
+/*
+ * edge_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+
+ if (eb == NULL)
+ return 0;
+
+ len = edge_buf_space_avail(eb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = eb->buf_buf + eb->buf_size - eb->buf_put;
+ if (count > len) {
+ memcpy(eb->buf_put, buf, len);
+ memcpy(eb->buf_buf, buf+len, count - len);
+ eb->buf_put = eb->buf_buf + count - len;
+ } else {
+ memcpy(eb->buf_put, buf, count);
+ if (count < len)
+ eb->buf_put += count;
+ else /* count == len */
+ eb->buf_put = eb->buf_buf;
+ }
+
+ return count;
+}
+
+
+/*
+ * edge_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+
+ if (eb == NULL)
+ return 0;
+
+ len = edge_buf_data_avail(eb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = eb->buf_buf + eb->buf_size - eb->buf_get;
+ if (count > len) {
+ memcpy(buf, eb->buf_get, len);
+ memcpy(buf+len, eb->buf_buf, count - len);
+ eb->buf_get = eb->buf_buf + count - len;
+ } else {
+ memcpy(buf, eb->buf_get, count);
+ if (count < len)
+ eb->buf_get += count;
+ else /* count == len */
+ eb->buf_get = eb->buf_buf;
+ }
+
+ return count;
+}
+
+
static struct usb_serial_device_type edgeport_1port_device = {
.owner = THIS_MODULE,
.name = "Edgeport TI 1 port adapter",
@@ -2595,6 +3007,9 @@ static struct usb_serial_device_type edgeport_1port_device = {
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_callback,
};
static struct usb_serial_device_type edgeport_2port_device = {
@@ -2620,6 +3035,9 @@ static struct usb_serial_device_type edgeport_2port_device = {
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_callback,
};
@@ -2663,6 +3081,12 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(low_latency, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(low_latency, "Low latency enabled or not");
+
+module_param(closing_wait, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs");
+
module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device");
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index 65073409f8c0..8c1fa5e722b1 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -619,7 +619,7 @@ struct watchport_firmware_version
// Structure of header of download image in fw_down.h
struct ti_i2c_image_header
{
- __u16 Length;
+ __le16 Length;
__u8 CheckSum;
}__attribute__((packed));
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 11d356a6c08d..2e261c73cfcd 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -773,9 +773,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
switch (cflag & CSIZE) {
case CS5:
dbg("%s - 5 bits/byte not supported", __FUNCTION__);
+ spin_unlock_irqrestore (&priv->lock, flags);
return ;
case CS6:
dbg("%s - 6 bits/byte not supported", __FUNCTION__);
+ spin_unlock_irqrestore (&priv->lock, flags);
return ;
case CS7:
priv->cfg.databits = kl5kusb105a_dtb_7;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 567911b65929..1c16a1f0bfd2 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -236,7 +236,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) {
static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
{
- unsigned int divisor;
+ __le32 divisor;
int rc;
unsigned char zero_byte = 0;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 11664afffc65..e6c344bdbe97 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -463,6 +463,7 @@ static void destroy_serial(struct kref *kref)
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
+ kfree(port->interrupt_out_buffer);
}
}
@@ -480,45 +481,51 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial *serial;
struct usb_serial_port *port;
unsigned int portNumber;
- int retval = -ENODEV;
+ int retval;
dbg("%s", __FUNCTION__);
- /* initialize the pointer incase something fails */
- tty->driver_data = NULL;
-
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index);
- if (!serial)
- goto bailout;
+ if (!serial) {
+ tty->driver_data = NULL;
+ return -ENODEV;
+ }
- /* set up our port structure making the tty driver remember our port object, and us it */
portNumber = tty->index - serial->minor;
port = serial->port[portNumber];
- tty->driver_data = port;
-
- port->tty = tty;
- /* lock this module before we call it,
- this may, which means we must bail out, safe because we are called with BKL held */
- if (!try_module_get(serial->type->owner)) {
- kref_put(&serial->kref, destroy_serial);
- goto bailout;
- }
-
- retval = 0;
++port->open_count;
+
if (port->open_count == 1) {
+
+ /* set up our port structure making the tty driver
+ * remember our port object, and us it */
+ tty->driver_data = port;
+ port->tty = tty;
+
+ /* lock this module before we call it
+ * this may fail, which means we must bail out,
+ * safe because we are called with BKL held */
+ if (!try_module_get(serial->type->owner)) {
+ retval = -ENODEV;
+ goto bailout_kref_put;
+ }
+
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
- if (retval) {
- port->open_count = 0;
- module_put(serial->type->owner);
- kref_put(&serial->kref, destroy_serial);
- }
+ if (retval)
+ goto bailout_module_put;
}
-bailout:
+
+ return 0;
+
+bailout_module_put:
+ module_put(serial->type->owner);
+bailout_kref_put:
+ kref_put(&serial->kref, destroy_serial);
+ port->open_count = 0;
return retval;
}
@@ -531,21 +538,24 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
+ if (port->open_count == 0)
+ return;
+
--port->open_count;
- if (port->open_count <= 0) {
+ if (port->open_count == 0) {
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
- port->open_count = 0;
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
+
+ module_put(port->serial->type->owner);
}
- module_put(port->serial->type->owner);
kref_put(&port->serial->kref, destroy_serial);
}
@@ -805,6 +815,7 @@ static void port_release(struct device *dev)
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
+ kfree(port->interrupt_out_buffer);
kfree(port);
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index dd7ed7b1760c..b6384a313373 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1114,11 +1114,11 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *
command_port->write_urb->transfer_buffer_length = datasize + 1;
command_port->write_urb->dev = port->serial->dev;
retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL);
- spin_unlock_irqrestore(&command_info->lock, flags);
if (retval) {
dbg("%s - submit urb failed", __FUNCTION__);
goto exit;
}
+ spin_unlock_irqrestore(&command_info->lock, flags);
/* wait for the command to complete */
wait_event_interruptible_timeout(command_info->wait_command,
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 1dbb6301d739..9df27f05d21c 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -290,7 +290,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
case MODE_SENSE:
case MODE_SENSE_10:
- length = fst->Count;
+ length = le16_to_cpu(fst->Count);
break;
default:
length = srb->request_bufflen;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 1e0eb58f0c09..27cd9bbdb1ec 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -281,6 +281,14 @@ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Yakumo Mega Image 47
+ * Reported by Bjoern Paetzel <kolrabi@kolrabi.de> */
+UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100,
+ "Tekom Technologies, Inc",
+ "400_CAMERA",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
"Sony",
@@ -447,6 +455,13 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
0 ),
#endif
+/* Reported by Avi Kivity <avi@argo.co.il> */
+UNUSUAL_DEV( 0x05ac, 0x1203, 0x0001, 0x0001,
+ "Apple",
+ "iPod",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
"Lexar",
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 819e211f60be..a86882b84127 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -219,6 +219,7 @@ struct v4l2_pix_format
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
+#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
/*
* F O R M A T E N U M E R A T I O N