Commit bd392eef authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents eed9fa35 7081675f
......@@ -2764,7 +2764,7 @@ N: Luca Risolia
E: luca.risolia@studio.unibo.it
P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
D: V4L2 driver for SN9C10[12] PC Camera Controllers
D: V4L2 driver for SN9C10x PC Camera Controllers
S: Via Liberta' 41/A
S: Osio Sotto, 24046, Bergamo
S: Italy
......
......@@ -1311,6 +1311,8 @@ running once the system is up.
uart6850= [HW,OSS]
Format: <io>,<irq>
usb-handoff [HW] Enable early USB BIOS -> OS handoff
video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt.
......
SN9C10[12] PC Camera Controllers
SN9C10x PC Camera Controllers
Driver for Linux
================================
=============================
- Documentation -
......@@ -49,22 +49,23 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3. Overview
===========
This driver attempts to support the video streaming capabilities of the devices
mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers.
This driver attempts to support the video and audio streaming capabilities of
the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC
Camera Controllers.
- It's worth to note that SONiX has never collaborated with me during the
development of this project, despite of 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
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 the hotplug facility.
your system supports hotplugging.
The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well.
The latest version of the SN9C10[12] 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/
......@@ -122,12 +123,12 @@ analyze kernel messages and verify that the loading process has gone well:
Module parameters are listed below:
-------------------------------------------------------------------------------
Name: video_nr
Type: int array (min = 0, max = 32)
Type: int array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
-1 = use next available
n = use minor number n
You can specify up to 32 cameras this way.
You can specify up to 64 cameras this way.
For example:
video_nr=-1,2,-1 would assign minor number 2 to the second
recognized camera and use auto for the first one and for every
......@@ -150,17 +151,20 @@ Default: 2
7. Optional device control through "sysfs"
==========================================
It is possible to read and write both the SN9C10[12] 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.
Every time a supported device is recognized, a read-only file named "green" is
Every time a supported device is recognized, a write-only file named "green" is
created in the /sys/class/video4linux/videoX directory. You can set the green
channel's gain by writing the desired value to it. The value may range from 0
to 15.
to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
Similarly, only for SN9C103 controllers, blue and red gain control files are
available in the same directory, for which accepted values may range from 0 to
127.
There are other four entries in the directory above for each registered camera:
"reg", "val", "i2c_reg" and "i2c_val". The first two files control the
SN9C10[12] bridge, while the other two control the sensor chip. "reg" and
SN9C10x bridge, while the other two control the sensor chip. "reg" and
"i2c_reg" hold the values of the current register index where the following
reading/writing operations are addressed at through "val" and "i2c_val". Their
use is not intended for end-users, unless you know what you are doing. Note
......@@ -169,19 +173,21 @@ support the standard I2C protocol. Also, remember that you must be logged in as
root before writing to them.
As an example, suppose we were to want to read the value contained in the
register number 1 of the sensor register table - which usually is the product
register number 1 of the sensor register table - which is usually the product
identifier - of the camera registered as "/dev/video0":
[root@localhost #] cd /sys/class/video4linux/video0
[root@localhost #] echo 1 > i2c_reg
[root@localhost #] cat i2c_val
Now let's set the green gain's register of the SN9C10[12] chip to 2:
Note that "cat" will fail if sensor registers cannot be read.
Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2:
[root@localhost #] echo 0x11 > reg
[root@localhost #] echo 2 > val
Note that the SN9C10[12] always returns 0 when some of its registers are read.
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.
......@@ -192,25 +198,52 @@ here. They have never collaborated with me, so no advertising -
From the point of view of a driver, what unambiguously identify a device are
its vendor and product USB identifiers. Below is a list of known identifiers of
devices mounting the SN9C10[12] PC camera controllers:
devices mounting the SN9C10x PC camera controllers:
Vendor ID Product ID
--------- ----------
0xc45 0x6001
0xc45 0x6005
0xc45 0x6009
0xc45 0x600d
0xc45 0x6024
0xc45 0x6025
0xc45 0x6028
0xc45 0x6029
0xc45 0x602a
0xc45 0x602c
0xc45 0x6030
0x0c45 0x6001
0x0c45 0x6005
0x0c45 0x6009
0x0c45 0x600d
0x0c45 0x6024
0x0c45 0x6025
0x0c45 0x6028
0x0c45 0x6029
0x0c45 0x602a
0x0c45 0x602b
0x0c45 0x602c
0x0c45 0x6030
0x0c45 0x6080
0x0c45 0x6082
0x0c45 0x6083
0x0c45 0x6088
0x0c45 0x608a
0x0c45 0x608b
0x0c45 0x608c
0x0c45 0x608e
0x0c45 0x608f
0x0c45 0x60a0
0x0c45 0x60a2
0x0c45 0x60a3
0x0c45 0x60a8
0x0c45 0x60aa
0x0c45 0x60ab
0x0c45 0x60ac
0x0c45 0x60ae
0x0c45 0x60af
0x0c45 0x60b0
0x0c45 0x60b2
0x0c45 0x60b3
0x0c45 0x60b8
0x0c45 0x60ba
0x0c45 0x60bb
0x0c45 0x60bc
0x0c45 0x60be
The list above does NOT imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported.
Kernel messages will always tell you whether this is the case:
until now only the ones that mount the following image sensors are supported;
kernel messages will always tell you whether this is the case:
Model Manufacturer
----- ------------
......@@ -219,12 +252,15 @@ PAS202BCB PixArt Imaging Inc.
TAS5110C1B Taiwan Advanced Sensor Corporation
TAS5130D1B Taiwan Advanced Sensor Corporation
All the available control settings of each image sensor are supported through
the V4L2 interface.
If you think your camera is based on the above hardware and is not actually
listed in the above table, you may try to add the specific USB VendorID and
ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
then compile, load the module again and look at the kernel output.
If this works, please send an email to me reporting the kernel messages, so
that I will add a new entry in the list of supported devices.
that I can add a new entry in the list of supported devices.
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
......@@ -238,8 +274,8 @@ 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
"sn9c102_pas106b.c", which uses the mentioned interface.
At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
MI03 (VGA), OV7620 (VGA).
At the moment, possible unsupported image sensors are: HV7131x series (VGA),
MI03x series (VGA), OV7620 (VGA), OV7630 (VGA), CIS-VF10 (VGA).
10. Notes for V4L2 application developers
......@@ -254,12 +290,13 @@ device to switch to the other I/O method;
- previously mapped buffer memory must always be unmapped before calling any
of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. The same
number of buffers as before will be allocated again to match the size of the
new video frames, so you have to map them again before any I/O attempts.
new video frames, so you have to map the buffers again before any I/O attempts
on them.
Consistently with the hardware limits, this driver also supports image
downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions.
However the V4L2 API specifications don't correctly define how the scaling
factor can be choosen arbitrarily by the "negotiation" of the "source" and
However, the V4L2 API specifications don't correctly define how the scaling
factor can be chosen arbitrarily by the "negotiation" of the "source" and
"target" rectangles. To work around this flaw, we have added the convention
that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1.
......
......@@ -947,7 +947,7 @@ S: Maintained
HPUSBSCSI
P: Oliver Neukum
M: drivers@neukum.org
M: oliver@neukum.name
S: Maintained
I2C AND SENSORS DRIVERS
......@@ -1437,7 +1437,7 @@ S: Maintained
MICROTEK X6 SCANNER
P: Oliver Neukum
M: drivers@neukum.org
M: oliver@neukum.name
S: Maintained
MIPS
......@@ -2206,8 +2206,8 @@ W: http://www.kernel.dk
S: Maintained
USB ACM DRIVER
P: Vojtech Pavlik
M: vojtech@suse.cz
P: Oliver Neukum
M: oliver@neukum.name
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
......@@ -2250,7 +2250,7 @@ S: Maintained
USB KAWASAKI LSI DRIVER
P: Oliver Neukum
M: drivers@neukum.org
M: oliver@neukum.name
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
......@@ -2367,7 +2367,7 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.connecttech.com
S: Supported
USB SN9C10[12] DRIVER
USB SN9C10x DRIVER
P: Luca Risolia
M: luca.risolia@studio.unibo.it
L: linux-usb-devel@lists.sourceforge.net
......
......@@ -17,8 +17,10 @@
#include <asm/arch/pxa-regs.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include "generic.h"
......@@ -117,3 +119,45 @@ unsigned int get_lcdclk_frequency_10khz(void)
EXPORT_SYMBOL(get_clk_frequency_khz);
EXPORT_SYMBOL(get_memclk_frequency_10khz);
EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
/*
* device registration specific to PXA27x.
*/
static u64 pxa27x_dmamask = 0xffffffffUL;
static struct resource pxa27x_ohci_resources[] = {
[0] = {
.start = 0x4C000000,
.end = 0x4C00ff6f,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USBH1,
.end = IRQ_USBH1,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device ohci_device = {
.name = "pxa27x-ohci",
.id = -1,
.dev = {
.dma_mask = &pxa27x_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(pxa27x_ohci_resources),
.resource = pxa27x_ohci_resources,
};
static struct platform_device *devices[] __initdata = {
&ohci_device,
};
static int __init pxa27x_init(void)
{
return platform_add_devices(devices, ARRAY_SIZE(devices));
}
subsys_initcall(pxa27x_init);
This diff is collapsed.
......@@ -168,6 +168,7 @@ enum StirTestMask {
struct stir_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct usb_interface *usbintf;
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct net_device_stats stats; /* network statistics */
......@@ -508,6 +509,7 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
{
int i, err;
__u8 mode;
int rc;
for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) {
if (speed == stir_modes[i].speed)
......@@ -521,7 +523,14 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
pr_debug("speed change from %d to %d\n", stir->speed, speed);
/* sometimes needed to get chip out of stuck state */
rc = usb_lock_device_for_reset(stir->usbdev, stir->usbintf);
if (rc < 0) {
err = rc;
goto out;
}
err = usb_reset_device(stir->usbdev);
if (rc)
usb_unlock_device(stir->usbdev);
if (err)
goto out;
......@@ -1066,6 +1075,7 @@ static int stir_probe(struct usb_interface *intf,
stir = net->priv;
stir->netdev = net;
stir->usbdev = dev;
stir->usbintf = intf;
ret = usb_reset_configuration(dev);
if (ret != 0) {
......
......@@ -827,6 +827,236 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
pci_read_config_byte(dev, 0x77, &val);
}
#define UHCI_USBLEGSUP 0xc0 /* legacy support */
#define UHCI_USBCMD 0 /* command register */
#define UHCI_USBSTS 2 /* status register */
#define UHCI_USBINTR 4 /* interrupt register */
#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
#define OHCI_CONTROL 0x04
#define OHCI_CMDSTATUS 0x08
#define OHCI_INTRSTATUS 0x0c
#define OHCI_INTRENABLE 0x10
#define OHCI_INTRDISABLE 0x14
#define OHCI_OCR (1 << 3) /* ownership change request */
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
#define OHCI_INTR_OC (1 << 30) /* ownership change */
#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
#define EHCI_USBCMD 0 /* command register */
#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
#define EHCI_USBSTS 4 /* status register */
#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
#define EHCI_USBINTR 8 /* interrupt register */
#define EHCI_USBLEGSUP 0 /* legacy support register */
#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
int usb_early_handoff __initdata = 0;
static int __init usb_handoff_early(char *str)
{
usb_early_handoff = 1;
return 0;
}
__setup("usb-handoff", usb_handoff_early);
static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
{
unsigned long base = 0;
int wait_time, delta;
u16 val, sts;
int i;
for (i = 0; i < PCI_ROM_RESOURCE; i++)
if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
base = pci_resource_start(pdev, i);
break;
}
if (!base)
return;
/*
* stop controller
*/
sts = inw(base + UHCI_USBSTS);
val = inw(base + UHCI_USBCMD);
val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
outw(val, base + UHCI_USBCMD);
/*
* wait while it stops if it was running
*/
if ((sts & UHCI_USBSTS_HALTED) == 0)
{
wait_time = 1000;
delta = 100;
do {
outw(0x1f, base + UHCI_USBSTS);
udelay(delta);
wait_time -= delta;
val = inw(base + UHCI_USBSTS);
if (val & UHCI_USBSTS_HALTED)
break;
} while (wait_time > 0);
}
/*
* disable interrupts & legacy support
*/
outw(0, base + UHCI_USBINTR);
outw(0x1f, base + UHCI_USBSTS);
pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
if (val & 0xbf)
pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
}
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
int wait_time;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL) return;
if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
wait_time = 500; /* 0.5 seconds */
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
writel(OHCI_OCR, base + OHCI_CMDSTATUS);
while (wait_time > 0 &&
readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
wait_time -= 10;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((HZ*10 + 999) / 1000);
}
}
/*
* disable interrupts
*/
writel(~(u32)0, base + OHCI_INTRDISABLE);
writel(~(u32)0, base + OHCI_INTRSTATUS);
iounmap(base);
}
static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
{
int wait_time, delta;
void __iomem *base, *op_reg_base;
u32 hcc_params, val, temp;
u8 cap_length;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL) return;
cap_length = readb(base);
op_reg_base = base + cap_length;
hcc_params = readl(base + EHCI_HCC_PARAMS);
hcc_params = (hcc_params >> 8) & 0xff;
if (hcc_params) {
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
&val);
if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
/*
* Ok, BIOS is in smm mode, try to hand off...
*/
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
&temp);
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
temp | EHCI_USBLEGCTLSTS_SOOE);
val |= EHCI_USBLEGSUP_OS;
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
val);
wait_time = 500;
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((HZ*10+999)/1000);
wait_time -= 10;
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
&val);
} while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
if (!wait_time) {
/*
* well, possibly buggy BIOS...
*/
printk(KERN_WARNING "EHCI early BIOS handoff "
"failed (BIOS bug ?)\n");
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
EHCI_USBLEGSUP_OS);
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
0);
}
}
}
/*
* halt EHCI & disable its interrupts in any case
*/
val = readl(op_reg_base + EHCI_USBSTS);
if ((val & EHCI_USBSTS_HALTED) == 0) {
val = readl(op_reg_base + EHCI_USBCMD);
val &= ~EHCI_USBCMD_RUN;
writel(val, op_reg_base + EHCI_USBCMD);
wait_time = 2000;
delta = 100;
do {
writel(0x3f, op_reg_base + EHCI_USBSTS);
udelay(delta);
wait_time -= delta;
val = readl(op_reg_base + EHCI_USBSTS);
if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
break;
}
} while (wait_time > 0);
}
writel(0, op_reg_base + EHCI_USBINTR);
writel(0x3f, op_reg_base + EHCI_USBSTS);
iounmap(base);
return;
}
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
{
if (!usb_early_handoff)
return;
if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
quirk_usb_handoff_uhci(pdev);
} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
quirk_usb_handoff_ohci(pdev);
} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
quirk_usb_disable_ehci(pdev);
}
return;
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
/*
* ... This is further complicated by the fact that some SiS96x south
* bridges pretend to be 85C503/5513 instead. In that case see if we
......
......@@ -7,7 +7,7 @@ menu "USB support"
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
config USB
tristate "Support for Host-side USB"
depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404
depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404 || PXA27x
---help---
Universal Serial Bus (USB) is a specification for a serial bus
subsystem which offers higher speeds and more features than the
......@@ -91,6 +91,8 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
endmenu
......
......@@ -62,8 +62,10 @@ obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SPEEDTOUCH) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
#
# USB ATM driver configuration
#
comment "USB ATM/DSL drivers"
depends on USB
config USB_ATM
tristate "Generic USB ATM/DSL core I/O support"
depends on USB && ATM
select CRC32
default n
help
This provides a library which is used for packet I/O by USB DSL
modems, such as the SpeedTouch driver below.
To compile this driver as a module, choose M here: the
module will be called usb_atm.
config USB_SPEEDTOUCH
tristate "Alcatel Speedtouch USB support"
depends on USB && ATM
select USB_ATM
help
Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
modem. In order to use your modem you will need to install the
two parts of the firmware, extracted by the user space tools; see
<http://www.linux-usb.org/SpeedTouch/> for details.
To compile this driver as a module, choose M here: the
module will be called speedtch.
#
# Makefile for the rest of the USB drivers
# (the ones that don't fit into any other categories)
#
obj-$(CONFIG_USB_ATM) += usb_atm.o
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
This diff is collapsed.
This diff is collapsed.
/******************************************************************************
* usb_atm.h - Generic USB xDSL driver core
*
* Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
* Copyright (C) 2004, David Woodhouse
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
******************************************************************************/
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/kref.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <asm/semaphore.h>
#define UDSL_MAX_RCV_URBS 4
#define UDSL_MAX_SND_URBS 4
#define UDSL_MAX_RCV_BUFS 8
#define UDSL_MAX_SND_BUFS 8
#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
#define UDSL_DEFAULT_RCV_URBS 2
#define UDSL_DEFAULT_SND_URBS 2
#define UDSL_DEFAULT_RCV_BUFS 4
#define UDSL_DEFAULT_SND_BUFS 4
#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
/* receive */
struct udsl_receive_buffer {
struct list_head list;
unsigned char *base;
unsigned int filled_cells;
};
struct udsl_receiver {
struct list_head list;
struct udsl_receive_buffer *buffer;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_vcc_data {
/* vpi/vci lookup */
struct list_head list;
short vpi;
int vci;
struct atm_vcc *vcc;
/* raw cell reassembly */
struct sk_buff *sarb;
};
/* send */
struct udsl_send_buffer {
struct list_head list;
unsigned char *base;
unsigned char *free_start;
unsigned int free_cells;
};
struct udsl_sender {
struct list_head list;
struct udsl_send_buffer *buffer;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_control {
struct atm_skb_data atm_data;
unsigned int num_cells;
unsigned int num_entire;
unsigned int pdu_padding;
unsigned char aal5_trailer[ATM_AAL5_TRAILER];
};
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
/* main driver data */
enum udsl_status {
UDSL_NO_FIRMWARE,
UDSL_LOADING_FIRMWARE,
UDSL_LOADED_FIRMWARE
};
struct udsl_instance_data {
struct kref refcount;
struct semaphore serialize;
/* USB device part */
struct usb_device *usb_dev;
char description[64];
int data_endpoint;
int snd_padding;
int rcv_padding;
const char *driver_name;
/* ATM device part */
struct atm_dev *atm_dev;
struct list_head vcc_list;
/* firmware */
int (*firmware_wait) (struct udsl_instance_data *);
enum udsl_status status;
wait_queue_head_t firmware_waiters;
/* receive */
struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
spinlock_t receive_lock;
struct list_head spare_receivers;
struct list_head filled_receive_buffers;
struct tasklet_struct receive_tasklet;
struct list_head spare_receive_buffers;
/* send */
struct udsl_sender senders[UDSL_MAX_SND_URBS];
struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
struct sk_buff_head sndqueue;
spinlock_t send_lock;
struct list_head spare_senders;
struct list_head spare_send_buffers;
struct tasklet_struct send_tasklet;
struct sk_buff *current_skb; /* being emptied */
struct udsl_send_buffer *current_buffer; /* being filled */
struct list_head filled_send_buffers;
};
extern int udsl_instance_setup(struct usb_device *dev,
struct udsl_instance_data *instance);
extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
extern void udsl_get_instance(struct udsl_instance_data *instance);
extern void udsl_put_instance(struct udsl_instance_data *instance);
......@@ -9,7 +9,8 @@ config USB_AUDIO
depends on USB && SOUND
help
Say Y here if you want to connect USB audio equipment such as
speakers to your computer's USB port.
speakers to your computer's USB port. You only need this if you use
the OSS sound driver; ALSA has its own option for usb audio support.
To compile this driver as a module, choose M here: the
module will be called audio.
......
......@@ -635,13 +635,13 @@ static void usbin_stop(struct usb_audiodev *as)
spin_unlock_irqrestore(&as->lock, flags);
if (notkilled && signal_pending(current)) {
if (i & FLG_URB0RUNNING)
usb_unlink_urb(u->durb[0].urb);
usb_kill_urb(u->durb[0].urb);
if (i & FLG_URB1RUNNING)
usb_unlink_urb(u->durb[1].urb);
usb_kill_urb(u->durb[1].urb);
if (i & FLG_SYNC0RUNNING)
usb_unlink_urb(u->surb[0].urb);
usb_kill_urb(u->surb[0].urb);
if (i & FLG_SYNC1RUNNING)
usb_unlink_urb(u->surb[1].urb);
usb_kill_urb(u->surb[1].urb);
notkilled = 0;
}
}
......@@ -1114,13 +1114,13 @@ static void usbout_stop(struct usb_audiodev *as)
spin_unlock_irqrestore(&as->lock, flags);
if (notkilled && signal_pending(current)) {
if (i & FLG_URB0RUNNING)
usb_unlink_urb(u->durb[0].urb);
usb_kill_urb(u->durb[0].urb);
if (i & FLG_URB1RUNNING)
usb_unlink_urb(u->durb[1].urb);
usb_kill_urb(u->durb[1].urb);
if (i & FLG_SYNC0RUNNING)
usb_unlink_urb(u->surb[0].urb);
usb_kill_urb(u->surb[0].urb);
if (i & FLG_SYNC1RUNNING)
usb_unlink_urb(u->surb[1].urb);
usb_kill_urb(u->surb[1].urb);
notkilled = 0;
}
}
......@@ -1949,15 +1949,12 @@ static inline int prog_dmabuf_out(struct usb_audiodev *as)
static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct list_head *devs, *mdevs;
struct usb_mixerdev *ms;
struct usb_audio_state *s;
down(&open_sem);
list_for_each(devs, &audiodevs) {
s = list_entry(devs, struct usb_audio_state, audiodev);
list_for_each(mdevs, &s->mixerlist) {
ms = list_entry(mdevs, struct usb_mixerdev, list);
list_for_each_entry(s, &audiodevs, audiodev) {
list_for_each_entry(ms, &s->mixerlist, list) {
if (ms->dev_mixer == minor)
goto mixer_found;
}
......@@ -2634,16 +2631,13 @@ static int usb_audio_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
DECLARE_WAITQUEUE(wait, current);
struct list_head *devs, *adevs;
struct usb_audiodev *as;
struct usb_audio_state *s;
for (;;) {
down(&open_sem);
list_for_each(devs, &audiodevs) {
s = list_entry(devs, struct usb_audio_state, audiodev);
list_for_each(adevs, &s->audiolist) {
as = list_entry(adevs, struct usb_audiodev, list);
list_for_each_entry(s, &audiodevs, audiodev) {
list_for_each_entry(as, &s->audiolist, list) {
if (!((as->dev_audio ^ minor) & ~0xf))
goto device_found;
}
......@@ -3809,7 +3803,6 @@ static int usb_audio_probe(struct usb_interface *intf,
static void usb_audio_disconnect(struct usb_interface *intf)
{
struct usb_audio_state *s = usb_get_intfdata (intf);
struct list_head *list;
struct usb_audiodev *as;
struct usb_mixerdev *ms;
......@@ -3831,8 +3824,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
usb_set_intfdata (intf, NULL);
/* deregister all audio and mixer devices, so no new processes can open this device */
list_for_each(list, &s->audiolist) {
as = list_entry(list, struct usb_audiodev, list);
list_for_each_entry(as, &s->audiolist, list) {
usbin_disc(as);
usbout_disc(as);
wake_up(&as->usbin.dma.wait);
......@@ -3843,8 +3835,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
}
as->dev_audio = -1;
}
list_for_each(list, &s->mixerlist) {
ms = list_entry(list, struct usb_mixerdev, list);
list_for_each_entry(ms, &s->mixerlist, list) {
if (ms->dev_mixer >= 0) {
unregister_sound_mixer(ms->dev_mixer);
printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
......
......@@ -426,8 +426,8 @@ static void bluetooth_close (struct tty_struct *tty, struct file * filp)
bluetooth->open_count = 0;
/* shutdown any in-flight urbs that we know about */
usb_unlink_urb (bluetooth->read_urb);
usb_unlink_urb (bluetooth->interrupt_in_urb);
usb_kill_urb (bluetooth->read_urb);
usb_kill_urb (bluetooth->interrupt_in_urb);
}
up(&bluetooth->lock);
}
......@@ -705,7 +705,7 @@ void btusb_disable_bulk_read(struct tty_struct *tty){
}
if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
usb_unlink_urb(bluetooth->read_urb);
usb_kill_urb(bluetooth->read_urb);
}
#endif
......@@ -1179,14 +1179,14 @@ static void usb_bluetooth_disconnect(struct usb_interface *intf)
bluetooth->open_count = 0;
if (bluetooth->read_urb) {
usb_unlink_urb (bluetooth->read_urb);
usb_kill_urb (bluetooth->read_urb);
usb_free_urb (bluetooth->read_urb);
}
if (bluetooth->bulk_in_buffer)
kfree (bluetooth->bulk_in_buffer);
if (bluetooth->interrupt_in_urb) {
usb_unlink_urb (bluetooth->interrupt_in_urb);
usb_kill_urb (bluetooth->interrupt_in_urb);
usb_free_urb (bluetooth->interrupt_in_urb);
}
if (bluetooth->interrupt_in_buffer)
......@@ -1196,7 +1196,7 @@ static void usb_bluetooth_disconnect(struct usb_interface *intf)
for (i = 0; i < NUM_CONTROL_URBS; ++i) {
if (bluetooth->control_urb_pool[i]) {
usb_unlink_urb (bluetooth->control_urb_pool[i]);
usb_kill_urb (bluetooth->control_urb_pool[i]);
if (bluetooth->control_urb_pool[i]->transfer_buffer)
kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
usb_free_urb (bluetooth->control_urb_pool[i]);
......
......@@ -301,9 +301,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
return 0;
full_bailout:
usb_unlink_urb(acm->readurb);
usb_kill_urb(acm->readurb);
bail_out_and_unlink:
usb_unlink_urb(acm->ctrlurb);
usb_kill_urb(acm->ctrlurb);
bail_out:
up(&open_sem);
return -EIO;
......@@ -320,9 +320,9 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (!--acm->used) {
if (acm->dev) {
acm_set_control(acm, acm->ctrlout = 0);
usb_unlink_urb(acm->ctrlurb);
usb_unlink_urb(acm->writeurb);
usb_unlink_urb(acm->readurb);
usb_kill_urb(acm->ctrlurb);
usb_kill_urb(acm->writeurb);
usb_kill_urb(acm->readurb);
} else {
tty_unregister_device(acm_tty_driver, acm->minor);
acm_table[acm->minor] = NULL;
......@@ -542,6 +542,17 @@ static int acm_probe (struct usb_interface *intf,
return -EINVAL;
}
if (!buflen) {
if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
err("Zero length descriptor references");
return -EINVAL;
}
}
while (buflen > 0) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
err("skipping garbage");
......@@ -558,6 +569,8 @@ static int acm_probe (struct usb_interface *intf,
break;
case CDC_COUNTRY_TYPE: /* maybe somehow export */
break; /* for now we ignore it */
case CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case CDC_AC_MANAGEMENT_TYPE:
ac_management_function = buffer[3];
break;
......@@ -569,7 +582,7 @@ static int acm_probe (struct usb_interface *intf,
break;
default:
err("Ignoring extra header");
err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
break;
}
next_desc:
......@@ -637,7 +650,7 @@ static int acm_probe (struct usb_interface *intf,
dbg("interfaces are valid");
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (acm_table[minor]) {
if (minor == ACM_TTY_MINORS) {
err("no more free acm devices");
return -ENODEV;
}
......@@ -762,9 +775,9 @@ static void acm_disconnect(struct usb_interface *intf)
acm->dev = NULL;
usb_set_intfdata (intf, NULL);
usb_unlink_urb(acm->ctrlurb);
usb_unlink_urb(acm->readurb);
usb_unlink_urb(acm->writeurb);
usb_kill_urb(acm->ctrlurb);
usb_kill_urb(acm->readurb);
usb_kill_urb(acm->writeurb);
flush_scheduled_work(); /* wait for acm_softint */
......
......@@ -117,6 +117,7 @@ struct union_desc {
} __attribute__ ((packed));
/* class specific descriptor types */
#define CDC_HEADER_TYPE 0x00
#define CDC_CALL_MANAGEMENT_TYPE 0x01
#define CDC_AC_MANAGEMENT_TYPE 0x02
#define CDC_UNION_TYPE 0x06
......
......@@ -805,7 +805,6 @@ static int usb_midi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
DECLARE_WAITQUEUE(wait, current);
struct list_head *devs, *mdevs;
struct usb_midi_state *s;
struct usb_mididev *m;
unsigned long flags;
......@@ -817,10 +816,8 @@ static int usb_midi_open(struct inode *inode, struct file *file)
for(;;) {
down(&open_sem);
list_for_each(devs, &mididevs) {
s = list_entry(devs, struct usb_midi_state, mididev);
list_for_each(mdevs, &s->midiDevList) {
m = list_entry(mdevs, struct usb_mididev, list);
list_for_each_entry(s, &mididevs, mididev) {
list_for_each_entry(m, &s->midiDevList, list) {
if ( !((m->dev_midi ^ minor) & ~0xf) )
goto device_found;
}
......@@ -939,7 +936,7 @@ static int usb_midi_release(struct inode *inode, struct file *file)
if ( m->open_mode & FMODE_WRITE ) {
m->open_mode &= ~FMODE_WRITE;
usb_unlink_urb( m->mout.ep->urb );
usb_kill_urb( m->mout.ep->urb );
}
if ( m->open_mode & FMODE_READ ) {
......@@ -951,7 +948,7 @@ static int usb_midi_release(struct inode *inode, struct file *file)
if ( m->min.ep->readers == 0 &&
m->min.ep->urbSubmitted ) {
m->min.ep->urbSubmitted = 0;
usb_unlink_urb(m->min.ep->urb);
usb_kill_urb(m->min.ep->urb);
}
spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
}
......@@ -1042,7 +1039,7 @@ static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, in
static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
{
usb_unlink_urb( min->urb );
usb_kill_urb( min->urb );
usb_free_urb( min->urb );
kfree( min->recvBuf );
kfree( min );
......@@ -1102,7 +1099,7 @@ static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d,
static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
{
usb_unlink_urb( mout->urb );
usb_kill_urb( mout->urb );
usb_free_urb( mout->urb );
kfree( mout->buf );
kfree( mout );
......@@ -1994,7 +1991,6 @@ static int usb_midi_probe(struct usb_interface *intf,
static void usb_midi_disconnect(struct usb_interface *intf)
{
struct usb_midi_state *s = usb_get_intfdata (intf);
struct list_head *list;
struct usb_mididev *m;
if ( !s )
......@@ -2012,8 +2008,7 @@ static void usb_midi_disconnect(struct usb_interface *intf)
s->usbdev = NULL;
usb_set_intfdata (intf, NULL);
list_for_each(list, &s->midiDevList) {
m = list_entry(list, struct usb_mididev, list);
list_for_each_entry(m, &s->midiDevList, list) {
wake_up(&(m->min.ep->wait));
wake_up(&(m->mout.ep->wait));
if ( m->dev_midi >= 0 ) {
......
......@@ -406,9 +406,9 @@ static void usblp_cleanup (struct usblp *usblp)
static void usblp_unlink_urbs(struct usblp *usblp)
{
usb_unlink_urb(usblp->writeurb);
usb_kill_urb(usblp->writeurb);
if (usblp->bidir)
usb_unlink_urb(usblp->readurb);
usb_kill_urb(usblp->readurb);
}
static int usblp_release(struct inode *inode, struct file *file)
......
......@@ -149,7 +149,7 @@ static const struct class_info clas_info[] =
/*****************************************************************/
void usbdevfs_conn_disc_event(void)
void usbfs_conn_disc_event(void)
{
conndiscevcnt++;
wake_up(&deviceconndiscwq);
......@@ -451,7 +451,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
* nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion
* The caller must own the usbdev->serialize semaphore.
* The caller must own the device lock.
*/
static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
......@@ -569,7 +569,6 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
struct list_head *buslist;
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
......@@ -581,18 +580,15 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
/* enumerate busses */
down (&usb_bus_list_lock);
list_for_each(buslist, &usb_bus_list) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
/* print devices for all busses */
list_for_each_entry(bus, &usb_bus_list, bus_list) {
/* recurse through all children of the root hub */
if (!bus->root_hub)
continue;
down(&bus->root_hub->serialize);
usb_lock_device(bus->root_hub);
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
up(&bus->root_hub->serialize);
usb_unlock_device(bus->root_hub);
if (ret < 0) {
up(&usb_bus_list_lock);
return ret;
......@@ -682,7 +678,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
return ret;
}
struct file_operations usbdevfs_devices_fops = {
struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
......
......@@ -21,7 +21,7 @@
*
* $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
*
* This file implements the usbdevfs/x/y files, where
* This file implements the usbfs/x/y files, where
* x is the bus number and y the device number.
*
* It allows user space programs/"drivers" to communicate directly
......@@ -113,7 +113,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
int i;
pos = *ppos;
down(&dev->serialize);
usb_lock_device(dev);
if (!connected(dev)) {
ret = -ENODEV;
goto err;
......@@ -175,7 +175,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
}
err:
up(&dev->serialize);
usb_unlock_device(dev);
return ret;
}
......@@ -286,9 +286,10 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
/* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
/* usb_unlink_urb calls the completion handler with status == -ENOENT */
usb_unlink_urb(as->urb);
usb_kill_urb(as->urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
......@@ -353,7 +354,7 @@ static void driver_disconnect(struct usb_interface *intf)
destroy_async_on_interface(ps, ifnum);
}
struct usb_driver usbdevfs_driver = {
struct usb_driver usbfs_driver = {
.owner = THIS_MODULE,
.name = "usbfs",
.probe = driver_probe,
......@@ -378,7 +379,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
if (!intf)
err = -ENOENT;
else
err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps);
err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
up_write(&usb_bus_type.subsys.rwsem);
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
......@@ -401,7 +402,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
if (!intf)
err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
usb_driver_release_interface(&usbdevfs_driver, intf);
usb_driver_release_interface(&usbfs_driver, intf);
err = 0;
}
up_write(&usb_bus_type.subsys.rwsem);
......@@ -516,7 +517,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
struct usb_device *dev = ps->dev;
unsigned int ifnum;
down(&dev->serialize);
usb_lock_device(dev);
list_del_init(&ps->list);
if (connected(dev)) {
......@@ -525,7 +526,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
releaseintf(ps, ifnum);
destroy_all_async(ps);
}
up(&dev->serialize);
usb_unlock_device(dev);
usb_put_dev(dev);
ps->dev = NULL;
kfree(ps);
......@@ -557,10 +558,10 @@ static int proc_control(struct dev_state *ps, void __user *arg)
snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n",
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
up(&dev->serialize);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
down(&dev->serialize);
usb_lock_device(dev);
if ((i > 0) && ctrl.wLength) {
if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data ");
......@@ -588,10 +589,10 @@ static int proc_control(struct dev_state *ps, void __user *arg)
printk ("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
up(&dev->serialize);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
down(&dev->serialize);
usb_lock_device(dev);
}
free_page((unsigned long)tbuf);
if (i<0) {
......@@ -635,9 +636,9 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf);
return -EINVAL;
}
up(&dev->serialize);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
down(&dev->serialize);
usb_lock_device(dev);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf);
......@@ -651,9 +652,9 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT;
}
}
up(&dev->serialize);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
down(&dev->serialize);
usb_lock_device(dev);
}
kfree(tbuf);
if (i < 0) {
......@@ -734,7 +735,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
static int proc_resetdevice(struct dev_state *ps)
{
return __usb_reset_device(ps->dev);
return usb_reset_device(ps->dev);
}
......@@ -976,7 +977,7 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
as = async_getpending(ps, arg);
if (!as)
return -EINVAL;
usb_unlink_urb(as->urb);
usb_kill_urb(as->urb);
return 0;
}
......@@ -1024,9 +1025,9 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
break;
if (signal_pending(current))
break;
up(&dev->serialize);
usb_unlock_device(dev);
schedule();
down(&dev->serialize);
usb_lock_device(dev);
}
remove_wait_queue(&ps->wait, &wait);
set_current_state(TASK_RUNNING);
......@@ -1149,7 +1150,11 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
usb_lock_all_devices();
bus_rescan_devices(intf->dev.bus);
usb_unlock_all_devices();
usb_lock_device(ps->dev);
break;
/* talk directly to the interface's driver */
......@@ -1192,9 +1197,9 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
down(&dev->serialize);
usb_lock_device(dev);
if (!connected(dev)) {
up(&dev->serialize);
usb_unlock_device(dev);
return -ENODEV;
}
......@@ -1294,7 +1299,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
ret = proc_ioctl(ps, p);
break;
}
up(&dev->serialize);
usb_unlock_device(dev);
if (ret >= 0)
inode->i_atime = CURRENT_TIME;
return ret;
......@@ -1314,7 +1319,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
return mask;
}
struct file_operations usbdevfs_device_file_operations = {
struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
......
......@@ -188,9 +188,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
}
hcd->irq = dev->irq;
dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base);
resource);
usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations;
......@@ -260,6 +260,8 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
}
usb_deregister_bus (&hcd->self);
pci_disable_device(dev);
}
EXPORT_SYMBOL (usb_hcd_pci_remove);
......
......@@ -798,9 +798,9 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
return (retval < 0) ? retval : -EMSGSIZE;
}
down (&usb_dev->serialize);
usb_lock_device (usb_dev);
retval = usb_new_device (usb_dev);
up (&usb_dev->serialize);
usb_unlock_device (usb_dev);
if (retval) {
usb_dev->bus->root_hub = NULL;
dev_err (parent_dev, "can't register root hub for %s, %d\n",
......@@ -1264,7 +1264,7 @@ static int hcd_unlink_urb (struct urb *urb, int status)
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address().
*/
if (!hcd->saw_irq) {
if (!hcd->saw_irq && hcd->rh_timer.data != (unsigned long) urb) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Different ACPI or APIC settings may help."
"\n");
......@@ -1573,13 +1573,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
if (start == USB_STATE_HALT)
return IRQ_NONE;
hcd->saw_irq = 1;
if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE;
hcd->saw_irq = 1;
if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd);
return IRQ_HANDLED;
......@@ -1588,22 +1587,6 @@ EXPORT_SYMBOL (usb_hcd_irq);
/*-------------------------------------------------------------------------*/
static void hcd_panic (void *_hcd)
{
struct usb_hcd *hcd = _hcd;
struct usb_device *hub = hcd->self.root_hub;
unsigned i;
/* hc's root hub is removed later removed in hcd->stop() */
down (&hub->serialize);
usb_set_device_state(hub, USB_STATE_NOTATTACHED);
for (i = 0; i < hub->maxchild; i++) {
if (hub->children [i])
usb_disconnect (&hub->children [i]);
}
up (&hub->serialize);
}
/**
* usb_hc_died - report abnormal shutdown of a host controller (bus glue)
* @hcd: pointer to the HCD representing the controller
......@@ -1616,9 +1599,9 @@ void usb_hc_died (struct usb_hcd *hcd)
{
dev_err (hcd->self.controller, "HC died; cleaning up\n");
/* clean up old urbs and devices; needs a task context */
INIT_WORK (&hcd->work, hcd_panic, hcd);
(void) schedule_work (&hcd->work);
/* make khubd clean up old urbs and devices */
usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED);
mod_timer(&hcd->rh_timer, jiffies);
}
EXPORT_SYMBOL (usb_hc_died);
......@@ -67,7 +67,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct timer_list rh_timer; /* drives root hub */
struct list_head dev_list; /* devices on this bus */
struct work_struct work;
/*
* hardware info/state
......@@ -363,6 +362,9 @@ static inline int hcd_register_root (struct usb_device *usb_dev,
return usb_register_root_hub (usb_dev, hcd->self.controller);
}
extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state);
/*-------------------------------------------------------------------------*/
/* exported only within usbcore */
......
This diff is collapsed.
......@@ -4,7 +4,7 @@
* inode.c -- Inode/Dentry functions for the USB device file system.
*
* Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
* Copyright (C) 2001,2002 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -40,17 +40,15 @@
#include <linux/smp_lock.h>
#include <linux/parser.h>
#include <asm/byteorder.h>
#include "usb.h"
static struct super_operations usbfs_ops;
static struct file_operations default_file_operations;
static struct inode_operations usbfs_dir_inode_operations;
static struct vfsmount *usbdevfs_mount;
static struct vfsmount *usbfs_mount;
static int usbdevfs_mount_count; /* = 0 */
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
static struct dentry *devices_usbdevfs_dentry;
static struct dentry *devices_usbfs_dentry;
static int num_buses; /* = 0 */
......@@ -240,9 +238,6 @@ static int remount(struct super_block *sb, int *flags, char *data)
if (usbfs_mount && usbfs_mount->mnt_sb)
update_sb(usbfs_mount->mnt_sb);
if (usbdevfs_mount && usbdevfs_mount->mnt_sb)
update_sb(usbdevfs_mount->mnt_sb);
return 0;
}
......@@ -561,28 +556,12 @@ static void fs_remove_file (struct dentry *dentry)
/* --------------------------------------------------------------------- */
/*
* The usbdevfs name is now deprecated (as of 2.5.1).
* It will be removed when the 2.7.x development cycle is started.
* You have been warned :)
*/
static struct file_system_type usbdevice_fs_type;
static struct super_block *usb_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, usbfs_fill_super);
}
static struct file_system_type usbdevice_fs_type = {
.owner = THIS_MODULE,
.name = "usbdevfs",
.get_sb = usb_get_sb,
.kill_sb = kill_litter_super,
};
static struct file_system_type usb_fs_type = {
.owner = THIS_MODULE,
.name = "usbfs",
......@@ -603,16 +582,10 @@ static int create_special_files (void)
ignore_mount = 1;
/* create the devices special file */
retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count);
if (retval) {
err ("Unable to get usbdevfs mount");
goto exit;
}
retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
goto error_clean_usbdevfs_mount;
goto exit;
}
ignore_mount = 0;
......@@ -620,7 +593,7 @@ static int create_special_files (void)
parent = usbfs_mount->mnt_sb->s_root;
devices_usbfs_dentry = fs_create_file ("devices",
listmode | S_IFREG, parent,
NULL, &usbdevfs_devices_fops,
NULL, &usbfs_devices_fops,
listuid, listgid);
if (devices_usbfs_dentry == NULL) {
err ("Unable to create devices usbfs file");
......@@ -628,42 +601,19 @@ static int create_special_files (void)
goto error_clean_mounts;
}
parent = usbdevfs_mount->mnt_sb->s_root;
devices_usbdevfs_dentry = fs_create_file ("devices",
listmode | S_IFREG, parent,
NULL, &usbdevfs_devices_fops,
listuid, listgid);
if (devices_usbdevfs_dentry == NULL) {
err ("Unable to create devices usbfs file");
retval = -ENODEV;
goto error_remove_file;
}
goto exit;
error_remove_file:
fs_remove_file (devices_usbfs_dentry);
devices_usbfs_dentry = NULL;
error_clean_mounts:
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
error_clean_usbdevfs_mount:
simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
exit:
return retval;
}
static void remove_special_files (void)
{
if (devices_usbdevfs_dentry)
fs_remove_file (devices_usbdevfs_dentry);
if (devices_usbfs_dentry)
fs_remove_file (devices_usbfs_dentry);
devices_usbdevfs_dentry = NULL;
devices_usbfs_dentry = NULL;
simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
}
......@@ -671,11 +621,6 @@ void usbfs_update_special (void)
{
struct inode *inode;
if (devices_usbdevfs_dentry) {
inode = devices_usbdevfs_dentry->d_inode;
if (inode)
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
if (devices_usbfs_dentry) {
inode = devices_usbfs_dentry->d_inode;
if (inode)
......@@ -707,29 +652,16 @@ void usbfs_add_bus(struct usb_bus *bus)
return;
}
parent = usbdevfs_mount->mnt_sb->s_root;
bus->usbdevfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
bus, NULL, busuid, busgid);
if (bus->usbdevfs_dentry == NULL) {
err ("error creating usbdevfs bus entry");
return;
}
usbfs_update_special();
usbdevfs_conn_disc_event();
usbfs_conn_disc_event();
}
void usbfs_remove_bus(struct usb_bus *bus)
{
if (bus->usbfs_dentry) {
fs_remove_file (bus->usbfs_dentry);
bus->usbfs_dentry = NULL;
}
if (bus->usbdevfs_dentry) {
fs_remove_file (bus->usbdevfs_dentry);
bus->usbdevfs_dentry = NULL;
}
--num_buses;
if (num_buses <= 0) {
......@@ -738,7 +670,7 @@ void usbfs_remove_bus(struct usb_bus *bus)
}
usbfs_update_special();
usbdevfs_conn_disc_event();
usbfs_conn_disc_event();
}
void usbfs_add_device(struct usb_device *dev)
......@@ -750,20 +682,12 @@ void usbfs_add_device(struct usb_device *dev)
sprintf (name, "%03d", dev->devnum);
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbfs_dentry, dev,
&usbdevfs_device_file_operations,
&usbfs_device_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
err ("error creating usbfs device entry");
return;
}
dev->usbdevfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbdevfs_dentry, dev,
&usbdevfs_device_file_operations,
devuid, devgid);
if (dev->usbdevfs_dentry == NULL) {
err ("error creating usbdevfs device entry");
return;
}
/* Set the size of the device's file to be
* equal to the size of the device descriptors. */
......@@ -775,11 +699,9 @@ void usbfs_add_device(struct usb_device *dev)
}
if (dev->usbfs_dentry->d_inode)
dev->usbfs_dentry->d_inode->i_size = i_size;
if (dev->usbdevfs_dentry->d_inode)
dev->usbdevfs_dentry->d_inode->i_size = i_size;
usbfs_update_special();
usbdevfs_conn_disc_event();
usbfs_conn_disc_event();
}
void usbfs_remove_device(struct usb_device *dev)
......@@ -791,10 +713,6 @@ void usbfs_remove_device(struct usb_device *dev)
fs_remove_file (dev->usbfs_dentry);
dev->usbfs_dentry = NULL;
}
if (dev->usbdevfs_dentry) {
fs_remove_file (dev->usbdevfs_dentry);
dev->usbdevfs_dentry = NULL;
}
while (!list_empty(&dev->filelist)) {
ds = list_entry(dev->filelist.next, struct dev_state, list);
list_del_init(&ds->list);
......@@ -807,51 +725,38 @@ void usbfs_remove_device(struct usb_device *dev)
}
}
usbfs_update_special();
usbdevfs_conn_disc_event();
usbfs_conn_disc_event();
}
/* --------------------------------------------------------------------- */
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *usbdir = NULL;
#endif
int __init usbfs_init(void)
{
int retval;
retval = usb_register(&usbdevfs_driver);
retval = usb_register(&usbfs_driver);
if (retval)
return retval;
retval = register_filesystem(&usb_fs_type);
if (retval) {
usb_deregister(&usbdevfs_driver);
return retval;
}
retval = register_filesystem(&usbdevice_fs_type);
if (retval) {
unregister_filesystem(&usb_fs_type);
usb_deregister(&usbdevfs_driver);
usb_deregister(&usbfs_driver);
return retval;
}
#ifdef CONFIG_PROC_FS
/* create mount point for usbdevfs */
/* create mount point for usbfs */
usbdir = proc_mkdir("usb", proc_bus);
#endif
return 0;
}
void usbfs_cleanup(void)
{
usb_deregister(&usbdevfs_driver);
usb_deregister(&usbfs_driver);
unregister_filesystem(&usb_fs_type);
unregister_filesystem(&usbdevice_fs_type);
#ifdef CONFIG_PROC_FS
if (usbdir)
remove_proc_entry("usb", proc_bus);
#endif
}
This diff is collapsed.
This diff is collapsed.
......@@ -451,6 +451,11 @@ int usb_unlink_urb(struct urb *urb)
if (!urb)
return -EINVAL;
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
#ifdef CONFIG_DEBUG_KERNEL
printk(KERN_NOTICE "usb_unlink_urb() is deprecated for "
"synchronous unlinks. Use usb_kill_urb() instead.\n");
WARN_ON(1);
#endif
usb_kill_urb(urb);
return 0;
}
......
This diff is collapsed.
......@@ -22,8 +22,14 @@ extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state);
extern void usb_lock_all_devices(void);
extern void usb_unlock_all_devices(void);
/* for labeling diagnostics */
extern const char *usbcore_name;
/* usbfs stuff */
extern struct usb_driver usbfs_driver;
extern struct file_operations usbfs_devices_fops;
extern struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
......@@ -39,6 +39,17 @@ config USB_GADGET
If in doubt, say "N" and don't enable these drivers; most people
don't have this kind of hardware (except maybe inside Linux PDAs).
config USB_GADGET_DEBUG_FILES
boolean "Debugging information files"
depends on USB_GADGET && PROC_FS
help
Some of the drivers in the "gadget" framework can expose
debugging information in files such as /proc/driver/udc
(for a peripheral controller). The information in these
files may help when you're troubleshooting or bringing up a
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
#
# USB Peripheral Controller Support
#
......@@ -206,10 +217,6 @@ config USB_OTG
Select this only if your OMAP board has a Mini-AB connector.
config USB_OMAP_PROC
boolean "/proc/driver/udc file"
depends on USB_GADGET_OMAP
endchoice
config USB_GADGET_DUALSPEED
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1188,6 +1188,8 @@ zero_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
} else if (gadget_is_n9604(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x020a);
} else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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