Commit 9b4b2fa2 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/usb-2.6
parents 9ba41447 26b1295f
...@@ -9,28 +9,32 @@ ...@@ -9,28 +9,32 @@
Index Index
===== =====
1. Copyright 1. Copyright
2. License 2. Disclaimer
3. Overview 3. License
4. Module dependencies 4. Overview
5. Module loading 5. Driver installation
6. Module parameters 6. Module loading
7. Optional device control through "sysfs" 7. Module parameters
8. Supported devices 8. Optional device control through "sysfs"
9. How to add support for new image sensors 9. Supported devices
10. Notes for V4L2 application developers 10. How to add support for new image sensors
11. Contact information 11. Notes for V4L2 application developers
12. Credits 12. Contact information
13. Credits
1. Copyright 1. Copyright
============ ============
Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>
2. Disclaimer
=============
SONiX is a trademark of SONiX Technology Company Limited, inc. 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 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 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 ...@@ -47,29 +51,52 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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 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 the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC
Camera Controllers. 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 development of this project, despite several requests for enough detailed
specifications of the register tables, compression engine and video data format specifications of the register tables, compression engine and video data format
of the above chips - 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.
The driver relies on the Video4Linux2 and USB core modules. It has been The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well. designed to run properly on SMP systems as well.
The latest version of the SN9C10x driver can be found at the following URL: The latest version of the SN9C10x driver can be found at the following URL:
http://go.lamarinapunto.com/ http://www.linux-projects.org/
Some of the features of the driver are:
4. Module dependencies
- 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 For it to work properly, the driver needs kernel support for Video4Linux and
USB. USB.
...@@ -101,7 +128,7 @@ And finally: ...@@ -101,7 +128,7 @@ And finally:
CONFIG_USB_SN9C102=m CONFIG_USB_SN9C102=m
5. Module loading 6. Module loading
================= =================
To use the driver, it is necessary to load the "sn9c102" module into memory To use the driver, it is necessary to load the "sn9c102" module into memory
after every other module required: "videodev", "usbcore" and, depending on 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". ...@@ -109,7 +136,6 @@ the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
Loading can be done as shown below: Loading can be done as shown below:
[root@localhost home]# modprobe usbcore
[root@localhost home]# modprobe sn9c102 [root@localhost home]# modprobe sn9c102
At this point the devices should be recognized. You can invoke "dmesg" to 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: ...@@ -118,7 +144,7 @@ analyze kernel messages and verify that the loading process has gone well:
[user@localhost home]$ dmesg [user@localhost home]$ dmesg
6. Module parameters 7. Module parameters
==================== ====================
Module parameters are listed below: Module parameters are listed below:
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -144,12 +170,14 @@ Description: Debugging information level, from 0 to 3: ...@@ -144,12 +170,14 @@ Description: Debugging information level, from 0 to 3:
2 = significant informations 2 = significant informations
3 = more verbose messages 3 = more verbose messages
Level 3 is useful for testing only, when only one device 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 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 It is possible to read and write both the SN9C10x and the image sensor
registers by using the "sysfs" filesystem interface. 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. ...@@ -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. 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 None of the names of the companies as well as their products will be mentioned
here. They have never collaborated with me, so no advertising - 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 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 its vendor and product USB identifiers. Below is a list of known identifiers of
...@@ -241,7 +269,7 @@ Vendor ID Product ID ...@@ -241,7 +269,7 @@ Vendor ID Product ID
0x0c45 0x60bc 0x0c45 0x60bc
0x0c45 0x60be 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; until now only the ones that mount the following image sensors are supported;
kernel messages will always tell you whether this is the case: 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 ...@@ -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 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"; 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. 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 If this works, please send an email to the author reporting the kernel
that I can add a new entry in the list of supported devices. 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 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 appreciated. Non-available hardware won't be supported by the author of this
have. 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 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" 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 (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), ...@@ -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). 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 This driver follows the V4L2 API specifications. In particular, it enforces two
rules: rules:
...@@ -301,8 +329,18 @@ factor can be chosen arbitrarily by the "negotiation" of the "source" and ...@@ -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 that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1. 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>. 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 ...@@ -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'. is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
12. Credits 13. Credits
=========== ===========
I would thank the following persons: I would thank the following persons:
......
...@@ -71,12 +71,14 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -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) if (pci_enable_device (dev) < 0)
return -ENODEV; return -ENODEV;
dev->current_state = 0; dev->current_state = 0;
dev->dev.power.power_state = 0;
if (!dev->irq) { if (!dev->irq) {
dev_err (&dev->dev, dev_err (&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n", "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev)); pci_name(dev));
return -ENODEV; retval = -ENODEV;
goto done;
} }
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI 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) ...@@ -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); len = pci_resource_len (dev, 0);
if (!request_mem_region (resource, len, driver->description)) { if (!request_mem_region (resource, len, driver->description)) {
dev_dbg (&dev->dev, "controller already in use\n"); dev_dbg (&dev->dev, "controller already in use\n");
return -EBUSY; retval = -EBUSY;
goto done;
} }
base = ioremap_nocache (resource, len); base = ioremap_nocache (resource, len);
if (base == NULL) { if (base == NULL) {
...@@ -95,7 +98,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -95,7 +98,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
release_mem_region (resource, len); release_mem_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n", dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval); pci_name(dev), retval);
return retval; goto done;
} }
} else { // UHCI } else { // UHCI
...@@ -112,7 +115,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -112,7 +115,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
} }
if (region == PCI_ROM_RESOURCE) { if (region == PCI_ROM_RESOURCE) {
dev_dbg (&dev->dev, "no i/o regions available\n"); dev_dbg (&dev->dev, "no i/o regions available\n");
return -EBUSY; retval = -EBUSY;
goto done;
} }
base = (void __iomem *) resource; base = (void __iomem *) resource;
} }
...@@ -132,7 +136,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -132,7 +136,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
release_region (resource, len); release_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n", dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval); pci_name(dev), retval);
return retval; goto done;
} }
} }
// hcd zeroed everything // hcd zeroed everything
...@@ -200,6 +204,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -200,6 +204,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
usb_hcd_pci_remove (dev); usb_hcd_pci_remove (dev);
} }
done:
if (retval != 0)
pci_disable_device (dev);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_hcd_pci_probe); EXPORT_SYMBOL (usb_hcd_pci_probe);
...@@ -297,82 +304,78 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) ...@@ -297,82 +304,78 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
state = 4; state = 4;
switch (hcd->state) { 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) /* entry if root hub wasn't yet suspended ... from sysfs,
dev->dev.power.power_state = state; * without autosuspend, or if USB_SUSPEND isn't configured.
else */
dev_dbg (hcd->self.controller, case USB_STATE_RUNNING:
"re-suspend fail, %d\n", retval); hcd->state = USB_STATE_QUIESCING;
break;
default:
retval = hcd->driver->suspend (hcd, state); retval = hcd->driver->suspend (hcd, state);
if (retval) if (retval) {
dev_dbg (hcd->self.controller, dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n", "suspend fail, retval %d\n",
retval); retval);
else { break;
}
hcd->state = HCD_STATE_SUSPENDED; hcd->state = HCD_STATE_SUSPENDED;
pci_save_state (dev); /* 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); pci_disable_device (dev);
free_irq (hcd->irq, hcd); free_irq (hcd->irq, hcd);
}
if (has_pci_pm) { if (!has_pci_pm) {
retval = pci_set_power_state (dev, state); dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
break;
}
/* POLICY: ignore D1/D2/D3hot differences; /* POLICY: ignore D1/D2/D3hot differences;
* we know D3hot will always work. * we know D3hot will always work.
*/ */
retval = pci_set_power_state (dev, state);
if (retval < 0 && state < 3) { if (retval < 0 && state < 3) {
retval = pci_set_power_state (dev, 3); retval = pci_set_power_state (dev, 3);
if (retval == 0) if (retval == 0)
state = 3; state = 3;
} }
if (retval == 0) { if (retval == 0) {
dev->dev.power.power_state = state; dev_dbg (hcd->self.controller, "--> PCI %s\n",
pci_state(dev->current_state));
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, state, pci_enable_wake (dev, state, hcd->remote_wakeup);
hcd->remote_wakeup); pci_enable_wake (dev, 4, hcd->remote_wakeup);
pci_enable_wake (dev, 4,
hcd->remote_wakeup);
#endif #endif
} } else if (retval < 0) {
} else { dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
if (state > 3) pci_state(state), retval);
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); (void) usb_hcd_pci_resume (dev);
} else { break;
dev_dbg(hcd->self.controller,
"suspended to PCI %s%s\n",
pci_state(dev->current_state),
has_pci_pm ? "" : " (legacy)");
}
} }
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; return retval;
} }
EXPORT_SYMBOL (usb_hcd_pci_suspend); EXPORT_SYMBOL (usb_hcd_pci_suspend);
...@@ -390,6 +393,11 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -390,6 +393,11 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int has_pci_pm; int has_pci_pm;
hcd = pci_get_drvdata(dev); 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); has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
/* D3cold resume isn't usually reported this way... */ /* D3cold resume isn't usually reported this way... */
...@@ -397,11 +405,6 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -397,11 +405,6 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
pci_state(dev->current_state), pci_state(dev->current_state),
has_pci_pm ? "" : " (legacy)"); 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; hcd->state = USB_STATE_RESUMING;
if (has_pci_pm) if (has_pci_pm)
......
...@@ -479,6 +479,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -479,6 +479,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* /*
* Root Hub interrupt transfers are synthesized with a timer. * Root Hub interrupt transfers are synthesized with a timer.
* Completions are called in_interrupt() but not in_irq(). * 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); static void rh_report_status (unsigned long ptr);
...@@ -488,10 +493,7 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) ...@@ -488,10 +493,7 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8); int len = 1 + (urb->dev->maxchild / 8);
/* rh_timer protected by hcd_data_lock */ /* rh_timer protected by hcd_data_lock */
if (hcd->rh_timer.data if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
|| urb->status != -EINPROGRESS
|| urb->transfer_buffer_length < len
|| !HCD_IS_RUNNING (hcd->state)) {
dev_dbg (hcd->self.controller, dev_dbg (hcd->self.controller,
"not queuing rh status urb, stat %d\n", "not queuing rh status urb, stat %d\n",
urb->status); urb->status);
...@@ -530,19 +532,19 @@ static void rh_report_status (unsigned long ptr) ...@@ -530,19 +532,19 @@ static void rh_report_status (unsigned long ptr)
return; 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 */ /* complete the status urb, or retrigger the timer */
spin_lock (&hcd_data_lock); spin_lock (&hcd_data_lock);
if (urb->dev->state == USB_STATE_CONFIGURED) {
length = hcd->driver->hub_status_data (
hcd, urb->transfer_buffer);
if (length > 0) { if (length > 0) {
hcd->rh_timer.data = 0; hcd->rh_timer.data = 0;
urb->actual_length = length; urb->actual_length = length;
urb->status = 0; urb->status = 0;
urb->hcpriv = NULL; urb->hcpriv = NULL;
} else if (!urb->dev->dev.power.power_state) } else
mod_timer (&hcd->rh_timer, jiffies + HZ/4); mod_timer (&hcd->rh_timer, jiffies + HZ/4);
}
spin_unlock (&hcd_data_lock); spin_unlock (&hcd_data_lock);
spin_unlock (&urb->lock); spin_unlock (&urb->lock);
...@@ -1103,13 +1105,17 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1103,13 +1105,17 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
spin_lock_irqsave (&hcd_data_lock, flags); spin_lock_irqsave (&hcd_data_lock, flags);
if (unlikely (urb->reject)) if (unlikely (urb->reject))
status = -EPERM; status = -EPERM;
else if (HCD_IS_RUNNING (hcd->state) && else switch (hcd->state) {
hcd->state != USB_STATE_QUIESCING) { case USB_STATE_RUNNING:
case USB_STATE_RESUMING:
usb_get_dev (urb->dev); usb_get_dev (urb->dev);
list_add_tail (&urb->urb_list, &dev->urb_list); list_add_tail (&urb->urb_list, &dev->urb_list);
status = 0; status = 0;
} else break;
default:
status = -ESHUTDOWN; status = -ESHUTDOWN;
break;
}
spin_unlock_irqrestore (&hcd_data_lock, flags); spin_unlock_irqrestore (&hcd_data_lock, flags);
if (status) { if (status) {
INIT_LIST_HEAD (&urb->urb_list); INIT_LIST_HEAD (&urb->urb_list);
......
...@@ -1373,7 +1373,10 @@ static int hub_port_reset(struct usb_device *hdev, int port, ...@@ -1373,7 +1373,10 @@ static int hub_port_reset(struct usb_device *hdev, int port,
status = hub_port_wait_reset(hdev, port, udev, delay); status = hub_port_wait_reset(hdev, port, udev, delay);
/* return on disconnect or reset */ /* return on disconnect or reset */
if (status == -ENOTCONN || status == 0) { switch (status) {
case 0:
case -ENOTCONN:
case -ENODEV:
clear_port_feature(hdev, clear_port_feature(hdev,
port + 1, USB_PORT_FEAT_C_RESET); port + 1, USB_PORT_FEAT_C_RESET);
/* FIXME need disconnect() for NOTATTACHED device */ /* FIXME need disconnect() for NOTATTACHED device */
...@@ -1524,7 +1527,7 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state) ...@@ -1524,7 +1527,7 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
if (port < 0) if (port < 0)
return port; return port;
if (udev->dev.power.power_state if (udev->state == USB_STATE_SUSPENDED
|| udev->state == USB_STATE_NOTATTACHED) { || udev->state == USB_STATE_NOTATTACHED) {
return 0; return 0;
} }
...@@ -1595,16 +1598,16 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state) ...@@ -1595,16 +1598,16 @@ int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
*/ */
if (!udev->parent) { if (!udev->parent) {
struct usb_bus *bus = udev->bus; struct usb_bus *bus = udev->bus;
if (bus && bus->op->hub_suspend) if (bus && bus->op->hub_suspend) {
status = bus->op->hub_suspend (bus); status = bus->op->hub_suspend (bus);
else if (status == 0)
usb_set_device_state(udev,
USB_STATE_SUSPENDED);
} else
status = -EOPNOTSUPP; status = -EOPNOTSUPP;
} else } else
status = hub_port_suspend(udev->parent, port); status = hub_port_suspend(udev->parent, port);
if (status == 0)
udev->dev.power.power_state = PM_SUSPEND_MEM;
up(&udev->serialize);
return status; return status;
} }
EXPORT_SYMBOL(__usb_suspend_device); EXPORT_SYMBOL(__usb_suspend_device);
...@@ -1652,7 +1655,6 @@ static int finish_port_resume(struct usb_device *udev) ...@@ -1652,7 +1655,6 @@ static int finish_port_resume(struct usb_device *udev)
/* caller owns the udev device lock */ /* caller owns the udev device lock */
dev_dbg(&udev->dev, "usb resume\n"); 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 /* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the * state the device resumes to. Linux currently won't see the
...@@ -1809,14 +1811,15 @@ int usb_resume_device(struct usb_device *udev) ...@@ -1809,14 +1811,15 @@ int usb_resume_device(struct usb_device *udev)
*/ */
if (!udev->parent) { if (!udev->parent) {
struct usb_bus *bus = udev->bus; struct usb_bus *bus = udev->bus;
if (bus && bus->op->hub_resume) if (bus && bus->op->hub_resume) {
status = bus->op->hub_resume (bus); status = bus->op->hub_resume (bus);
else } else
status = -EOPNOTSUPP; status = -EOPNOTSUPP;
if (status == 0) { if (status == 0) {
/* TRSMRCY = 10 msec */ /* TRSMRCY = 10 msec */
msleep(10); msleep(10);
status = hub_resume (bus->root_hub usb_set_device_state (udev, USB_STATE_CONFIGURED);
status = hub_resume (udev
->actconfig->interface[0]); ->actconfig->interface[0]);
} }
} else if (udev->state == USB_STATE_SUSPENDED) { } else if (udev->state == USB_STATE_SUSPENDED) {
...@@ -1824,7 +1827,6 @@ int usb_resume_device(struct usb_device *udev) ...@@ -1824,7 +1827,6 @@ int usb_resume_device(struct usb_device *udev)
status = hub_port_resume(udev->parent, port); status = hub_port_resume(udev->parent, port);
} else { } else {
status = 0; status = 0;
udev->dev.power.power_state = PM_SUSPEND_ON;
} }
if (status < 0) { if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", dev_dbg(&udev->dev, "can't resume, status %d\n",
......
...@@ -1395,10 +1395,6 @@ static int usb_generic_suspend(struct device *dev, u32 state) ...@@ -1395,10 +1395,6 @@ static int usb_generic_suspend(struct device *dev, u32 state)
struct usb_interface *intf; struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
/* there's only one USB suspend state */
if (dev->power.power_state)
return 0;
if (dev->driver == &usb_generic_driver) if (dev->driver == &usb_generic_driver)
return usb_suspend_device (to_usb_device(dev), state); return usb_suspend_device (to_usb_device(dev), state);
...@@ -1409,6 +1405,10 @@ static int usb_generic_suspend(struct device *dev, u32 state) ...@@ -1409,6 +1405,10 @@ static int usb_generic_suspend(struct device *dev, u32 state)
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver); driver = to_usb_driver(dev->driver);
/* there's only one USB suspend state */
if (intf->dev.power.power_state)
return 0;
if (driver->suspend) if (driver->suspend)
return driver->suspend(intf, state); return driver->suspend(intf, state);
return 0; return 0;
......
...@@ -3579,7 +3579,7 @@ static ssize_t show_file(struct device *dev, char *buf) ...@@ -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; ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev); struct lun *curlun = dev_to_lun(dev);
...@@ -3603,7 +3603,7 @@ ssize_t store_ro(struct device *dev, const char *buf, size_t count) ...@@ -3603,7 +3603,7 @@ ssize_t store_ro(struct device *dev, const char *buf, size_t count)
return rc; 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 lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
......
...@@ -1275,7 +1275,7 @@ int rndis_rm_hdr (u8 *buf, u32 *length) ...@@ -1275,7 +1275,7 @@ int rndis_rm_hdr (u8 *buf, u32 *length)
#ifdef CONFIG_USB_GADGET_DEBUG_FILES #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) void *data)
{ {
char *out = page; char *out = page;
...@@ -1320,7 +1320,7 @@ int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, ...@@ -1320,7 +1320,7 @@ int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
return len; 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) unsigned long count, void *data)
{ {
rndis_params *p = data; rndis_params *p = data;
......
...@@ -172,13 +172,6 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) ...@@ -172,13 +172,6 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
return -ETIMEDOUT; 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) */ /* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci) static int ehci_halt (struct ehci_hcd *ehci)
{ {
...@@ -480,8 +473,8 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -480,8 +473,8 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->async->hw_qtd_next = EHCI_LIST_END; ehci->async->hw_qtd_next = EHCI_LIST_END;
ehci->async->qh_state = QH_STATE_LINKED; ehci->async->qh_state = QH_STATE_LINKED;
ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma); 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 (!!!) * hcc_params controls whether ehci->regs->segment must (!!!)
...@@ -540,7 +533,6 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -540,7 +533,6 @@ static int ehci_start (struct usb_hcd *hcd)
} }
udev->speed = USB_SPEED_HIGH; udev->speed = USB_SPEED_HIGH;
udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED; 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 * 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) ...@@ -663,20 +655,19 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
if (hcd->self.root_hub->dev.power.power_state) if (time_before (jiffies, ehci->next_statechange))
return 0;
while (time_before (jiffies, ehci->next_statechange))
msleep (100); msleep (100);
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub, state); (void) usb_suspend_device (hcd->self.root_hub, state);
#else #else
/* FIXME lock root hub */ usb_lock_device (hcd->self.root_hub);
(void) ehci_hub_suspend (hcd); (void) ehci_hub_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif #endif
// save (PCI) FLADJ in case of Vaux power loss // save (PCI) FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew
return 0; return 0;
} }
...@@ -687,10 +678,11 @@ static int ehci_resume (struct usb_hcd *hcd) ...@@ -687,10 +678,11 @@ static int ehci_resume (struct usb_hcd *hcd)
unsigned port; unsigned port;
struct usb_device *root = hcd->self.root_hub; struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL; int retval = -EINVAL;
int powerup = 0;
// maybe restore (PCI) FLADJ // maybe restore (PCI) FLADJ
while (time_before (jiffies, ehci->next_statechange)) if (time_before (jiffies, ehci->next_statechange))
msleep (100); msleep (100);
/* If any port is suspended, we know we can/must resume the HC. */ /* 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) ...@@ -704,6 +696,8 @@ static int ehci_resume (struct usb_hcd *hcd)
up (&hcd->self.root_hub->serialize); up (&hcd->self.root_hub->serialize);
break; break;
} }
if ((status & PORT_POWER) == 0)
powerup = 1;
if (!root->children [port]) if (!root->children [port])
continue; continue;
dbg_port (ehci, __FUNCTION__, port + 1, status); dbg_port (ehci, __FUNCTION__, port + 1, status);
...@@ -728,9 +722,20 @@ static int ehci_resume (struct usb_hcd *hcd) ...@@ -728,9 +722,20 @@ static int ehci_resume (struct usb_hcd *hcd)
/* restart; khubd will disconnect devices */ /* restart; khubd will disconnect devices */
retval = ehci_start (hcd); 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; return retval;
} }
......
...@@ -33,24 +33,19 @@ ...@@ -33,24 +33,19 @@
static int ehci_hub_suspend (struct usb_hcd *hcd) static int ehci_hub_suspend (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
int port; int port;
if (root->dev.power.power_state != 0)
return 0;
if (time_before (jiffies, ehci->next_statechange)) if (time_before (jiffies, ehci->next_statechange))
return -EAGAIN; msleep(5);
port = HCS_N_PORTS (ehci->hcs_params); port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock); 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 */ /* stop schedules, clean any completed work */
if (HCD_IS_RUNNING(hcd->state)) if (HCD_IS_RUNNING(hcd->state)) {
ehci_quiesce (ehci); ehci_quiesce (ehci);
ehci->hcd.state = USB_STATE_QUIESCING;
}
ehci->command = readl (&ehci->regs->command); ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim) if (ehci->reclaim)
ehci->reclaim_ready = 1; ehci->reclaim_ready = 1;
...@@ -78,6 +73,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -78,6 +73,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
/* turn off now-idle HC */ /* turn off now-idle HC */
ehci_halt (ehci); ehci_halt (ehci);
ehci->hcd.state = HCD_STATE_SUSPENDED;
ehci->next_statechange = jiffies + msecs_to_jiffies(10); ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock); spin_unlock_irq (&ehci->lock);
...@@ -89,27 +85,27 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -89,27 +85,27 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
static int ehci_hub_resume (struct usb_hcd *hcd) static int ehci_hub_resume (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
u32 temp; u32 temp;
int i; int i;
int intr_enable;
if (!root->dev.power.power_state)
return 0;
if (time_before (jiffies, ehci->next_statechange)) 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 */ /* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) { if (readl (&ehci->regs->intr_enable) == 0) {
temp = 1; /* at least some APM implementations will try to deliver
writel (INTR_MASK, &ehci->regs->intr_enable); * IRQs right away, so delay them until we're ready.
*/
intr_enable = 1;
writel (0, &ehci->regs->segment); writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list); writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* FIXME will this work even if (pci) vAUX was lost? */
} else } else
temp = 0; intr_enable = 0;
ehci_dbg(ehci, "resume root hub%s\n", 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 */ /* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command); writel (ehci->command, &ehci->regs->command);
...@@ -148,9 +144,14 @@ static int ehci_hub_resume (struct usb_hcd *hcd) ...@@ -148,9 +144,14 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
writel (ehci->command, &ehci->regs->command); writel (ehci->command, &ehci->regs->command);
} }
root->dev.power.power_state = 0;
ehci->next_statechange = jiffies + msecs_to_jiffies(5); ehci->next_statechange = jiffies + msecs_to_jiffies(5);
ehci->hcd.state = USB_STATE_RUNNING; 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; return 0;
} }
...@@ -210,6 +211,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -210,6 +211,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
int ports, i, retval = 1; int ports, i, retval = 1;
unsigned long flags; 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 */ /* init status to no-changes */
buf [0] = 0; buf [0] = 0;
ports = HCS_N_PORTS (ehci->hcs_params); ports = HCS_N_PORTS (ehci->hcs_params);
...@@ -246,6 +251,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -246,6 +251,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
status = STS_PCD; status = STS_PCD;
} }
} }
/* FIXME autosuspend idle root hubs */
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
return status ? retval : 0; return status ? retval : 0;
} }
......
...@@ -908,6 +908,7 @@ itd_urb_transaction ( ...@@ -908,6 +908,7 @@ itd_urb_transaction (
if (unlikely (0 == itd)) { if (unlikely (0 == itd)) {
iso_sched_free (stream, sched); iso_sched_free (stream, sched);
spin_unlock_irqrestore (&ehci->lock, flags);
return -ENOMEM; return -ENOMEM;
} }
memset (itd, 0, sizeof *itd); memset (itd, 0, sizeof *itd);
......
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
#include <asm/byteorder.h> #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_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
...@@ -657,8 +657,6 @@ static int ohci_run (struct ohci_hcd *ohci) ...@@ -657,8 +657,6 @@ static int ohci_run (struct ohci_hcd *ohci)
udev = hcd_to_bus (&ohci->hcd)->root_hub; udev = hcd_to_bus (&ohci->hcd)->root_hub;
if (udev) { if (udev) {
udev->dev.power.power_state = 0;
usb_set_device_state (udev, USB_STATE_CONFIGURED);
return 0; return 0;
} }
...@@ -799,6 +797,7 @@ static int ohci_restart (struct ohci_hcd *ohci) ...@@ -799,6 +797,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
int temp; int temp;
int i; int i;
struct urb_priv *priv; struct urb_priv *priv;
struct usb_device *root = ohci->hcd.self.root_hub;
/* mark any devices gone, so they do nothing till khubd disconnects. /* mark any devices gone, so they do nothing till khubd disconnects.
* recycle any "live" eds/tds (and urbs) right away. * recycle any "live" eds/tds (and urbs) right away.
...@@ -807,7 +806,11 @@ static int ohci_restart (struct ohci_hcd *ohci) ...@@ -807,7 +806,11 @@ static int ohci_restart (struct ohci_hcd *ohci)
*/ */
spin_lock_irq(&ohci->lock); spin_lock_irq(&ohci->lock);
disable (ohci); 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)) if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n"); ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) { list_for_each_entry (priv, &ohci->pending, pending) {
...@@ -864,7 +867,6 @@ static int ohci_restart (struct ohci_hcd *ohci) ...@@ -864,7 +867,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
ohci_writel (ohci, RH_PS_PSS, ohci_writel (ohci, RH_PS_PSS,
&ohci->regs->roothub.portstatus [temp]); &ohci->regs->roothub.portstatus [temp]);
ohci_dbg (ohci, "restart complete\n"); ohci_dbg (ohci, "restart complete\n");
ohci->hcd.state = USB_STATE_RUNNING;
} }
return 0; return 0;
} }
......
...@@ -48,15 +48,10 @@ static int ohci_restart (struct ohci_hcd *ohci); ...@@ -48,15 +48,10 @@ static int ohci_restart (struct ohci_hcd *ohci);
static int ohci_hub_suspend (struct usb_hcd *hcd) static int ohci_hub_suspend (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
int status = 0; int status = 0;
unsigned long flags;
if (root->dev.power.power_state != 0) spin_lock_irqsave (&ohci->lock, flags);
return 0;
if (time_before (jiffies, ohci->next_statechange))
return -EAGAIN;
spin_lock_irq (&ohci->lock);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) { switch (ohci->hc_control & OHCI_CTRL_HCFS) {
...@@ -72,8 +67,8 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ...@@ -72,8 +67,8 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
ohci_dbg (ohci, "needs reinit!\n"); ohci_dbg (ohci, "needs reinit!\n");
goto done; goto done;
case OHCI_USB_SUSPEND: case OHCI_USB_SUSPEND:
ohci_dbg (ohci, "already suspended?\n"); ohci_dbg (ohci, "already suspended\n");
goto succeed; goto done;
} }
ohci_dbg (ohci, "suspend root hub\n"); ohci_dbg (ohci, "suspend root hub\n");
...@@ -122,14 +117,10 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ...@@ -122,14 +117,10 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
/* no resumes until devices finish suspending */ /* no resumes until devices finish suspending */
ohci->next_statechange = jiffies + msecs_to_jiffies (5); 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: done:
spin_unlock_irq (&ohci->lock); if (status == 0)
ohci->hcd.state = HCD_STATE_SUSPENDED;
spin_unlock_irqrestore (&ohci->lock, flags);
return status; return status;
} }
...@@ -145,22 +136,26 @@ static inline struct ed *find_head (struct ed *ed) ...@@ -145,22 +136,26 @@ static inline struct ed *find_head (struct ed *ed)
static int ohci_hub_resume (struct usb_hcd *hcd) static int ohci_hub_resume (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
u32 temp, enables; u32 temp, enables;
int status = -EINPROGRESS; int status = -EINPROGRESS;
if (!root->dev.power.power_state)
return 0;
if (time_before (jiffies, ohci->next_statechange)) if (time_before (jiffies, ohci->next_statechange))
return -EAGAIN; msleep(5);
spin_lock_irq (&ohci->lock); spin_lock_irq (&ohci->lock);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
/* this can happen after suspend-to-disk */ /* this can happen after suspend-to-disk */
if (hcd->state == USB_STATE_RESUMING) {
ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
ohci->hc_control); ohci->hc_control);
status = -EBUSY; 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) { } else switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_SUSPEND: case OHCI_USB_SUSPEND:
ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
...@@ -175,7 +170,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ...@@ -175,7 +170,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
break; break;
case OHCI_USB_OPER: case OHCI_USB_OPER:
ohci_dbg (ohci, "odd resume\n"); ohci_dbg (ohci, "odd resume\n");
root->dev.power.power_state = 0;
status = 0; status = 0;
break; break;
default: /* RESET, we lost power */ default: /* RESET, we lost power */
...@@ -245,8 +239,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ...@@ -245,8 +239,6 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
/* TRSMRCY */ /* TRSMRCY */
msleep (10); msleep (10);
root->dev.power.power_state = 0;
usb_set_device_state (root, USB_STATE_CONFIGURED);
/* keep it alive for ~5x suspend + resume costs */ /* keep it alive for ~5x suspend + resume costs */
ohci->next_statechange = jiffies + msecs_to_jiffies (250); ohci->next_statechange = jiffies + msecs_to_jiffies (250);
...@@ -315,10 +307,12 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -315,10 +307,12 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
int ports, i, changed = 0, length = 1; int ports, i, changed = 0, length = 1;
int can_suspend = 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; ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) { 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_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */ /* retry later; "should not happen" */
...@@ -362,6 +356,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -362,6 +356,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* save power by suspending idle root hubs; /* save power by suspending idle root hubs;
* INTR_RD wakes us when there's work * 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 if (can_suspend
&& !changed && !changed
...@@ -369,6 +364,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -369,6 +364,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
& ohci->hc_control) & ohci->hc_control)
== OHCI_USB_OPER == OHCI_USB_OPER
&& time_after (jiffies, ohci->next_statechange)
&& usb_trylock_device (hcd->self.root_hub) && usb_trylock_device (hcd->self.root_hub)
) { ) {
ohci_vdbg (ohci, "autosuspend\n"); ohci_vdbg (ohci, "autosuspend\n");
...@@ -409,7 +405,7 @@ ohci_hub_descriptor ( ...@@ -409,7 +405,7 @@ ohci_hub_descriptor (
temp |= 0x0010; temp |= 0x0010;
else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
temp |= 0x0008; 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 */ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
rh = roothub_b (ohci); rh = roothub_b (ohci);
...@@ -475,7 +471,7 @@ static void start_hnp(struct ohci_hcd *ohci); ...@@ -475,7 +471,7 @@ static void start_hnp(struct ohci_hcd *ohci);
/* called from some task, normally khubd */ /* called from some task, normally khubd */
static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) 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; u32 temp;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC; u16 reset_done = now + PORT_RESET_MSEC;
......
...@@ -106,7 +106,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -106,7 +106,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
/* suspend root hub, hoping it keeps power during suspend */ /* 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); msleep (100);
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_USB_SUSPEND
...@@ -154,7 +154,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -154,7 +154,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#endif #endif
/* resume root hub */ /* resume root hub */
while (time_before (jiffies, ohci->next_statechange)) if (time_before (jiffies, ohci->next_statechange))
msleep (100); msleep (100);
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_USB_SUSPEND
/* get extra cleanup even if remote wakeup isn't in use */ /* get extra cleanup even if remote wakeup isn't in use */
...@@ -166,7 +166,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -166,7 +166,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#endif #endif
if (retval == 0) { if (retval == 0) {
hcd->self.controller->power.power_state = 0;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac) if (_machine == _MACH_Pmac)
enable_irq (to_pci_dev(hcd->self.controller)->irq); enable_irq (to_pci_dev(hcd->self.controller)->irq);
......
...@@ -510,7 +510,7 @@ static inline void ohci_writel (const struct ohci_hcd *ohci, ...@@ -510,7 +510,7 @@ static inline void ohci_writel (const struct ohci_hcd *ohci,
/* cpu to ohci */ /* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) 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) 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) ...@@ -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) 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) 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) ...@@ -531,22 +531,22 @@ static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
/* ohci to cpu */ /* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) 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) 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) 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) 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);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/param.h> #include <linux/param.h>
...@@ -45,7 +46,8 @@ ...@@ -45,7 +46,8 @@
#define SN9C102_URBS 2 #define SN9C102_URBS 2
#define SN9C102_ISO_PACKETS 7 #define SN9C102_ISO_PACKETS 7
#define SN9C102_ALTERNATE_SETTING 8 #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 @@ ...@@ -53,8 +55,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL" #define SN9C102_MODULE_LICENSE "GPL"
#define SN9C102_MODULE_VERSION "1:1.12" #define SN9C102_MODULE_VERSION "1:1.19"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 12) #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 19)
enum sn9c102_bridge { enum sn9c102_bridge {
BRIDGE_SN9C101 = 0x01, BRIDGE_SN9C101 = 0x01,
...@@ -100,7 +102,7 @@ enum sn9c102_stream_state { ...@@ -100,7 +102,7 @@ enum sn9c102_stream_state {
}; };
struct sn9c102_sysfs_attr { struct sn9c102_sysfs_attr {
u8 reg, val, i2c_reg, i2c_val; u8 reg, i2c_reg;
}; };
static DECLARE_MUTEX(sn9c102_sysfs_lock); static DECLARE_MUTEX(sn9c102_sysfs_lock);
...@@ -121,11 +123,13 @@ struct sn9c102_device { ...@@ -121,11 +123,13 @@ struct sn9c102_device {
struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
struct list_head inqueue, outqueue; struct list_head inqueue, outqueue;
u32 frame_count, nbuffers; u32 frame_count, nbuffers, nreadbuffers;
enum sn9c102_io_method io; enum sn9c102_io_method io;
enum sn9c102_stream_state stream; enum sn9c102_stream_state stream;
struct v4l2_jpegcompression compression;
struct sn9c102_sysfs_attr sysfs; struct sn9c102_sysfs_attr sysfs;
u16 reg[32]; u16 reg[32];
......
This diff is collapsed.
/*************************************************************************** /***************************************************************************
* Driver for PAS106B image sensor connected to the SN9C10x PC Camera * * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
* Controllers * * Controllers *
* * * *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> * * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
...@@ -38,14 +38,9 @@ static int pas106b_init(struct sn9c102_device* cam) ...@@ -38,14 +38,9 @@ static int pas106b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x09, 0x18); err += sn9c102_write_reg(cam, 0x09, 0x18);
err += sn9c102_i2c_write(cam, 0x02, 0x0c); 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, 0x05, 0x5a);
err += sn9c102_i2c_write(cam, 0x06, 0x88); err += sn9c102_i2c_write(cam, 0x06, 0x88);
err += sn9c102_i2c_write(cam, 0x07, 0x80); 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, 0x10, 0x06);
err += sn9c102_i2c_write(cam, 0x11, 0x06); err += sn9c102_i2c_write(cam, 0x11, 0x06);
err += sn9c102_i2c_write(cam, 0x12, 0x00); err += sn9c102_i2c_write(cam, 0x12, 0x00);
...@@ -62,6 +57,15 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam, ...@@ -62,6 +57,15 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl) struct v4l2_control* ctrl)
{ {
switch (ctrl->id) { 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: case V4L2_CID_RED_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
return -EIO; return -EIO;
...@@ -77,16 +81,26 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam, ...@@ -77,16 +81,26 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
return -EIO; return -EIO;
ctrl->value &= 0x1f; ctrl->value &= 0x1f;
return 0; 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: case V4L2_CID_CONTRAST:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
return -EIO; return -EIO;
ctrl->value &= 0x07; ctrl->value &= 0x07;
return 0; 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: default:
return -EINVAL; return -EINVAL;
} }
...@@ -99,6 +113,10 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam, ...@@ -99,6 +113,10 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
int err = 0; int err = 0;
switch (ctrl->id) { 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: case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
break; break;
...@@ -108,12 +126,23 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam, ...@@ -108,12 +126,23 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_GAIN: case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
break; break;
case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x0d, 0x1f - ctrl->value);
break;
case V4L2_CID_CONTRAST: case V4L2_CID_CONTRAST:
err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
break; 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: default:
return -EINVAL; return -EINVAL;
} }
...@@ -147,6 +176,36 @@ static struct sn9c102_sensor pas106b = { ...@@ -147,6 +176,36 @@ static struct sn9c102_sensor pas106b = {
.slave_write_id = 0x40, .slave_write_id = 0x40,
.init = &pas106b_init, .init = &pas106b_init,
.qctrl = { .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, .id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
...@@ -168,33 +227,33 @@ static struct sn9c102_sensor pas106b = { ...@@ -168,33 +227,33 @@ static struct sn9c102_sensor pas106b = {
.flags = 0, .flags = 0,
}, },
{ {
.id = V4L2_CID_GAIN, .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain", .name = "green balance",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x1f, .maximum = 0x3e,
.step = 0x01, .step = 0x02,
.default_value = 0x0d, .default_value = 0x02,
.flags = 0, .flags = 0,
}, },
{ {
.id = V4L2_CID_BRIGHTNESS, .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "brightness", .name = "DAC magnitude",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x1f, .maximum = 0x1f,
.step = 0x01, .step = 0x01,
.default_value = 0x1f, .default_value = 0x01,
.flags = 0, .flags = 0,
}, },
{ {
.id = V4L2_CID_CONTRAST, .id = SN9C102_V4L2_CID_DAC_SIGN,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "contrast", .name = "DAC sign",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x07, .maximum = 0x01,
.step = 0x01, .step = 0x01,
.default_value = 0x00, /* 0x00~0x03 have same effect */ .default_value = 0x00,
.flags = 0, .flags = 0,
}, },
}, },
......
/*************************************************************************** /***************************************************************************
* Driver for PAS202BCB image sensor connected to the SN9C10x PC Camera * * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera *
* Controllers * * Controllers *
* * * *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> * * <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
...@@ -41,14 +44,10 @@ static int pas202bcb_init(struct sn9c102_device* cam) ...@@ -41,14 +44,10 @@ static int pas202bcb_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x02, 0x14); err += sn9c102_i2c_write(cam, 0x02, 0x14);
err += sn9c102_i2c_write(cam, 0x03, 0x40); 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, 0x0d, 0x2c);
err += sn9c102_i2c_write(cam, 0x0e, 0x01); err += sn9c102_i2c_write(cam, 0x0e, 0x01);
err += sn9c102_i2c_write(cam, 0x0f, 0xa9); err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
err += sn9c102_i2c_write(cam, 0x10, 0x08); 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, 0x13, 0x63);
err += sn9c102_i2c_write(cam, 0x15, 0x70); err += sn9c102_i2c_write(cam, 0x15, 0x70);
err += sn9c102_i2c_write(cam, 0x11, 0x01); err += sn9c102_i2c_write(cam, 0x11, 0x01);
...@@ -63,6 +62,15 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam, ...@@ -63,6 +62,15 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl) struct v4l2_control* ctrl)
{ {
switch (ctrl->id) { 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: case V4L2_CID_RED_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
return -EIO; return -EIO;
...@@ -78,11 +86,20 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam, ...@@ -78,11 +86,20 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
return -EIO; return -EIO;
ctrl->value &= 0x1f; ctrl->value &= 0x1f;
return 0; return 0;
case V4L2_CID_BRIGHTNESS: case SN9C102_V4L2_CID_GREEN_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0) if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
return -EIO; return -EIO;
ctrl->value &= 0x0f; ctrl->value &= 0x0f;
return 0; 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: default:
return -EINVAL; return -EINVAL;
} }
...@@ -95,6 +112,10 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam, ...@@ -95,6 +112,10 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
int err = 0; int err = 0;
switch (ctrl->id) { 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: case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value); err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
break; break;
...@@ -104,8 +125,18 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam, ...@@ -104,8 +125,18 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_GAIN: case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x10, ctrl->value); err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break; break;
case V4L2_CID_BRIGHTNESS: case SN9C102_V4L2_CID_GREEN_BALANCE:
err += sn9c102_i2c_write(cam, 0x06, 0x0f - ctrl->value); 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; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -141,6 +172,26 @@ static struct sn9c102_sensor pas202bcb = { ...@@ -141,6 +172,26 @@ static struct sn9c102_sensor pas202bcb = {
.slave_write_id = 0x40, .slave_write_id = 0x40,
.init = &pas202bcb_init, .init = &pas202bcb_init,
.qctrl = { .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, .id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
...@@ -162,23 +213,33 @@ static struct sn9c102_sensor pas202bcb = { ...@@ -162,23 +213,33 @@ static struct sn9c102_sensor pas202bcb = {
.flags = 0, .flags = 0,
}, },
{ {
.id = V4L2_CID_GAIN, .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain", .name = "green balance",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x1f, .maximum = 0x0f,
.step = 0x01, .step = 0x01,
.default_value = 0x0c, .default_value = 0x00,
.flags = 0, .flags = 0,
}, },
{ {
.id = V4L2_CID_BRIGHTNESS, .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "brightness", .name = "DAC magnitude",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x0f, .maximum = 0xff,
.step = 0x01,
.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, .step = 0x01,
.default_value = 0x0f, .default_value = 0x01,
.flags = 0, .flags = 0,
}, },
}, },
......
...@@ -98,7 +98,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \ ...@@ -98,7 +98,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \
{ USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
{ USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
{ USB_DEVICE(0x0c45, 0x602a), }, /* HV7131[D|E1] */ \ { 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, 0x602c), }, /* OV7620 */ \
{ USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
{ USB_DEVICE(0x0c45, 0x6080), }, \ { USB_DEVICE(0x0c45, 0x6080), }, \
...@@ -292,21 +292,25 @@ struct sn9c102_sensor { ...@@ -292,21 +292,25 @@ struct sn9c102_sensor {
NOTE: in case, you must program the SN9C10X chip to get rid of 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 blank pixels or blank lines at the _start_ of each line or
frame after each HSYNC or VSYNC, so that the image starts with 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 V_SIZE you don't have to care about blank pixels or blank
lines at the end of each line or frame). lines at the end of each line or frame).
*/ */
struct v4l2_pix_format pix_format; struct v4l2_pix_format pix_format;
/* /*
What you have to define here are: initial 'width' and 'height' of What you have to define here are: 1) initial 'width' and 'height' of
the target rectangle, the bayer 'pixelformat' and 'priv' which we'll the target rectangle 2) the initial 'pixelformat', which can be
be used to indicate the number of bits per pixel, 8 or 9. either V4L2_PIX_FMT_SN9C10X (for compressed video) or
Nothing more. 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 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 of cropcap.defrect.width and cropcap.defrect.height. I
suggest 1/1. 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 rid of any blank pixels, so that the output of the sensor
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
*/ */
...@@ -333,4 +337,11 @@ struct sn9c102_sensor { ...@@ -333,4 +337,11 @@ struct sn9c102_sensor {
struct v4l2_rect _rect; 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_ */ #endif /* _SN9C102_SENSOR_H_ */
/*************************************************************************** /***************************************************************************
* Driver for TAS5110C1B image sensor connected to the SN9C10x PC Camera * * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
* Controllers * * Controllers *
* * * *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> * * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
...@@ -150,7 +150,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) ...@@ -150,7 +150,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */ /* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5110c1b); 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 && if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 &&
tas5110c1b.usbdev->descriptor.idProduct != 0x6005 && tas5110c1b.usbdev->descriptor.idProduct != 0x6005 &&
tas5110c1b.usbdev->descriptor.idProduct != 0x60ab) tas5110c1b.usbdev->descriptor.idProduct != 0x60ab)
......
/*************************************************************************** /***************************************************************************
* Driver for TAS5130D1B image sensor connected to the SN9C10x PC Camera * * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
* Controllers * * Controllers *
* * * *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> * * Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
...@@ -96,8 +96,8 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam, ...@@ -96,8 +96,8 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam,
err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, v_start, 0x13);
/* Do NOT change! */ /* Do NOT change! */
err += sn9c102_write_reg(cam, 0x1d, 0x1a); err += sn9c102_write_reg(cam, 0x1f, 0x1a);
err += sn9c102_write_reg(cam, 0x10, 0x1b); err += sn9c102_write_reg(cam, 0x1a, 0x1b);
err += sn9c102_write_reg(cam, 0xf3, 0x19); err += sn9c102_write_reg(cam, 0xf3, 0x19);
return err; return err;
...@@ -165,7 +165,7 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) ...@@ -165,7 +165,7 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */ /* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5130d1b); 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 && if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025 &&
tas5130d1b.usbdev->descriptor.idProduct != 0x60aa) tas5130d1b.usbdev->descriptor.idProduct != 0x60aa)
return -ENODEV; return -ENODEV;
......
...@@ -170,13 +170,11 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -170,13 +170,11 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
if (result == -ETIMEDOUT) if (result == -ETIMEDOUT)
retries--; retries--;
else if (result < 0) { else if (result < 0) {
err("Error executing ioctrl. code = %d", err("Error executing ioctrl. code = %d", result);
le32_to_cpu(result));
retries = 0; retries = 0;
} else { } else {
dbg("Executed ioctl. Result = %d (data=%04x)", dbg("Executed ioctl. Result = %d (data=%02x)",
le32_to_cpu(result), result, buffer[0]);
le32_to_cpu(*((long *) buffer)));
if (copy_to_user(rio_cmd.buffer, buffer, if (copy_to_user(rio_cmd.buffer, buffer,
rio_cmd.length)) { rio_cmd.length)) {
free_page((unsigned long) buffer); free_page((unsigned long) buffer);
...@@ -239,12 +237,10 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -239,12 +237,10 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
if (result == -ETIMEDOUT) if (result == -ETIMEDOUT)
retries--; retries--;
else if (result < 0) { else if (result < 0) {
err("Error executing ioctrl. code = %d", err("Error executing ioctrl. code = %d", result);
le32_to_cpu(result));
retries = 0; retries = 0;
} else { } else {
dbg("Executed ioctl. Result = %d", dbg("Executed ioctl. Result = %d", result);
le32_to_cpu(result));
retries = 0; retries = 0;
} }
......
...@@ -310,11 +310,11 @@ tiglusb_ioctl (struct inode *inode, struct file *filp, ...@@ -310,11 +310,11 @@ tiglusb_ioctl (struct inode *inode, struct file *filp,
ret = -EIO; ret = -EIO;
break; break;
case IOCTL_TIUSB_GET_MAXPS: 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; return -EFAULT;
break; break;
case IOCTL_TIUSB_GET_DEVID: 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))) sizeof(int)))
return -EFAULT; return -EFAULT;
break; break;
......
...@@ -1355,7 +1355,7 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1355,7 +1355,7 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs)
"iso test, %lu errors\n", "iso test, %lu errors\n",
ctx->errors); ctx->errors);
complete (&ctx->done); complete (&ctx->done);
} else }
done: done:
spin_unlock(&ctx->lock); spin_unlock(&ctx->lock);
} }
...@@ -1457,8 +1457,10 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, ...@@ -1457,8 +1457,10 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
status = usb_submit_urb (urbs [i], SLAB_ATOMIC); status = usb_submit_urb (urbs [i], SLAB_ATOMIC);
if (status < 0) { if (status < 0) {
ERROR (dev, "submit iso[%d], error %d\n", i, status); ERROR (dev, "submit iso[%d], error %d\n", i, status);
if (i == 0) if (i == 0) {
spin_unlock_irq (&context.lock);
goto fail; goto fail;
}
simple_free_urb (urbs [i]); simple_free_urb (urbs [i]);
context.pending--; context.pending--;
......
# #
# USB Network devices configuration # USB Network devices configuration
# #
comment "USB Network adaptors" comment "Networking support is needed for USB Network Adapter support"
depends on USB
comment "Networking support is needed for USB Networking device support"
depends on USB && !NET depends on USB && !NET
menu "USB Network Adapters"
depends on USB && NET
config USB_CATC config USB_CATC
tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
depends on USB && NET && EXPERIMENTAL depends on EXPERIMENTAL
select CRC32 select CRC32
---help--- ---help---
Say Y if you want to use one of the following 10Mbps USB Ethernet Say Y if you want to use one of the following 10Mbps USB Ethernet
...@@ -29,7 +29,6 @@ config USB_CATC ...@@ -29,7 +29,6 @@ config USB_CATC
config USB_KAWETH config USB_KAWETH
tristate "USB KLSI KL5USB101-based ethernet device support" tristate "USB KLSI KL5USB101-based ethernet device support"
depends on USB && NET
---help--- ---help---
Say Y here if you want to use one of the following 10Mbps only Say Y here if you want to use one of the following 10Mbps only
USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
...@@ -69,7 +68,6 @@ config USB_KAWETH ...@@ -69,7 +68,6 @@ config USB_KAWETH
config USB_PEGASUS config USB_PEGASUS
tristate "USB Pegasus/Pegasus-II based ethernet device support" tristate "USB Pegasus/Pegasus-II based ethernet device support"
depends on USB && NET
select MII select MII
---help--- ---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter. Say Y here if you know you have Pegasus or Pegasus-II based adapter.
...@@ -85,7 +83,7 @@ config USB_PEGASUS ...@@ -85,7 +83,7 @@ config USB_PEGASUS
config USB_RTL8150 config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)" tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
depends on USB && NET && EXPERIMENTAL depends on EXPERIMENTAL
help help
Say Y here if you have RTL8150 based usb-ethernet adapter. Say Y here if you have RTL8150 based usb-ethernet adapter.
Send me <petkan@users.sourceforge.net> any comments you may have. Send me <petkan@users.sourceforge.net> any comments you may have.
...@@ -96,7 +94,6 @@ config USB_RTL8150 ...@@ -96,7 +94,6 @@ config USB_RTL8150
config USB_USBNET config USB_USBNET
tristate "Multi-purpose USB Networking Framework" tristate "Multi-purpose USB Networking Framework"
depends on USB && NET
---help--- ---help---
This driver supports several kinds of network links over USB, This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core with "minidrivers" built around a common network driver core
...@@ -206,6 +203,9 @@ config USB_ARMLINUX ...@@ -206,6 +203,9 @@ config USB_ARMLINUX
such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities
in some PXA versions of the "blob" boot loader. 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 Although the ROMs shipped with Sharp Zaurus products use a
different link level framing protocol, you can have them use different link level framing protocol, you can have them use
this simpler protocol by installing a different kernel. this simpler protocol by installing a different kernel.
...@@ -266,17 +266,20 @@ config USB_AX8817X ...@@ -266,17 +266,20 @@ config USB_AX8817X
select MII select MII
default y default y
help help
This option adds support for ASIX AX88172 based USB 2.0 This option adds support for ASIX AX88172 based USB 2.0
10/100 Ethernet devices. 10/100 Ethernet devices.
This driver should work with at least the following devices: This driver should work with at least the following devices:
* Aten UC210T * Aten UC210T
* ASIX AX88172 * ASIX AX88172
* Billionton Systems, USB2AR
* Buffalo LUA-U2-KTX
* Corega FEther USB2-TX
* D-Link DUB-E100 * D-Link DUB-E100
* Hawking UF200 * Hawking UF200
* Linksys USB200M * Linksys USB200M
* Netgear FA120 * Netgear FA120
* Sitecom LN-029
* Intellinet USB 2.0 Ethernet * Intellinet USB 2.0 Ethernet
* ST Lab USB 2.0 Ethernet * ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100 * TrendNet TU2-ET100
...@@ -284,4 +287,4 @@ config USB_AX8817X ...@@ -284,4 +287,4 @@ config USB_AX8817X
This driver creates an interface named "ethX", where X depends on This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use. what other networking devices you have in use.
endmenu
This diff is collapsed.
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record { struct edge_firmware_image_record {
unsigned short ExtAddr; __le16 ExtAddr;
unsigned short Addr; __le16 Addr;
unsigned short Len; __le16 Len;
unsigned char Data[0]; unsigned char Data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record { struct edge_firmware_image_record {
unsigned short ExtAddr; __le16 ExtAddr;
unsigned short Addr; __le16 Addr;
unsigned short Len; __le16 Len;
unsigned char Data[0]; unsigned char Data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record { struct edge_firmware_image_record {
unsigned short ExtAddr; __le16 ExtAddr;
unsigned short Addr; __le16 Addr;
unsigned short Len; __le16 Len;
unsigned char Data[0]; unsigned char Data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) #if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
struct edge_firmware_image_record { struct edge_firmware_image_record {
unsigned short ExtAddr; __le16 ExtAddr;
unsigned short Addr; __le16 Addr;
unsigned short Len; __le16 Len;
unsigned char Data[0]; unsigned char Data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -98,6 +98,9 @@ static struct usb_serial_device_type edgeport_2port_device = { ...@@ -98,6 +98,9 @@ static struct usb_serial_device_type edgeport_2port_device = {
.write_room = edge_write_room, .write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer, .chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break, .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 = { static struct usb_serial_device_type edgeport_4port_device = {
...@@ -123,6 +126,9 @@ 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, .write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer, .chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break, .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 = { static struct usb_serial_device_type edgeport_8port_device = {
...@@ -148,6 +154,9 @@ 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, .write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer, .chars_in_buffer = edge_chars_in_buffer,
.break_ctl = edge_break, .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 #endif
......
This diff is collapsed.
...@@ -619,7 +619,7 @@ struct watchport_firmware_version ...@@ -619,7 +619,7 @@ struct watchport_firmware_version
// Structure of header of download image in fw_down.h // Structure of header of download image in fw_down.h
struct ti_i2c_image_header struct ti_i2c_image_header
{ {
__u16 Length; __le16 Length;
__u8 CheckSum; __u8 CheckSum;
}__attribute__((packed)); }__attribute__((packed));
......
...@@ -773,9 +773,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port, ...@@ -773,9 +773,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
switch (cflag & CSIZE) { switch (cflag & CSIZE) {
case CS5: case CS5:
dbg("%s - 5 bits/byte not supported", __FUNCTION__); dbg("%s - 5 bits/byte not supported", __FUNCTION__);
spin_unlock_irqrestore (&priv->lock, flags);
return ; return ;
case CS6: case CS6:
dbg("%s - 6 bits/byte not supported", __FUNCTION__); dbg("%s - 6 bits/byte not supported", __FUNCTION__);
spin_unlock_irqrestore (&priv->lock, flags);
return ; return ;
case CS7: case CS7:
priv->cfg.databits = kl5kusb105a_dtb_7; priv->cfg.databits = kl5kusb105a_dtb_7;
......
...@@ -236,7 +236,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) { ...@@ -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) static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
{ {
unsigned int divisor; __le32 divisor;
int rc; int rc;
unsigned char zero_byte = 0; unsigned char zero_byte = 0;
......
...@@ -463,6 +463,7 @@ static void destroy_serial(struct kref *kref) ...@@ -463,6 +463,7 @@ static void destroy_serial(struct kref *kref)
kfree(port->bulk_in_buffer); kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer); kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_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) ...@@ -480,45 +481,51 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial *serial; struct usb_serial *serial;
struct usb_serial_port *port; struct usb_serial_port *port;
unsigned int portNumber; unsigned int portNumber;
int retval = -ENODEV; int retval;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
/* initialize the pointer incase something fails */
tty->driver_data = NULL;
/* get the serial object associated with this tty pointer */ /* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index); serial = usb_serial_get_by_index(tty->index);
if (!serial) if (!serial) {
goto bailout; 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; portNumber = tty->index - serial->minor;
port = serial->port[portNumber]; port = serial->port[portNumber];
tty->driver_data = port;
++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; port->tty = tty;
/* lock this module before we call it, /* lock this module before we call it
this may, which means we must bail out, safe because we are called with BKL held */ * this may fail, which means we must bail out,
* safe because we are called with BKL held */
if (!try_module_get(serial->type->owner)) { if (!try_module_get(serial->type->owner)) {
kref_put(&serial->kref, destroy_serial); retval = -ENODEV;
goto bailout; goto bailout_kref_put;
} }
retval = 0;
++port->open_count;
if (port->open_count == 1) {
/* only call the device specific open if this /* only call the device specific open if this
* is the first time the port is opened */ * is the first time the port is opened */
retval = serial->type->open(port, filp); retval = serial->type->open(port, filp);
if (retval) { if (retval)
port->open_count = 0; goto bailout_module_put;
}
return 0;
bailout_module_put:
module_put(serial->type->owner); module_put(serial->type->owner);
bailout_kref_put:
kref_put(&serial->kref, destroy_serial); kref_put(&serial->kref, destroy_serial);
} port->open_count = 0;
}
bailout:
return retval; return retval;
} }
...@@ -531,21 +538,24 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -531,21 +538,24 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (port->open_count == 0)
return;
--port->open_count; --port->open_count;
if (port->open_count <= 0) { if (port->open_count == 0) {
/* only call the device specific close if this /* only call the device specific close if this
* port is being closed by the last owner */ * port is being closed by the last owner */
port->serial->type->close(port, filp); port->serial->type->close(port, filp);
port->open_count = 0;
if (port->tty) { if (port->tty) {
if (port->tty->driver_data) if (port->tty->driver_data)
port->tty->driver_data = NULL; port->tty->driver_data = NULL;
port->tty = NULL; port->tty = NULL;
} }
}
module_put(port->serial->type->owner); module_put(port->serial->type->owner);
}
kref_put(&port->serial->kref, destroy_serial); kref_put(&port->serial->kref, destroy_serial);
} }
...@@ -805,6 +815,7 @@ static void port_release(struct device *dev) ...@@ -805,6 +815,7 @@ static void port_release(struct device *dev)
kfree(port->bulk_in_buffer); kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer); kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer); kfree(port->interrupt_in_buffer);
kfree(port->interrupt_out_buffer);
kfree(port); kfree(port);
} }
......
...@@ -1114,11 +1114,11 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 * ...@@ -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->transfer_buffer_length = datasize + 1;
command_port->write_urb->dev = port->serial->dev; command_port->write_urb->dev = port->serial->dev;
retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL); retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL);
spin_unlock_irqrestore(&command_info->lock, flags);
if (retval) { if (retval) {
dbg("%s - submit urb failed", __FUNCTION__); dbg("%s - submit urb failed", __FUNCTION__);
goto exit; goto exit;
} }
spin_unlock_irqrestore(&command_info->lock, flags);
/* wait for the command to complete */ /* wait for the command to complete */
wait_event_interruptible_timeout(command_info->wait_command, wait_event_interruptible_timeout(command_info->wait_command,
......
...@@ -290,7 +290,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) ...@@ -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 REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
case MODE_SENSE: case MODE_SENSE:
case MODE_SENSE_10: case MODE_SENSE_10:
length = fst->Count; length = le16_to_cpu(fst->Count);
break; break;
default: default:
length = srb->request_bufflen; length = srb->request_bufflen;
......
...@@ -281,6 +281,14 @@ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, ...@@ -281,6 +281,14 @@ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ), 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 */ /* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
"Sony", "Sony",
...@@ -447,6 +455,13 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, ...@@ -447,6 +455,13 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
0 ), 0 ),
#endif #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 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
"Lexar", "Lexar",
......
...@@ -219,6 +219,7 @@ struct v4l2_pix_format ...@@ -219,6 +219,7 @@ struct v4l2_pix_format
/* Vendor-specific formats */ /* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */ #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 * F O R M A T E N U M E R A T I O N
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment