forked from Minki/linux
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (81 commits) [PATCH] USB: omninet: fix up debugging comments [PATCH] USB serial: add navman driver [PATCH] USB: Fix irda-usb use after use [PATCH] USB: rtl8150 small fix [PATCH] USB: ftdi_sio: add Icom ID1 USB product and vendor ids [PATCH] USB: cp2101: add new device IDs [PATCH] USB: fix check_ctrlrecip to allow control transfers in state ADDRESS [PATCH] USB: vicam.c: fix a NULL pointer dereference [PATCH] USB: ZC0301 driver bugfix [PATCH] USB: add support for Creativelabs Silvercrest USB keyboard [PATCH] USB: storage: new unusual_devs.h entry: Mitsumi 7in1 Card Reader [PATCH] USB: storage: unusual_devs.h entry 0420:0001 [PATCH] USB: storage: another unusual_devs.h entry [PATCH] USB: storage: sandisk unusual_devices entry [PATCH] USB: fix initdata issue in isp116x-hcd [PATCH] USB: usbcore: usb_set_configuration oops (NULL ptr dereference) [PATCH] USB: usbcore: Don't assume a USB configuration includes any interfaces [PATCH] USB: ub 03 drop stall clearing [PATCH] USB: ub 02 remove diag [PATCH] USB: ub 01 remove first_open ...
This commit is contained in:
commit
2bf2154c6b
2
CREDITS
2
CREDITS
@ -2813,6 +2813,8 @@ 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 SN9C10x PC Camera Controllers
|
||||
D: V4L2 driver for ET61X151 and ET61X251 PC Camera Controllers
|
||||
D: V4L2 driver for ZC0301 Image Processor and Control Chip
|
||||
S: Via Liberta' 41/A
|
||||
S: Osio Sotto, 24046, Bergamo
|
||||
S: Italy
|
||||
|
@ -176,6 +176,14 @@ Description: Force the application to unmap previously mapped buffer memory
|
||||
1 = force memory unmapping (save memory)
|
||||
Default: 0
|
||||
-------------------------------------------------------------------------------
|
||||
Name: frame_timeout
|
||||
Type: uint array (min = 0, max = 64)
|
||||
Syntax: <n[,...]>
|
||||
Description: Timeout for a video frame in seconds. This parameter is
|
||||
specific for each detected camera. This parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
Name: debug
|
||||
Type: ushort
|
||||
Syntax: <n>
|
||||
@ -266,7 +274,7 @@ the V4L2 interface.
|
||||
|
||||
|
||||
10. Notes for V4L2 application developers
|
||||
========================================
|
||||
=========================================
|
||||
This driver follows the V4L2 API specifications. In particular, it enforces two
|
||||
rules:
|
||||
|
||||
|
@ -196,6 +196,14 @@ Description: Force the application to unmap previously mapped buffer memory
|
||||
1 = force memory unmapping (save memory)
|
||||
Default: 0
|
||||
-------------------------------------------------------------------------------
|
||||
Name: frame_timeout
|
||||
Type: uint array (min = 0, max = 64)
|
||||
Syntax: <n[,...]>
|
||||
Description: Timeout for a video frame in seconds. This parameter is
|
||||
specific for each detected camera. This parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
Name: debug
|
||||
Type: ushort
|
||||
Syntax: <n>
|
||||
@ -321,6 +329,7 @@ Vendor ID Product ID
|
||||
--------- ----------
|
||||
0x0c45 0x6001
|
||||
0x0c45 0x6005
|
||||
0x0c45 0x6007
|
||||
0x0c45 0x6009
|
||||
0x0c45 0x600d
|
||||
0x0c45 0x6024
|
||||
@ -370,6 +379,7 @@ HV7131D Hynix Semiconductor, Inc.
|
||||
MI-0343 Micron Technology, Inc.
|
||||
OV7630 OmniVision Technologies, Inc.
|
||||
PAS106B PixArt Imaging, Inc.
|
||||
PAS202BCA PixArt Imaging, Inc.
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||
@ -493,6 +503,7 @@ Many thanks to following persons for their contribute (listed in alphabetical
|
||||
order):
|
||||
|
||||
- Luca Capello for the donation of a webcam;
|
||||
- Philippe Coval for having helped testing the PAS202BCA image sensor;
|
||||
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
|
||||
donation of a webcam;
|
||||
- Jon Hollstrom for the donation of a webcam;
|
||||
|
254
Documentation/usb/zc0301.txt
Normal file
254
Documentation/usb/zc0301.txt
Normal file
@ -0,0 +1,254 @@
|
||||
|
||||
ZC0301 Image Processor and Control Chip
|
||||
Driver for Linux
|
||||
=======================================
|
||||
|
||||
- Documentation -
|
||||
|
||||
|
||||
Index
|
||||
=====
|
||||
1. Copyright
|
||||
2. Disclaimer
|
||||
3. License
|
||||
4. Overview and features
|
||||
5. Module dependencies
|
||||
6. Module loading
|
||||
7. Module parameters
|
||||
8. Supported devices
|
||||
9. Notes for V4L2 application developers
|
||||
10. Contact information
|
||||
11. Credits
|
||||
|
||||
|
||||
1. Copyright
|
||||
============
|
||||
Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
|
||||
|
||||
2. Disclaimer
|
||||
=============
|
||||
This software is not developed or sponsored by Z-Star Microelectronics Corp.
|
||||
Trademarks are property of their respective owner.
|
||||
|
||||
|
||||
3. License
|
||||
==========
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
4. Overview and features
|
||||
========================
|
||||
This driver supports the video interface of the devices mounting the ZC0301
|
||||
Image Processor and Control Chip.
|
||||
|
||||
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 ZC0301 driver can be found at the following URL:
|
||||
http://www.linux-projects.org/
|
||||
|
||||
Some of the features of the driver are:
|
||||
|
||||
- full compliance with the Video4Linux2 API (see also "Notes for V4L2
|
||||
application developers" paragraph);
|
||||
- available mmap or read/poll methods for video streaming through isochronous
|
||||
data transfers;
|
||||
- automatic detection of image sensor;
|
||||
- video format is standard JPEG;
|
||||
- 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
|
||||
the system supports hotplugging;
|
||||
|
||||
|
||||
5. Module dependencies
|
||||
======================
|
||||
For it to work properly, the driver needs kernel support for Video4Linux and
|
||||
USB.
|
||||
|
||||
The following options of the kernel configuration file must be enabled and
|
||||
corresponding modules must be compiled:
|
||||
|
||||
# Multimedia devices
|
||||
#
|
||||
CONFIG_VIDEO_DEV=m
|
||||
|
||||
# USB support
|
||||
#
|
||||
CONFIG_USB=m
|
||||
|
||||
In addition, depending on the hardware being used, the modules below are
|
||||
necessary:
|
||||
|
||||
# USB Host Controller Drivers
|
||||
#
|
||||
CONFIG_USB_EHCI_HCD=m
|
||||
CONFIG_USB_UHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD=m
|
||||
|
||||
The ZC0301 controller also provides a built-in microphone interface. It is
|
||||
supported by the USB Audio driver thanks to the ALSA API:
|
||||
|
||||
# Sound
|
||||
#
|
||||
CONFIG_SOUND=y
|
||||
|
||||
# Advanced Linux Sound Architecture
|
||||
#
|
||||
CONFIG_SND=m
|
||||
|
||||
# USB devices
|
||||
#
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
|
||||
And finally:
|
||||
|
||||
# USB Multimedia devices
|
||||
#
|
||||
CONFIG_USB_ZC0301=m
|
||||
|
||||
|
||||
6. Module loading
|
||||
=================
|
||||
To use the driver, it is necessary to load the "zc0301" module into memory
|
||||
after every other module required: "videodev", "usbcore" and, depending on
|
||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
||||
|
||||
Loading can be done as shown below:
|
||||
|
||||
[root@localhost home]# modprobe zc0301
|
||||
|
||||
At this point the devices should be recognized. You can invoke "dmesg" to
|
||||
analyze kernel messages and verify that the loading process has gone well:
|
||||
|
||||
[user@localhost home]$ dmesg
|
||||
|
||||
|
||||
7. Module parameters
|
||||
====================
|
||||
Module parameters are listed below:
|
||||
-------------------------------------------------------------------------------
|
||||
Name: video_nr
|
||||
Type: short 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 64 cameras this way.
|
||||
For example:
|
||||
video_nr=-1,2,-1 would assign minor number 2 to the second
|
||||
registered camera and use auto for the first one and for every
|
||||
other camera.
|
||||
Default: -1
|
||||
-------------------------------------------------------------------------------
|
||||
Name: force_munmap
|
||||
Type: bool array (min = 0, max = 64)
|
||||
Syntax: <0|1[,...]>
|
||||
Description: Force the application to unmap previously mapped buffer memory
|
||||
before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
|
||||
all the applications support this feature. This parameter is
|
||||
specific for each detected camera.
|
||||
0 = do not force memory unmapping
|
||||
1 = force memory unmapping (save memory)
|
||||
Default: 0
|
||||
-------------------------------------------------------------------------------
|
||||
Name: frame_timeout
|
||||
Type: uint array (min = 0, max = 64)
|
||||
Syntax: <n[,...]>
|
||||
Description: Timeout for a video frame in seconds. This parameter is
|
||||
specific for each detected camera. This parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
Name: debug
|
||||
Type: ushort
|
||||
Syntax: <n>
|
||||
Description: Debugging information level, from 0 to 3:
|
||||
0 = none (use carefully)
|
||||
1 = critical errors
|
||||
2 = significant informations
|
||||
3 = more verbose messages
|
||||
Level 3 is useful for testing only, when only one device
|
||||
is used at the same time. It also shows some more informations
|
||||
about the hardware being detected. This module parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
8. Supported devices
|
||||
====================
|
||||
None of the names of the companies as well as their products will be mentioned
|
||||
here. They have never collaborated with the author, so no advertising.
|
||||
|
||||
From the point of view of a driver, what unambiguously identify a device are
|
||||
its vendor and product USB identifiers. Below is a list of known identifiers of
|
||||
devices mounting the ZC0301 Image Processor and Control Chips:
|
||||
|
||||
Vendor ID Product ID
|
||||
--------- ----------
|
||||
0x041e 0x4017
|
||||
0x041e 0x401c
|
||||
0x041e 0x401e
|
||||
0x041e 0x4034
|
||||
0x041e 0x4035
|
||||
0x046d 0x08ae
|
||||
0x0ac8 0x0301
|
||||
0x10fd 0x8050
|
||||
|
||||
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:
|
||||
|
||||
Model Manufacturer
|
||||
----- ------------
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
|
||||
|
||||
9. Notes for V4L2 application developers
|
||||
========================================
|
||||
This driver follows the V4L2 API specifications. In particular, it enforces two
|
||||
rules:
|
||||
|
||||
- exactly one I/O method, either "mmap" or "read", is associated with each
|
||||
file descriptor. Once it is selected, the application must close and reopen the
|
||||
device to switch to the other I/O method;
|
||||
|
||||
- although it is not mandatory, previously mapped buffer memory should always
|
||||
be unmapped before calling any "VIDIOC_S_CROP" or "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 the buffers again before any I/O
|
||||
attempts on them.
|
||||
|
||||
|
||||
10. Contact information
|
||||
=======================
|
||||
The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
|
||||
|
||||
GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
|
||||
'FCE635A4'; the public 1024-bit key should be available at any keyserver;
|
||||
the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
|
||||
|
||||
|
||||
11. Credits
|
||||
===========
|
||||
- Informations about the chip internals needed to enable the I2C protocol have
|
||||
been taken from the documentation of the ZC030x Video4Linux1 driver written
|
||||
by Andrew Birkett <andy@nobugs.org>;
|
||||
- The initialization values of the ZC0301 controller connected to the PAS202BCB
|
||||
image sensor have been taken from the SPCA5XX driver maintained by
|
||||
Michel Xhaard <mxhaard@magic.fr>.
|
@ -2896,6 +2896,14 @@ L: video4linux-list@redhat.com
|
||||
W: http://www.linux-projects.org
|
||||
S: Maintained
|
||||
|
||||
USB ZC0301 DRIVER
|
||||
P: Luca Risolia
|
||||
M: luca.risolia@studio.unibo.it
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
L: video4linux-list@redhat.com
|
||||
W: http://www.linux-projects.org
|
||||
S: Maintained
|
||||
|
||||
USB ZD1201 DRIVER
|
||||
P: Jeroen Vreeken
|
||||
M: pe1rxq@amsat.org
|
||||
|
@ -38,7 +38,7 @@ struct cpu_spec cpu_specs[] = {
|
||||
{ 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
|
||||
{ 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
|
||||
{ 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
|
||||
{ 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
|
||||
{ 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 },
|
||||
{ 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
static struct resource au1xxx_usb_ohci_resources[] = {
|
||||
[0] = {
|
||||
.start = USB_OHCI_BASE,
|
||||
.end = USB_OHCI_BASE + USB_OHCI_LEN,
|
||||
.end = USB_OHCI_BASE + USB_OHCI_LEN - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
@ -278,9 +278,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
|
||||
&au1100_lcd_device,
|
||||
#endif
|
||||
#ifdef CONFIG_SOC_AU1200
|
||||
#if 0 /* fixme */
|
||||
&au1xxx_usb_ehci_device,
|
||||
#endif
|
||||
&au1xxx_usb_gdt_device,
|
||||
&au1xxx_usb_otg_device,
|
||||
&au1200_lcd_device,
|
||||
|
@ -8,7 +8,6 @@
|
||||
* and is not licensed separately. See file COPYING for details.
|
||||
*
|
||||
* TODO (sorted by decreasing priority)
|
||||
* -- Kill first_open (Al Viro fixed the block layer now)
|
||||
* -- set readonly flag for CDs, set removable flag for CF readers
|
||||
* -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
|
||||
* -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
|
||||
@ -181,6 +180,7 @@ struct ub_dev;
|
||||
#define UB_DIR_ILLEGAL2 2
|
||||
#define UB_DIR_WRITE 3
|
||||
|
||||
/* P3 */
|
||||
#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \
|
||||
(((c)==UB_DIR_READ)? 'r': 'n'))
|
||||
|
||||
@ -196,24 +196,11 @@ enum ub_scsi_cmd_state {
|
||||
UB_CMDST_DONE /* Final state */
|
||||
};
|
||||
|
||||
static char *ub_scsi_cmd_stname[] = {
|
||||
". ",
|
||||
"Cmd",
|
||||
"dat",
|
||||
"c2s",
|
||||
"sts",
|
||||
"clr",
|
||||
"crs",
|
||||
"Sen",
|
||||
"fin"
|
||||
};
|
||||
|
||||
struct ub_scsi_cmd {
|
||||
unsigned char cdb[UB_MAX_CDB_SIZE];
|
||||
unsigned char cdb_len;
|
||||
|
||||
unsigned char dir; /* 0 - none, 1 - read, 3 - write. */
|
||||
unsigned char trace_index;
|
||||
enum ub_scsi_cmd_state state;
|
||||
unsigned int tag;
|
||||
struct ub_scsi_cmd *next;
|
||||
@ -249,28 +236,6 @@ struct ub_capacity {
|
||||
unsigned int bshift; /* Shift between 512 and hard sects */
|
||||
};
|
||||
|
||||
/*
|
||||
* The SCSI command tracing structure.
|
||||
*/
|
||||
|
||||
#define SCMD_ST_HIST_SZ 8
|
||||
#define SCMD_TRACE_SZ 63 /* Less than 4KB of 61-byte lines */
|
||||
|
||||
struct ub_scsi_cmd_trace {
|
||||
int hcur;
|
||||
unsigned int tag;
|
||||
unsigned int req_size, act_size;
|
||||
unsigned char op;
|
||||
unsigned char dir;
|
||||
unsigned char key, asc, ascq;
|
||||
char st_hst[SCMD_ST_HIST_SZ];
|
||||
};
|
||||
|
||||
struct ub_scsi_trace {
|
||||
int cur;
|
||||
struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a direct take-off from linux/include/completion.h
|
||||
* The difference is that I do not wait on this thing, just poll.
|
||||
@ -334,7 +299,6 @@ struct ub_lun {
|
||||
int changed; /* Media was changed */
|
||||
int removable;
|
||||
int readonly;
|
||||
int first_open; /* Kludge. See ub_bd_open. */
|
||||
|
||||
struct ub_request urq;
|
||||
|
||||
@ -390,7 +354,6 @@ struct ub_dev {
|
||||
wait_queue_head_t reset_wait;
|
||||
|
||||
int sg_stat[6];
|
||||
struct ub_scsi_trace tr;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -459,137 +422,6 @@ static int ub_qlock_next = 0;
|
||||
|
||||
static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */
|
||||
|
||||
/*
|
||||
* The SCSI command tracing procedures.
|
||||
*/
|
||||
|
||||
static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
int n;
|
||||
struct ub_scsi_cmd_trace *t;
|
||||
|
||||
if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
|
||||
t = &sc->tr.vec[n];
|
||||
|
||||
memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
|
||||
t->tag = cmd->tag;
|
||||
t->op = cmd->cdb[0];
|
||||
t->dir = cmd->dir;
|
||||
t->req_size = cmd->len;
|
||||
t->st_hst[0] = cmd->state;
|
||||
|
||||
sc->tr.cur = n;
|
||||
cmd->trace_index = n;
|
||||
}
|
||||
|
||||
static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
int n;
|
||||
struct ub_scsi_cmd_trace *t;
|
||||
|
||||
t = &sc->tr.vec[cmd->trace_index];
|
||||
if (t->tag == cmd->tag) {
|
||||
if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
|
||||
t->st_hst[n] = cmd->state;
|
||||
t->hcur = n;
|
||||
}
|
||||
}
|
||||
|
||||
static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
struct ub_scsi_cmd_trace *t;
|
||||
|
||||
t = &sc->tr.vec[cmd->trace_index];
|
||||
if (t->tag == cmd->tag)
|
||||
t->act_size = cmd->act_len;
|
||||
}
|
||||
|
||||
static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
|
||||
unsigned char *sense)
|
||||
{
|
||||
struct ub_scsi_cmd_trace *t;
|
||||
|
||||
t = &sc->tr.vec[cmd->trace_index];
|
||||
if (t->tag == cmd->tag) {
|
||||
t->key = sense[2] & 0x0F;
|
||||
t->asc = sense[12];
|
||||
t->ascq = sense[13];
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct usb_interface *intf;
|
||||
struct ub_dev *sc;
|
||||
struct list_head *p;
|
||||
struct ub_lun *lun;
|
||||
int cnt;
|
||||
unsigned long flags;
|
||||
int nc, nh;
|
||||
int i, j;
|
||||
struct ub_scsi_cmd_trace *t;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
sc = usb_get_intfdata(intf);
|
||||
if (sc == NULL)
|
||||
return 0;
|
||||
|
||||
cnt = 0;
|
||||
spin_lock_irqsave(sc->lock, flags);
|
||||
|
||||
cnt += sprintf(page + cnt,
|
||||
"poison %d reset %d\n",
|
||||
atomic_read(&sc->poison), sc->reset);
|
||||
cnt += sprintf(page + cnt,
|
||||
"qlen %d qmax %d\n",
|
||||
sc->cmd_queue.qlen, sc->cmd_queue.qmax);
|
||||
cnt += sprintf(page + cnt,
|
||||
"sg %d %d %d %d %d .. %d\n",
|
||||
sc->sg_stat[0],
|
||||
sc->sg_stat[1],
|
||||
sc->sg_stat[2],
|
||||
sc->sg_stat[3],
|
||||
sc->sg_stat[4],
|
||||
sc->sg_stat[5]);
|
||||
|
||||
list_for_each (p, &sc->luns) {
|
||||
lun = list_entry(p, struct ub_lun, link);
|
||||
cnt += sprintf(page + cnt,
|
||||
"lun %u changed %d removable %d readonly %d\n",
|
||||
lun->num, lun->changed, lun->removable, lun->readonly);
|
||||
}
|
||||
|
||||
if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
|
||||
for (j = 0; j < SCMD_TRACE_SZ; j++) {
|
||||
t = &sc->tr.vec[nc];
|
||||
|
||||
cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
|
||||
if (t->op == REQUEST_SENSE) {
|
||||
cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
|
||||
t->key, t->asc, t->ascq);
|
||||
} else {
|
||||
cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
|
||||
cnt += sprintf(page + cnt, " [%5d %5d]",
|
||||
t->req_size, t->act_size);
|
||||
}
|
||||
if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
|
||||
for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
|
||||
cnt += sprintf(page + cnt, " %s",
|
||||
ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
|
||||
if (++nh == SCMD_ST_HIST_SZ) nh = 0;
|
||||
}
|
||||
cnt += sprintf(page + cnt, "\n");
|
||||
|
||||
if (++nc == SCMD_TRACE_SZ) nc = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(sc->lock, flags);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
|
||||
|
||||
/*
|
||||
* The id allocator.
|
||||
*
|
||||
@ -1092,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
add_timer(&sc->work_timer);
|
||||
|
||||
cmd->state = UB_CMDST_CMD;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1145,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
|
||||
ub_cmdq_pop(sc);
|
||||
(*cmd->done)(sc, cmd);
|
||||
} else if (cmd->state == UB_CMDST_INIT) {
|
||||
ub_cmdtr_new(sc, cmd);
|
||||
if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
|
||||
break;
|
||||
cmd->error = rc;
|
||||
cmd->state = UB_CMDST_DONE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
} else {
|
||||
if (!ub_is_completed(&sc->work_done))
|
||||
break;
|
||||
@ -1247,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
cmd->state = UB_CMDST_CLEAR;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
case -EILSEQ: /* unplug timeout on uhci */
|
||||
@ -1279,7 +1107,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
cmd->state = UB_CMDST_CLR2STS;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return;
|
||||
}
|
||||
if (urb->status == -EOVERFLOW) {
|
||||
@ -1304,7 +1131,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
if (urb->status != 0 ||
|
||||
len != cmd->sgv[cmd->current_sg].length) {
|
||||
cmd->act_len += len;
|
||||
ub_cmdtr_act_len(sc, cmd);
|
||||
|
||||
cmd->error = -EIO;
|
||||
ub_state_stat(sc, cmd);
|
||||
@ -1331,7 +1157,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
}
|
||||
|
||||
cmd->act_len += urb->actual_length;
|
||||
ub_cmdtr_act_len(sc, cmd);
|
||||
|
||||
if (++cmd->current_sg < cmd->nsg) {
|
||||
ub_data_start(sc, cmd);
|
||||
@ -1357,7 +1182,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
cmd->error = -EIO; /* A cheap trick... */
|
||||
|
||||
cmd->state = UB_CMDST_CLRRS;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1441,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
cmd->state = UB_CMDST_DONE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
ub_cmdq_pop(sc);
|
||||
(*cmd->done)(sc, cmd);
|
||||
|
||||
@ -1496,7 +1319,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
add_timer(&sc->work_timer);
|
||||
|
||||
cmd->state = UB_CMDST_DATA;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1508,7 +1330,6 @@ static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
|
||||
|
||||
cmd->error = rc;
|
||||
cmd->state = UB_CMDST_DONE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
ub_cmdq_pop(sc);
|
||||
(*cmd->done)(sc, cmd);
|
||||
}
|
||||
@ -1554,7 +1375,6 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
|
||||
cmd->stat_count = 0;
|
||||
cmd->state = UB_CMDST_STAT;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1573,7 +1393,6 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
return;
|
||||
|
||||
cmd->state = UB_CMDST_STAT;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1611,7 +1430,6 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
scmd->tag = sc->tagcnt++;
|
||||
|
||||
cmd->state = UB_CMDST_SENSE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
|
||||
ub_cmdq_insert(sc, scmd);
|
||||
return;
|
||||
@ -1667,11 +1485,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
|
||||
unsigned char *sense = sc->top_sense;
|
||||
struct ub_scsi_cmd *cmd;
|
||||
|
||||
/*
|
||||
* Ignoring scmd->act_len, because the buffer was pre-zeroed.
|
||||
*/
|
||||
ub_cmdtr_sense(sc, scmd, sense);
|
||||
|
||||
/*
|
||||
* Find the command which triggered the unit attention or a check,
|
||||
* save the sense into it, and advance its state machine.
|
||||
@ -1693,6 +1506,9 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignoring scmd->act_len, because the buffer was pre-zeroed.
|
||||
*/
|
||||
cmd->key = sense[2] & 0x0F;
|
||||
cmd->asc = sense[12];
|
||||
cmd->ascq = sense[13];
|
||||
@ -1849,26 +1665,6 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
|
||||
sc->openc++;
|
||||
spin_unlock_irqrestore(&ub_lock, flags);
|
||||
|
||||
/*
|
||||
* This is a workaround for a specific problem in our block layer.
|
||||
* In 2.6.9, register_disk duplicates the code from rescan_partitions.
|
||||
* However, if we do add_disk with a device which persistently reports
|
||||
* a changed media, add_disk calls register_disk, which does do_open,
|
||||
* which will call rescan_paritions for changed media. After that,
|
||||
* register_disk attempts to do it all again and causes double kobject
|
||||
* registration and a eventually an oops on module removal.
|
||||
*
|
||||
* The bottom line is, Al Viro says that we should not allow
|
||||
* bdev->bd_invalidated to be set when doing add_disk no matter what.
|
||||
*/
|
||||
if (lun->first_open) {
|
||||
lun->first_open = 0;
|
||||
if (lun->changed) {
|
||||
rc = -ENOMEDIUM;
|
||||
goto err_open;
|
||||
}
|
||||
}
|
||||
|
||||
if (lun->removable || lun->readonly)
|
||||
check_disk_change(inode->i_bdev);
|
||||
|
||||
@ -2007,9 +1803,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
|
||||
init_completion(&compl);
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
||||
if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
||||
goto err_alloc;
|
||||
memset(cmd, 0, ALLOC_SIZE);
|
||||
|
||||
cmd->cdb[0] = TEST_UNIT_READY;
|
||||
cmd->cdb_len = 6;
|
||||
@ -2062,9 +1857,8 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
|
||||
init_completion(&compl);
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
||||
if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
||||
goto err_alloc;
|
||||
memset(cmd, 0, ALLOC_SIZE);
|
||||
p = (char *)cmd + sizeof(struct ub_scsi_cmd);
|
||||
|
||||
cmd->cdb[0] = 0x25;
|
||||
@ -2405,9 +2199,8 @@ static int ub_probe(struct usb_interface *intf,
|
||||
return -ENXIO;
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
|
||||
if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
|
||||
goto err_core;
|
||||
memset(sc, 0, sizeof(struct ub_dev));
|
||||
sc->lock = ub_next_lock();
|
||||
INIT_LIST_HEAD(&sc->luns);
|
||||
usb_init_urb(&sc->work_urb);
|
||||
@ -2438,9 +2231,6 @@ static int ub_probe(struct usb_interface *intf,
|
||||
if (ub_get_pipes(sc, sc->dev, intf) != 0)
|
||||
goto err_dev_desc;
|
||||
|
||||
if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
|
||||
goto err_diag;
|
||||
|
||||
/*
|
||||
* At this point, all USB initialization is done, do upper layer.
|
||||
* We really hate halfway initialized structures, so from the
|
||||
@ -2480,19 +2270,8 @@ static int ub_probe(struct usb_interface *intf,
|
||||
|
||||
nluns = 1;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ((rc = ub_sync_getmaxlun(sc)) < 0) {
|
||||
/*
|
||||
* This segment is taken from usb-storage. They say
|
||||
* that ZIP-100 needs this, but my own ZIP-100 works
|
||||
* fine without this.
|
||||
* Still, it does not seem to hurt anything.
|
||||
*/
|
||||
if (rc == -EPIPE) {
|
||||
ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
|
||||
ub_probe_clear_stall(sc, sc->send_bulk_pipe);
|
||||
}
|
||||
if ((rc = ub_sync_getmaxlun(sc)) < 0)
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
nluns = rc;
|
||||
break;
|
||||
@ -2505,8 +2284,6 @@ static int ub_probe(struct usb_interface *intf,
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
|
||||
err_diag:
|
||||
err_dev_desc:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
// usb_put_intf(sc->intf);
|
||||
@ -2524,9 +2301,8 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
|
||||
int rc;
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
|
||||
if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
|
||||
goto err_alloc;
|
||||
memset(lun, 0, sizeof(struct ub_lun));
|
||||
lun->num = lnum;
|
||||
|
||||
rc = -ENOSR;
|
||||
@ -2541,7 +2317,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
|
||||
|
||||
lun->removable = 1; /* XXX Query this from the device */
|
||||
lun->changed = 1; /* ub_revalidate clears only */
|
||||
lun->first_open = 1;
|
||||
ub_revalidate(sc, lun);
|
||||
|
||||
rc = -ENOMEM;
|
||||
@ -2636,7 +2411,6 @@ static void ub_disconnect(struct usb_interface *intf)
|
||||
while ((cmd = ub_cmdq_peek(sc)) != NULL) {
|
||||
cmd->error = -ENOTCONN;
|
||||
cmd->state = UB_CMDST_DONE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
ub_cmdq_pop(sc);
|
||||
(*cmd->done)(sc, cmd);
|
||||
cnt++;
|
||||
@ -2687,7 +2461,6 @@ static void ub_disconnect(struct usb_interface *intf)
|
||||
* and no URBs left in transit.
|
||||
*/
|
||||
|
||||
device_remove_file(&sc->intf->dev, &dev_attr_diag);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
// usb_put_intf(sc->intf);
|
||||
sc->intf = NULL;
|
||||
|
@ -740,7 +740,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
|
||||
struct sk_buff *newskb;
|
||||
struct sk_buff *dataskb;
|
||||
struct urb *next_urb;
|
||||
int docopy;
|
||||
unsigned int len, docopy;
|
||||
|
||||
IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
|
||||
|
||||
@ -851,10 +851,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
|
||||
dataskb->dev = self->netdev;
|
||||
dataskb->mac.raw = dataskb->data;
|
||||
dataskb->protocol = htons(ETH_P_IRDA);
|
||||
len = dataskb->len;
|
||||
netif_rx(dataskb);
|
||||
|
||||
/* Keep stats up to date */
|
||||
self->stats.rx_bytes += dataskb->len;
|
||||
self->stats.rx_bytes += len;
|
||||
self->stats.rx_packets++;
|
||||
self->netdev->last_rx = jiffies;
|
||||
|
||||
|
@ -10,6 +10,7 @@ menu "USB support"
|
||||
config USB_ARCH_HAS_HCD
|
||||
boolean
|
||||
default y if USB_ARCH_HAS_OHCI
|
||||
default y if USB_ARCH_HAS_EHCI
|
||||
default y if ARM # SL-811
|
||||
default PCI
|
||||
|
||||
@ -22,6 +23,7 @@ config USB_ARCH_HAS_OHCI
|
||||
default y if ARCH_LH7A404
|
||||
default y if ARCH_S3C2410
|
||||
default y if PXA27x
|
||||
default y if ARCH_AT91RM9200
|
||||
# PPC:
|
||||
default y if STB03xxx
|
||||
default y if PPC_MPC52xx
|
||||
@ -30,6 +32,13 @@ config USB_ARCH_HAS_OHCI
|
||||
# more:
|
||||
default PCI
|
||||
|
||||
# some non-PCI hcds implement EHCI
|
||||
config USB_ARCH_HAS_EHCI
|
||||
boolean
|
||||
default y if PPC_83xx
|
||||
default y if SOC_AU1200
|
||||
default PCI
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
config USB
|
||||
tristate "Support for Host-side USB"
|
||||
|
@ -15,10 +15,9 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_UHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_SL811_HCD) += host/
|
||||
obj-$(CONFIG_ETRAX_USB_HOST) += host/
|
||||
obj-$(CONFIG_USB_OHCI_AT91) += host/
|
||||
|
||||
obj-$(CONFIG_USB_ACM) += class/
|
||||
obj-$(CONFIG_USB_AUDIO) += class/
|
||||
obj-$(CONFIG_USB_MIDI) += class/
|
||||
obj-$(CONFIG_USB_PRINTER) += class/
|
||||
|
||||
obj-$(CONFIG_USB_STORAGE) += storage/
|
||||
@ -48,6 +47,7 @@ obj-$(CONFIG_USB_SN9C102) += media/
|
||||
obj-$(CONFIG_USB_STV680) += media/
|
||||
obj-$(CONFIG_USB_VICAM) += media/
|
||||
obj-$(CONFIG_USB_W9968CF) += media/
|
||||
obj-$(CONFIG_USB_ZC0301) += media/
|
||||
|
||||
obj-$(CONFIG_USB_CATC) += net/
|
||||
obj-$(CONFIG_USB_KAWETH) += net/
|
||||
|
@ -4,53 +4,6 @@
|
||||
comment "USB Device Class drivers"
|
||||
depends on USB
|
||||
|
||||
config OBSOLETE_OSS_USB_DRIVER
|
||||
bool "Obsolete OSS USB drivers"
|
||||
depends on USB && SOUND
|
||||
help
|
||||
This option enables support for the obsolete USB Audio and Midi
|
||||
drivers that are scheduled for removal in the near future since
|
||||
there are ALSA drivers for the same hardware.
|
||||
|
||||
Please contact Adrian Bunk <bunk@stusta.de> if you had to
|
||||
say Y here because of missing support in the ALSA drivers.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config USB_AUDIO
|
||||
tristate "USB Audio support"
|
||||
depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
|
||||
help
|
||||
Say Y here if you want to connect USB audio equipment such as
|
||||
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.
|
||||
|
||||
config USB_MIDI
|
||||
tristate "USB MIDI support"
|
||||
depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
|
||||
---help---
|
||||
Say Y here if you want to connect a USB MIDI device to your
|
||||
computer's USB port. You only need this if you use the OSS
|
||||
sound system; USB MIDI devices are supported by ALSA's USB
|
||||
audio driver. This driver is for devices that comply with
|
||||
'Universal Serial Bus Device Class Definition for MIDI Device'.
|
||||
|
||||
The following devices are known to work:
|
||||
* Steinberg USB2MIDI
|
||||
* Roland MPU64
|
||||
* Roland PC-300
|
||||
* Roland SC8850
|
||||
* Roland UM-1
|
||||
* Roland UM-2
|
||||
* Roland UA-100
|
||||
* Yamaha MU1000
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called usb-midi.
|
||||
|
||||
config USB_ACM
|
||||
tristate "USB Modem (CDC ACM) support"
|
||||
depends on USB
|
||||
|
@ -4,6 +4,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_ACM) += cdc-acm.o
|
||||
obj-$(CONFIG_USB_AUDIO) += audio.o
|
||||
obj-$(CONFIG_USB_MIDI) += usb-midi.o
|
||||
obj-$(CONFIG_USB_PRINTER) += usblp.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,110 +0,0 @@
|
||||
#define CS_AUDIO_UNDEFINED 0x20
|
||||
#define CS_AUDIO_DEVICE 0x21
|
||||
#define CS_AUDIO_CONFIGURATION 0x22
|
||||
#define CS_AUDIO_STRING 0x23
|
||||
#define CS_AUDIO_INTERFACE 0x24
|
||||
#define CS_AUDIO_ENDPOINT 0x25
|
||||
|
||||
#define HEADER 0x01
|
||||
#define INPUT_TERMINAL 0x02
|
||||
#define OUTPUT_TERMINAL 0x03
|
||||
#define MIXER_UNIT 0x04
|
||||
#define SELECTOR_UNIT 0x05
|
||||
#define FEATURE_UNIT 0x06
|
||||
#define PROCESSING_UNIT 0x07
|
||||
#define EXTENSION_UNIT 0x08
|
||||
|
||||
#define AS_GENERAL 0x01
|
||||
#define FORMAT_TYPE 0x02
|
||||
#define FORMAT_SPECIFIC 0x03
|
||||
|
||||
#define EP_GENERAL 0x01
|
||||
|
||||
#define MAX_CHAN 9
|
||||
#define MAX_FREQ 16
|
||||
#define MAX_IFACE 8
|
||||
#define MAX_FORMAT 8
|
||||
#define MAX_ALT 32 /* Sorry, we need quite a few for the Philips webcams */
|
||||
|
||||
struct usb_audio_terminal
|
||||
{
|
||||
u8 flags;
|
||||
u8 assoc;
|
||||
u16 type; /* Mic etc */
|
||||
u8 channels;
|
||||
u8 source;
|
||||
u16 chancfg;
|
||||
};
|
||||
|
||||
struct usb_audio_format
|
||||
{
|
||||
u8 type;
|
||||
u8 channels;
|
||||
u8 num_freq;
|
||||
u8 sfz;
|
||||
u8 bits;
|
||||
u16 freq[MAX_FREQ];
|
||||
};
|
||||
|
||||
struct usb_audio_interface
|
||||
{
|
||||
u8 terminal;
|
||||
u8 delay;
|
||||
u16 num_formats;
|
||||
u16 format_type;
|
||||
u8 flags;
|
||||
u8 idleconf; /* Idle config */
|
||||
#define AU_IFACE_FOUND 1
|
||||
struct usb_audio_format format[MAX_FORMAT];
|
||||
};
|
||||
|
||||
struct usb_audio_device
|
||||
{
|
||||
struct list_head list;
|
||||
u8 mixer;
|
||||
u8 selector;
|
||||
void *irq_handle;
|
||||
u8 num_channels;
|
||||
u8 num_dsp_iface;
|
||||
u8 channel_map[MAX_CHAN];
|
||||
struct usb_audio_terminal terminal[MAX_CHAN];
|
||||
struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Audio Class specific Request Codes */
|
||||
|
||||
#define SET_CUR 0x01
|
||||
#define GET_CUR 0x81
|
||||
#define SET_MIN 0x02
|
||||
#define GET_MIN 0x82
|
||||
#define SET_MAX 0x03
|
||||
#define GET_MAX 0x83
|
||||
#define SET_RES 0x04
|
||||
#define GET_RES 0x84
|
||||
#define SET_MEM 0x05
|
||||
#define GET_MEM 0x85
|
||||
#define GET_STAT 0xff
|
||||
|
||||
/* Terminal Control Selectors */
|
||||
|
||||
#define COPY_PROTECT_CONTROL 0x01
|
||||
|
||||
/* Feature Unit Control Selectors */
|
||||
|
||||
#define MUTE_CONTROL 0x01
|
||||
#define VOLUME_CONTROL 0x02
|
||||
#define BASS_CONTROL 0x03
|
||||
#define MID_CONTROL 0x04
|
||||
#define TREBLE_CONTROL 0x05
|
||||
#define GRAPHIC_EQUALIZER_CONTROL 0x06
|
||||
#define AUTOMATIC_GAIN_CONTROL 0x07
|
||||
#define DELAY_CONTROL 0x08
|
||||
#define BASS_BOOST_CONTROL 0x09
|
||||
#define LOUDNESS_CONTROL 0x0a
|
||||
|
||||
/* Endpoint Control Selectors */
|
||||
|
||||
#define SAMPLING_FREQ_CONTROL 0x01
|
||||
#define PITCH_CONTROL 0x02
|
@ -60,6 +60,7 @@
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb_cdc.h>
|
||||
@ -80,7 +81,7 @@ static struct usb_driver acm_driver;
|
||||
static struct tty_driver *acm_tty_driver;
|
||||
static struct acm *acm_table[ACM_TTY_MINORS];
|
||||
|
||||
static DECLARE_MUTEX(open_sem);
|
||||
static DEFINE_MUTEX(open_mutex);
|
||||
|
||||
#define ACM_READY(acm) (acm && acm->dev && acm->used)
|
||||
|
||||
@ -431,8 +432,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
int rv = -EINVAL;
|
||||
int i;
|
||||
dbg("Entering acm_tty_open.\n");
|
||||
|
||||
down(&open_sem);
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
|
||||
acm = acm_table[tty->index];
|
||||
if (!acm || !acm->dev)
|
||||
@ -474,14 +475,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
done:
|
||||
err_out:
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
return rv;
|
||||
|
||||
full_bailout:
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
bail_out:
|
||||
acm->used--;
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -507,7 +508,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (!acm || !acm->used)
|
||||
return;
|
||||
|
||||
down(&open_sem);
|
||||
mutex_lock(&open_mutex);
|
||||
if (!--acm->used) {
|
||||
if (acm->dev) {
|
||||
acm_set_control(acm, acm->ctrlout = 0);
|
||||
@ -518,7 +519,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
} else
|
||||
acm_tty_unregister(acm);
|
||||
}
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
}
|
||||
|
||||
static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
@ -1013,9 +1014,9 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
return;
|
||||
}
|
||||
|
||||
down(&open_sem);
|
||||
mutex_lock(&open_mutex);
|
||||
if (!usb_get_intfdata(intf)) {
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
return;
|
||||
}
|
||||
acm->dev = NULL;
|
||||
@ -1045,11 +1046,11 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
|
||||
if (!acm->used) {
|
||||
acm_tty_unregister(acm);
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
up(&open_sem);
|
||||
mutex_unlock(&open_mutex);
|
||||
|
||||
if (acm->tty)
|
||||
tty_hangup(acm->tty);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,164 +0,0 @@
|
||||
/*
|
||||
usb-midi.h -- USB-MIDI driver
|
||||
|
||||
Copyright (C) 2001
|
||||
NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
|
||||
|
||||
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef _USB_MIDI_H_
|
||||
#define _USB_MIDI_H_
|
||||
|
||||
#ifndef USB_SUBCLASS_MIDISTREAMING
|
||||
#define USB_SUBCLASS_MIDISTREAMING 3
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Roland MIDI Devices */
|
||||
|
||||
#define USB_VENDOR_ID_ROLAND 0x0582
|
||||
#define USBMIDI_ROLAND_UA100G 0x0000
|
||||
#define USBMIDI_ROLAND_MPU64 0x0002
|
||||
#define USBMIDI_ROLAND_SC8850 0x0003
|
||||
#define USBMIDI_ROLAND_SC8820 0x0007
|
||||
#define USBMIDI_ROLAND_UM2 0x0005
|
||||
#define USBMIDI_ROLAND_UM1 0x0009
|
||||
#define USBMIDI_ROLAND_PC300 0x0008
|
||||
|
||||
/* YAMAHA MIDI Devices */
|
||||
#define USB_VENDOR_ID_YAMAHA 0x0499
|
||||
#define USBMIDI_YAMAHA_MU1000 0x1001
|
||||
|
||||
/* Steinberg MIDI Devices */
|
||||
#define USB_VENDOR_ID_STEINBERG 0x0763
|
||||
#define USBMIDI_STEINBERG_USB2MIDI 0x1001
|
||||
|
||||
/* Mark of the Unicorn MIDI Devices */
|
||||
#define USB_VENDOR_ID_MOTU 0x07fd
|
||||
#define USBMIDI_MOTU_FASTLANE 0x0001
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Supported devices */
|
||||
|
||||
struct usb_midi_endpoint {
|
||||
int endpoint;
|
||||
int cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
|
||||
};
|
||||
|
||||
struct usb_midi_device {
|
||||
char *deviceName;
|
||||
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
int interface;
|
||||
int altSetting; /* -1: auto detect */
|
||||
|
||||
struct usb_midi_endpoint in[15];
|
||||
struct usb_midi_endpoint out[15];
|
||||
};
|
||||
|
||||
static struct usb_midi_device usb_midi_devices[] = {
|
||||
{ /* Roland UM-1 */
|
||||
"Roland UM-1",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
|
||||
{ { 0x81, 1 }, {-1, -1} },
|
||||
{ { 0x01, 1,}, {-1, -1} },
|
||||
},
|
||||
|
||||
{ /* Roland UM-2 */
|
||||
"Roland UM-2" ,
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
|
||||
{ { 0x81, 3 }, {-1, -1} },
|
||||
{ { 0x01, 3,}, {-1, -1} },
|
||||
},
|
||||
|
||||
/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
|
||||
{ /* Roland UA-100 */
|
||||
"Roland UA-100",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
|
||||
{ { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
|
||||
{ { 0x02, 7 }, {-1, -1} },
|
||||
},
|
||||
|
||||
/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
|
||||
{ /* Roland SC8850 */
|
||||
"Roland SC8850",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
|
||||
{ { 0x81, 0x3f }, {-1, -1} },
|
||||
{ { 0x01, 0x3f }, {-1, -1} },
|
||||
},
|
||||
|
||||
{ /* Roland SC8820 */
|
||||
"Roland SC8820",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
|
||||
{ { 0x81, 0x13 }, {-1, -1} },
|
||||
{ { 0x01, 0x13 }, {-1, -1} },
|
||||
},
|
||||
|
||||
{ /* Roland SC8820 */
|
||||
"Roland SC8820",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
|
||||
{ { 0x81, 17 }, {-1, -1} },
|
||||
{ { 0x01, 17 }, {-1, -1} },
|
||||
},
|
||||
|
||||
{ /* YAMAHA MU1000 */
|
||||
"YAMAHA MU1000",
|
||||
USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1,
|
||||
{ { 0x81, 1 }, {-1, -1} },
|
||||
{ { 0x01, 15 }, {-1, -1} },
|
||||
},
|
||||
{ /* Roland PC-300 */
|
||||
"Roland PC-300",
|
||||
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1,
|
||||
{ { 0x81, 1 }, {-1, -1} },
|
||||
{ { 0x01, 1 }, {-1, -1} },
|
||||
},
|
||||
{ /* MOTU Fastlane USB */
|
||||
"MOTU Fastlane USB",
|
||||
USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0,
|
||||
{ { 0x82, 3 }, {-1, -1} },
|
||||
{ { 0x02, 3 }, {-1, -1} },
|
||||
}
|
||||
};
|
||||
|
||||
#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
|
||||
|
||||
/* for Hot-Plugging */
|
||||
|
||||
static struct usb_device_id usb_midi_ids [] = {
|
||||
{ .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
|
||||
.bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING},
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
|
||||
{ USB_DEVICE( USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE ) },
|
||||
/* { USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, usb_midi_ids);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
#endif /* _USB_MIDI_H_ */
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/lp.h>
|
||||
#include <linux/mutex.h>
|
||||
#undef DEBUG
|
||||
#include <linux/usb.h>
|
||||
|
||||
@ -223,7 +224,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp);
|
||||
|
||||
/* forward reference to make our lives easier */
|
||||
static struct usb_driver usblp_driver;
|
||||
static DECLARE_MUTEX(usblp_sem); /* locks the existence of usblp's */
|
||||
static DEFINE_MUTEX(usblp_mutex); /* locks the existence of usblp's */
|
||||
|
||||
/*
|
||||
* Functions for usblp control messages.
|
||||
@ -351,7 +352,7 @@ static int usblp_open(struct inode *inode, struct file *file)
|
||||
if (minor < 0)
|
||||
return -ENODEV;
|
||||
|
||||
down (&usblp_sem);
|
||||
mutex_lock (&usblp_mutex);
|
||||
|
||||
retval = -ENODEV;
|
||||
intf = usb_find_interface(&usblp_driver, minor);
|
||||
@ -399,7 +400,7 @@ static int usblp_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
}
|
||||
out:
|
||||
up (&usblp_sem);
|
||||
mutex_unlock (&usblp_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -425,13 +426,13 @@ static int usblp_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usblp *usblp = file->private_data;
|
||||
|
||||
down (&usblp_sem);
|
||||
mutex_lock (&usblp_mutex);
|
||||
usblp->used = 0;
|
||||
if (usblp->present) {
|
||||
usblp_unlink_urbs(usblp);
|
||||
} else /* finish cleanup from disconnect */
|
||||
usblp_cleanup (usblp);
|
||||
up (&usblp_sem);
|
||||
mutex_unlock (&usblp_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1152,7 +1153,7 @@ static void usblp_disconnect(struct usb_interface *intf)
|
||||
|
||||
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
|
||||
|
||||
down (&usblp_sem);
|
||||
mutex_lock (&usblp_mutex);
|
||||
down (&usblp->sem);
|
||||
usblp->present = 0;
|
||||
usb_set_intfdata (intf, NULL);
|
||||
@ -1166,7 +1167,7 @@ static void usblp_disconnect(struct usb_interface *intf)
|
||||
|
||||
if (!usblp->used)
|
||||
usblp_cleanup (usblp);
|
||||
up (&usblp_sem);
|
||||
mutex_unlock (&usblp_mutex);
|
||||
}
|
||||
|
||||
static struct usb_device_id usblp_ids [] = {
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "usb.h"
|
||||
@ -570,7 +571,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
|
||||
if (!access_ok(VERIFY_WRITE, buf, nbytes))
|
||||
return -EFAULT;
|
||||
|
||||
down (&usb_bus_list_lock);
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
/* print devices for all busses */
|
||||
list_for_each_entry(bus, &usb_bus_list, bus_list) {
|
||||
/* recurse through all children of the root hub */
|
||||
@ -580,12 +581,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
|
||||
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
|
||||
usb_unlock_device(bus->root_hub);
|
||||
if (ret < 0) {
|
||||
up(&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return ret;
|
||||
}
|
||||
total_written += ret;
|
||||
}
|
||||
up (&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
|
@ -134,26 +134,21 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
|
||||
}
|
||||
|
||||
if (pos < sizeof(struct usb_device_descriptor)) {
|
||||
struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
|
||||
if (!desc) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
|
||||
le16_to_cpus(&desc->bcdUSB);
|
||||
le16_to_cpus(&desc->idVendor);
|
||||
le16_to_cpus(&desc->idProduct);
|
||||
le16_to_cpus(&desc->bcdDevice);
|
||||
struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
|
||||
|
||||
memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
|
||||
le16_to_cpus(&temp_desc.bcdUSB);
|
||||
le16_to_cpus(&temp_desc.idVendor);
|
||||
le16_to_cpus(&temp_desc.idProduct);
|
||||
le16_to_cpus(&temp_desc.bcdDevice);
|
||||
|
||||
len = sizeof(struct usb_device_descriptor) - pos;
|
||||
if (len > nbytes)
|
||||
len = nbytes;
|
||||
if (copy_to_user(buf, ((char *)desc) + pos, len)) {
|
||||
kfree(desc);
|
||||
if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
kfree(desc);
|
||||
|
||||
*ppos += len;
|
||||
buf += len;
|
||||
@ -498,7 +493,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ps->dev->state != USB_STATE_CONFIGURED)
|
||||
if (ps->dev->state != USB_STATE_ADDRESS
|
||||
&& ps->dev->state != USB_STATE_CONFIGURED)
|
||||
return -EHOSTUNREACH;
|
||||
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
|
||||
return 0;
|
||||
|
@ -264,14 +264,19 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
|
||||
*/
|
||||
retval = pci_set_power_state (dev, PCI_D3hot);
|
||||
if (retval == 0) {
|
||||
dev_dbg (hcd->self.controller, "--> PCI D3\n");
|
||||
int wake = device_can_wakeup(&hcd->self.root_hub->dev);
|
||||
|
||||
wake = wake && device_may_wakeup(hcd->self.controller);
|
||||
|
||||
dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
|
||||
wake ? "/wakeup" : "");
|
||||
|
||||
/* Ignore these return values. We rely on pci code to
|
||||
* reject requests the hardware can't implement, rather
|
||||
* than coding the same thing.
|
||||
*/
|
||||
(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
|
||||
(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
|
||||
(void) pci_enable_wake (dev, PCI_D3hot, wake);
|
||||
(void) pci_enable_wake (dev, PCI_D3cold, wake);
|
||||
} else {
|
||||
dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
|
||||
retval);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <asm/scatterlist.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
@ -93,7 +94,7 @@ struct usb_busmap {
|
||||
static struct usb_busmap busmap;
|
||||
|
||||
/* used when updating list of hcds */
|
||||
DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */
|
||||
DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */
|
||||
EXPORT_SYMBOL_GPL (usb_bus_list_lock);
|
||||
|
||||
/* used for controlling access to virtual root hubs */
|
||||
@ -366,21 +367,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
|
||||
/* DEVICE REQUESTS */
|
||||
|
||||
/* The root hub's remote wakeup enable bit is implemented using
|
||||
* driver model wakeup flags. If this system supports wakeup
|
||||
* through USB, userspace may change the default "allow wakeup"
|
||||
* policy through sysfs or these calls.
|
||||
*
|
||||
* Most root hubs support wakeup from downstream devices, for
|
||||
* runtime power management (disabling USB clocks and reducing
|
||||
* VBUS power usage). However, not all of them do so; silicon,
|
||||
* board, and BIOS bugs here are not uncommon, so these can't
|
||||
* be treated quite like external hubs.
|
||||
*
|
||||
* Likewise, not all root hubs will pass wakeup events upstream,
|
||||
* to wake up the whole system. So don't assume root hub and
|
||||
* controller capabilities are identical.
|
||||
*/
|
||||
|
||||
case DeviceRequest | USB_REQ_GET_STATUS:
|
||||
tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
|
||||
tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
|
||||
<< USB_DEVICE_REMOTE_WAKEUP)
|
||||
| (1 << USB_DEVICE_SELF_POWERED);
|
||||
tbuf [1] = 0;
|
||||
len = 2;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (wValue == USB_DEVICE_REMOTE_WAKEUP)
|
||||
hcd->remote_wakeup = 0;
|
||||
device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
|
||||
hcd->remote_wakeup = 1;
|
||||
if (device_can_wakeup(&hcd->self.root_hub->dev)
|
||||
&& wValue == USB_DEVICE_REMOTE_WAKEUP)
|
||||
device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
@ -409,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
bufp = fs_rh_config_descriptor;
|
||||
len = sizeof fs_rh_config_descriptor;
|
||||
}
|
||||
if (hcd->can_wakeup)
|
||||
if (device_can_wakeup(&hcd->self.root_hub->dev))
|
||||
patch_wakeup = 1;
|
||||
break;
|
||||
case USB_DT_STRING << 8:
|
||||
@ -761,14 +780,14 @@ static int usb_register_bus(struct usb_bus *bus)
|
||||
{
|
||||
int busnum;
|
||||
|
||||
down (&usb_bus_list_lock);
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
|
||||
if (busnum < USB_MAXBUS) {
|
||||
set_bit (busnum, busmap.busmap);
|
||||
bus->busnum = busnum;
|
||||
} else {
|
||||
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
|
||||
up(&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
@ -776,7 +795,7 @@ static int usb_register_bus(struct usb_bus *bus)
|
||||
bus->controller, "usb_host%d", busnum);
|
||||
if (IS_ERR(bus->class_dev)) {
|
||||
clear_bit(busnum, busmap.busmap);
|
||||
up(&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return PTR_ERR(bus->class_dev);
|
||||
}
|
||||
|
||||
@ -784,7 +803,7 @@ static int usb_register_bus(struct usb_bus *bus)
|
||||
|
||||
/* Add it to the local list of buses */
|
||||
list_add (&bus->bus_list, &usb_bus_list);
|
||||
up (&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
|
||||
usb_notify_add_bus(bus);
|
||||
|
||||
@ -809,9 +828,9 @@ static void usb_deregister_bus (struct usb_bus *bus)
|
||||
* controller code, as well as having it call this when cleaning
|
||||
* itself up
|
||||
*/
|
||||
down (&usb_bus_list_lock);
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
list_del (&bus->bus_list);
|
||||
up (&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
|
||||
usb_notify_remove_bus(bus);
|
||||
|
||||
@ -822,18 +841,17 @@ static void usb_deregister_bus (struct usb_bus *bus)
|
||||
|
||||
/**
|
||||
* register_root_hub - called by usb_add_hcd() to register a root hub
|
||||
* @usb_dev: the usb root hub device to be registered.
|
||||
* @hcd: host controller for this root hub
|
||||
*
|
||||
* This function registers the root hub with the USB subsystem. It sets up
|
||||
* the device properly in the device tree and stores the root_hub pointer
|
||||
* in the bus structure, then calls usb_new_device() to register the usb
|
||||
* device. It also assigns the root hub's USB address (always 1).
|
||||
* the device properly in the device tree and then calls usb_new_device()
|
||||
* to register the usb device. It also assigns the root hub's USB address
|
||||
* (always 1).
|
||||
*/
|
||||
static int register_root_hub (struct usb_device *usb_dev,
|
||||
struct usb_hcd *hcd)
|
||||
static int register_root_hub(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *parent_dev = hcd->self.controller;
|
||||
struct usb_device *usb_dev = hcd->self.root_hub;
|
||||
const int devnum = 1;
|
||||
int retval;
|
||||
|
||||
@ -844,14 +862,12 @@ static int register_root_hub (struct usb_device *usb_dev,
|
||||
set_bit (devnum, usb_dev->bus->devmap.devicemap);
|
||||
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
|
||||
|
||||
down (&usb_bus_list_lock);
|
||||
usb_dev->bus->root_hub = usb_dev;
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
|
||||
usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
|
||||
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
|
||||
if (retval != sizeof usb_dev->descriptor) {
|
||||
usb_dev->bus->root_hub = NULL;
|
||||
up (&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
|
||||
usb_dev->dev.bus_id, retval);
|
||||
return (retval < 0) ? retval : -EMSGSIZE;
|
||||
@ -859,11 +875,10 @@ static int register_root_hub (struct usb_device *usb_dev,
|
||||
|
||||
retval = usb_new_device (usb_dev);
|
||||
if (retval) {
|
||||
usb_dev->bus->root_hub = NULL;
|
||||
dev_err (parent_dev, "can't register root hub for %s, %d\n",
|
||||
usb_dev->dev.bus_id, retval);
|
||||
}
|
||||
up (&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
|
||||
if (retval == 0) {
|
||||
spin_lock_irq (&hcd_root_hub_lock);
|
||||
@ -1090,7 +1105,6 @@ static void urb_unlink (struct urb *urb)
|
||||
spin_lock_irqsave (&hcd_data_lock, flags);
|
||||
list_del_init (&urb->urb_list);
|
||||
spin_unlock_irqrestore (&hcd_data_lock, flags);
|
||||
usb_put_dev (urb->dev);
|
||||
}
|
||||
|
||||
|
||||
@ -1130,7 +1144,6 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
|
||||
case HC_STATE_RUNNING:
|
||||
case HC_STATE_RESUMING:
|
||||
doit:
|
||||
usb_get_dev (urb->dev);
|
||||
list_add_tail (&urb->urb_list, &ep->urb_list);
|
||||
status = 0;
|
||||
break;
|
||||
@ -1771,12 +1784,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* till now HC has been in an indeterminate state ... */
|
||||
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
|
||||
dev_err(hcd->self.controller, "can't reset\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* HC is in reset state, but accessible. Now do the one-time init,
|
||||
* bottom up so that hcds can customize the root hubs before khubd
|
||||
* starts talking to them. (Note, bus id is assigned early too.)
|
||||
*/
|
||||
if ((retval = hcd_buffer_create(hcd)) != 0) {
|
||||
dev_dbg(hcd->self.controller, "pool alloc failed\n");
|
||||
return retval;
|
||||
@ -1785,6 +1796,36 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
if ((retval = usb_register_bus(&hcd->self)) < 0)
|
||||
goto err_register_bus;
|
||||
|
||||
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
|
||||
dev_err(hcd->self.controller, "unable to allocate root hub\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
|
||||
USB_SPEED_FULL;
|
||||
hcd->self.root_hub = rhdev;
|
||||
|
||||
/* "reset" is misnamed; its role is now one-time init. the controller
|
||||
* should already have been reset (and boot firmware kicked off etc).
|
||||
*/
|
||||
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
|
||||
dev_err(hcd->self.controller, "can't setup\n");
|
||||
goto err_hcd_driver_setup;
|
||||
}
|
||||
|
||||
/* wakeup flag init is in transition; for now we can't rely on PCI to
|
||||
* initialize these bits properly, so we let reset() override it.
|
||||
* This init should _precede_ the reset() once PCI behaves.
|
||||
*/
|
||||
device_init_wakeup(&rhdev->dev,
|
||||
device_can_wakeup(hcd->self.controller));
|
||||
|
||||
/* NOTE: root hub and controller capabilities may not be the same */
|
||||
if (device_can_wakeup(hcd->self.controller)
|
||||
&& device_can_wakeup(&hcd->self.root_hub->dev))
|
||||
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
|
||||
|
||||
/* enable irqs just before we start the controller */
|
||||
if (hcd->driver->irq) {
|
||||
char buf[8], *bufp = buf;
|
||||
|
||||
@ -1816,56 +1857,32 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
(unsigned long long)hcd->rsrc_start);
|
||||
}
|
||||
|
||||
/* Allocate the root hub before calling hcd->driver->start(),
|
||||
* but don't register it until afterward so that the hardware
|
||||
* is running.
|
||||
*/
|
||||
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
|
||||
dev_err(hcd->self.controller, "unable to allocate root hub\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
|
||||
/* Although in principle hcd->driver->start() might need to use rhdev,
|
||||
* none of the current drivers do.
|
||||
*/
|
||||
if ((retval = hcd->driver->start(hcd)) < 0) {
|
||||
dev_err(hcd->self.controller, "startup error %d\n", retval);
|
||||
goto err_hcd_driver_start;
|
||||
}
|
||||
|
||||
/* hcd->driver->start() reported can_wakeup, probably with
|
||||
* assistance from board's boot firmware.
|
||||
* NOTE: normal devices won't enable wakeup by default.
|
||||
*/
|
||||
if (hcd->can_wakeup)
|
||||
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
|
||||
hcd->remote_wakeup = hcd->can_wakeup;
|
||||
|
||||
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
|
||||
USB_SPEED_FULL;
|
||||
/* starting here, usbcore will pay attention to this root hub */
|
||||
rhdev->bus_mA = min(500u, hcd->power_budget);
|
||||
if ((retval = register_root_hub(rhdev, hcd)) != 0)
|
||||
if ((retval = register_root_hub(hcd)) != 0)
|
||||
goto err_register_root_hub;
|
||||
|
||||
if (hcd->uses_new_polling && hcd->poll_rh)
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
return retval;
|
||||
|
||||
err_register_root_hub:
|
||||
err_register_root_hub:
|
||||
hcd->driver->stop(hcd);
|
||||
|
||||
err_hcd_driver_start:
|
||||
usb_put_dev(rhdev);
|
||||
|
||||
err_allocate_root_hub:
|
||||
err_hcd_driver_start:
|
||||
if (hcd->irq >= 0)
|
||||
free_irq(irqnum, hcd);
|
||||
|
||||
err_request_irq:
|
||||
err_request_irq:
|
||||
err_hcd_driver_setup:
|
||||
hcd->self.root_hub = NULL;
|
||||
usb_put_dev(rhdev);
|
||||
err_allocate_root_hub:
|
||||
usb_deregister_bus(&hcd->self);
|
||||
|
||||
err_register_bus:
|
||||
err_register_bus:
|
||||
hcd_buffer_destroy(hcd);
|
||||
return retval;
|
||||
}
|
||||
@ -1891,9 +1908,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
|
||||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
down(&usb_bus_list_lock);
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
usb_disconnect(&hcd->self.root_hub);
|
||||
up(&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
|
||||
hcd->poll_rh = 0;
|
||||
del_timer_sync(&hcd->rh_timer);
|
||||
|
@ -78,8 +78,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
|
||||
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
|
||||
#define HCD_FLAG_SAW_IRQ 0x00000002
|
||||
|
||||
unsigned can_wakeup:1; /* hw supports wakeup? */
|
||||
unsigned remote_wakeup:1;/* sw should use wakeup? */
|
||||
unsigned rh_registered:1;/* is root hub registered? */
|
||||
|
||||
/* The next flag is a stopgap, to be removed when all the HCDs
|
||||
@ -364,7 +362,7 @@ extern void usb_set_device_state(struct usb_device *udev,
|
||||
/* exported only within usbcore */
|
||||
|
||||
extern struct list_head usb_bus_list;
|
||||
extern struct semaphore usb_bus_list_lock;
|
||||
extern struct mutex usb_bus_list_lock;
|
||||
extern wait_queue_head_t usb_kill_urb_queue;
|
||||
|
||||
extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/uaccess.h>
|
||||
@ -1005,12 +1006,18 @@ void usb_set_device_state(struct usb_device *udev,
|
||||
; /* do nothing */
|
||||
else if (new_state != USB_STATE_NOTATTACHED) {
|
||||
udev->state = new_state;
|
||||
if (new_state == USB_STATE_CONFIGURED)
|
||||
device_init_wakeup(&udev->dev,
|
||||
(udev->actconfig->desc.bmAttributes
|
||||
& USB_CONFIG_ATT_WAKEUP));
|
||||
else if (new_state != USB_STATE_SUSPENDED)
|
||||
device_init_wakeup(&udev->dev, 0);
|
||||
|
||||
/* root hub wakeup capabilities are managed out-of-band
|
||||
* and may involve silicon errata ... ignore them here.
|
||||
*/
|
||||
if (udev->parent) {
|
||||
if (new_state == USB_STATE_CONFIGURED)
|
||||
device_init_wakeup(&udev->dev,
|
||||
(udev->actconfig->desc.bmAttributes
|
||||
& USB_CONFIG_ATT_WAKEUP));
|
||||
else if (new_state != USB_STATE_SUSPENDED)
|
||||
device_init_wakeup(&udev->dev, 0);
|
||||
}
|
||||
} else
|
||||
recursively_mark_NOTATTACHED(udev);
|
||||
spin_unlock_irqrestore(&device_state_lock, flags);
|
||||
@ -1172,8 +1179,11 @@ static int choose_configuration(struct usb_device *udev)
|
||||
c = udev->config;
|
||||
num_configs = udev->descriptor.bNumConfigurations;
|
||||
for (i = 0; i < num_configs; (i++, c++)) {
|
||||
struct usb_interface_descriptor *desc =
|
||||
&c->intf_cache[0]->altsetting->desc;
|
||||
struct usb_interface_descriptor *desc = NULL;
|
||||
|
||||
/* It's possible that a config has no interfaces! */
|
||||
if (c->desc.bNumInterfaces > 0)
|
||||
desc = &c->intf_cache[0]->altsetting->desc;
|
||||
|
||||
/*
|
||||
* HP's USB bus-powered keyboard has only one configuration
|
||||
@ -1208,7 +1218,8 @@ static int choose_configuration(struct usb_device *udev)
|
||||
/* If the first config's first interface is COMM/2/0xff
|
||||
* (MSFT RNDIS), rule it out unless Linux has host-side
|
||||
* RNDIS support. */
|
||||
if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
|
||||
if (i == 0 && desc
|
||||
&& desc->bInterfaceClass == USB_CLASS_COMM
|
||||
&& desc->bInterfaceSubClass == 2
|
||||
&& desc->bInterfaceProtocol == 0xff) {
|
||||
#ifndef CONFIG_USB_NET_RNDIS
|
||||
@ -1224,8 +1235,8 @@ static int choose_configuration(struct usb_device *udev)
|
||||
* than a vendor-specific driver. */
|
||||
else if (udev->descriptor.bDeviceClass !=
|
||||
USB_CLASS_VENDOR_SPEC &&
|
||||
desc->bInterfaceClass !=
|
||||
USB_CLASS_VENDOR_SPEC) {
|
||||
(!desc || desc->bInterfaceClass !=
|
||||
USB_CLASS_VENDOR_SPEC)) {
|
||||
best = c;
|
||||
break;
|
||||
}
|
||||
@ -1876,18 +1887,18 @@ int usb_resume_device(struct usb_device *udev)
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
/* selective resume of one downstream hub-to-device port */
|
||||
if (udev->parent) {
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
if (udev->state == USB_STATE_SUSPENDED) {
|
||||
// NOTE swsusp may bork us, device state being wrong...
|
||||
// NOTE this fails if parent is also suspended...
|
||||
status = hub_port_resume(hdev_to_hub(udev->parent),
|
||||
udev->portnum, udev);
|
||||
} else
|
||||
#endif
|
||||
status = 0;
|
||||
} else
|
||||
#endif
|
||||
status = finish_device_resume(udev);
|
||||
if (status < 0)
|
||||
dev_dbg(&udev->dev, "can't resume, status %d\n",
|
||||
@ -2162,7 +2173,7 @@ static int
|
||||
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
int retry_counter)
|
||||
{
|
||||
static DECLARE_MUTEX(usb_address0_sem);
|
||||
static DEFINE_MUTEX(usb_address0_mutex);
|
||||
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int i, j, retval;
|
||||
@ -2183,7 +2194,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
if (oldspeed == USB_SPEED_LOW)
|
||||
delay = HUB_LONG_RESET_TIME;
|
||||
|
||||
down(&usb_address0_sem);
|
||||
mutex_lock(&usb_address0_mutex);
|
||||
|
||||
/* Reset the device; full speed may morph to high speed */
|
||||
retval = hub_port_reset(hub, port1, udev, delay);
|
||||
@ -2381,7 +2392,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
fail:
|
||||
if (retval)
|
||||
hub_port_disable(hub, port1, 0);
|
||||
up(&usb_address0_sem);
|
||||
mutex_unlock(&usb_address0_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -3017,7 +3028,7 @@ int usb_reset_device(struct usb_device *udev)
|
||||
parent_hub = hdev_to_hub(parent_hdev);
|
||||
|
||||
/* If we're resetting an active hub, take some special actions */
|
||||
if (udev->actconfig &&
|
||||
if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
|
||||
udev->actconfig->interface[0]->dev.driver ==
|
||||
&hub_driver.driver &&
|
||||
(hub = hdev_to_hub(udev)) != NULL) {
|
||||
|
@ -631,8 +631,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
|
||||
* Returns the number of bytes received on success, or else the status code
|
||||
* returned by the underlying usb_control_msg() call.
|
||||
*/
|
||||
int usb_get_string(struct usb_device *dev, unsigned short langid,
|
||||
unsigned char index, void *buf, int size)
|
||||
static int usb_get_string(struct usb_device *dev, unsigned short langid,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
@ -1388,11 +1388,13 @@ free_interfaces:
|
||||
if (dev->state != USB_STATE_ADDRESS)
|
||||
usb_disable_device (dev, 1); // Skip ep0
|
||||
|
||||
i = dev->bus_mA - cp->desc.bMaxPower * 2;
|
||||
if (i < 0)
|
||||
dev_warn(&dev->dev, "new config #%d exceeds power "
|
||||
"limit by %dmA\n",
|
||||
configuration, -i);
|
||||
if (cp) {
|
||||
i = dev->bus_mA - cp->desc.bMaxPower * 2;
|
||||
if (i < 0)
|
||||
dev_warn(&dev->dev, "new config #%d exceeds power "
|
||||
"limit by %dmA\n",
|
||||
configuration, -i);
|
||||
}
|
||||
|
||||
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
@ -1488,7 +1490,6 @@ EXPORT_SYMBOL(usb_sg_wait);
|
||||
// synchronous control message convenience routines
|
||||
EXPORT_SYMBOL(usb_get_descriptor);
|
||||
EXPORT_SYMBOL(usb_get_status);
|
||||
EXPORT_SYMBOL(usb_get_string);
|
||||
EXPORT_SYMBOL(usb_string);
|
||||
|
||||
// synchronous calls that also maintain usbcore state
|
||||
|
@ -13,16 +13,17 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
static struct notifier_block *usb_notifier_list;
|
||||
static DECLARE_MUTEX(usb_notifier_lock);
|
||||
static DEFINE_MUTEX(usb_notifier_lock);
|
||||
|
||||
static void usb_notifier_chain_register(struct notifier_block **list,
|
||||
struct notifier_block *n)
|
||||
{
|
||||
down(&usb_notifier_lock);
|
||||
mutex_lock(&usb_notifier_lock);
|
||||
while (*list) {
|
||||
if (n->priority > (*list)->priority)
|
||||
break;
|
||||
@ -30,13 +31,13 @@ static void usb_notifier_chain_register(struct notifier_block **list,
|
||||
}
|
||||
n->next = *list;
|
||||
*list = n;
|
||||
up(&usb_notifier_lock);
|
||||
mutex_unlock(&usb_notifier_lock);
|
||||
}
|
||||
|
||||
static void usb_notifier_chain_unregister(struct notifier_block **nl,
|
||||
struct notifier_block *n)
|
||||
{
|
||||
down(&usb_notifier_lock);
|
||||
mutex_lock(&usb_notifier_lock);
|
||||
while ((*nl)!=NULL) {
|
||||
if ((*nl)==n) {
|
||||
*nl = n->next;
|
||||
@ -45,7 +46,7 @@ static void usb_notifier_chain_unregister(struct notifier_block **nl,
|
||||
nl=&((*nl)->next);
|
||||
}
|
||||
exit:
|
||||
up(&usb_notifier_lock);
|
||||
mutex_unlock(&usb_notifier_lock);
|
||||
}
|
||||
|
||||
static int usb_notifier_call_chain(struct notifier_block **n,
|
||||
@ -54,7 +55,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
|
||||
int ret=NOTIFY_DONE;
|
||||
struct notifier_block *nb = *n;
|
||||
|
||||
down(&usb_notifier_lock);
|
||||
mutex_lock(&usb_notifier_lock);
|
||||
while (nb) {
|
||||
ret = nb->notifier_call(nb,val,v);
|
||||
if (ret&NOTIFY_STOP_MASK) {
|
||||
@ -63,7 +64,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
|
||||
nb = nb->next;
|
||||
}
|
||||
exit:
|
||||
up(&usb_notifier_lock);
|
||||
mutex_unlock(&usb_notifier_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/scatterlist.h>
|
||||
@ -639,7 +640,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev = NULL;
|
||||
|
||||
down(&usb_bus_list_lock);
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
for (buslist = usb_bus_list.next;
|
||||
buslist != &usb_bus_list;
|
||||
buslist = buslist->next) {
|
||||
@ -653,7 +654,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
up(&usb_bus_list_lock);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@ -187,6 +187,23 @@ config USB_OTG
|
||||
|
||||
Select this only if your OMAP board has a Mini-AB connector.
|
||||
|
||||
config USB_GADGET_AT91
|
||||
boolean "AT91 USB Device Port"
|
||||
depends on ARCH_AT91RM9200
|
||||
select USB_GADGET_SELECTED
|
||||
help
|
||||
Many Atmel AT91 processors (such as the AT91RM2000) have a
|
||||
full speed USB Device Port with support for five configurable
|
||||
endpoints (plus endpoint zero).
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "at91_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_AT91
|
||||
tristate
|
||||
depends on USB_GADGET_AT91
|
||||
default USB_GADGET
|
||||
|
||||
config USB_GADGET_DUMMY_HCD
|
||||
boolean "Dummy HCD (DEVELOPMENT)"
|
||||
|
@ -7,6 +7,7 @@ obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
|
||||
obj-$(CONFIG_USB_GOKU) += goku_udc.o
|
||||
obj-$(CONFIG_USB_OMAP) += omap_udc.o
|
||||
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
|
||||
obj-$(CONFIG_USB_AT91) += at91_udc.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
1773
drivers/usb/gadget/at91_udc.c
Normal file
1773
drivers/usb/gadget/at91_udc.c
Normal file
File diff suppressed because it is too large
Load Diff
181
drivers/usb/gadget/at91_udc.h
Normal file
181
drivers/usb/gadget/at91_udc.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2004 by Thomas Rathbone, HP Labs
|
||||
* Copyright (C) 2005 by Ivan Kokshaysky
|
||||
* Copyright (C) 2006 by SAN People
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef AT91_UDC_H
|
||||
#define AT91_UDC_H
|
||||
|
||||
/*
|
||||
* USB Device Port (UDP) registers.
|
||||
* Based on AT91RM9200 datasheet revision E.
|
||||
*/
|
||||
|
||||
#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */
|
||||
#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */
|
||||
#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */
|
||||
#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */
|
||||
|
||||
#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */
|
||||
#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */
|
||||
#define AT91_UDP_CONFG (1 << 1) /* Configured */
|
||||
#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */
|
||||
#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */
|
||||
#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */
|
||||
|
||||
#define AT91_UDP_FADDR 0x08 /* Function Address Register */
|
||||
#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */
|
||||
#define AT91_UDP_FEN (1 << 8) /* Function Enable */
|
||||
|
||||
#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */
|
||||
#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */
|
||||
#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */
|
||||
|
||||
#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */
|
||||
#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */
|
||||
#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */
|
||||
#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */
|
||||
#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */
|
||||
#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
|
||||
#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */
|
||||
#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */
|
||||
|
||||
#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */
|
||||
#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */
|
||||
|
||||
#define AT91_UDP_CSR(n) (0x30+((n)*4)) /* Endpoint Control/Status Registers 0-7 */
|
||||
#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */
|
||||
#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */
|
||||
#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */
|
||||
#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */
|
||||
#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */
|
||||
#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */
|
||||
#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */
|
||||
#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */
|
||||
#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */
|
||||
#define AT91_UDP_EPTYPE_CTRL (0 << 8)
|
||||
#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8)
|
||||
#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8)
|
||||
#define AT91_UDP_EPTYPE_INT_OUT (3 << 8)
|
||||
#define AT91_UDP_EPTYPE_ISO_IN (5 << 8)
|
||||
#define AT91_UDP_EPTYPE_BULK_IN (6 << 8)
|
||||
#define AT91_UDP_EPTYPE_INT_IN (7 << 8)
|
||||
#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */
|
||||
#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */
|
||||
#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */
|
||||
|
||||
#define AT91_UDP_FDR(n) (0x50+((n)*4)) /* Endpoint FIFO Data Registers 0-7 */
|
||||
|
||||
#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */
|
||||
#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* controller driver data structures
|
||||
*/
|
||||
|
||||
#define NUM_ENDPOINTS 6
|
||||
|
||||
/*
|
||||
* hardware won't disable bus reset, or resume while the controller
|
||||
* is suspended ... watching suspend helps keep the logic symmetric.
|
||||
*/
|
||||
#define MINIMUS_INTERRUPTUS \
|
||||
(AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
|
||||
|
||||
struct at91_ep {
|
||||
struct usb_ep ep;
|
||||
struct list_head queue;
|
||||
struct at91_udc *udc;
|
||||
void __iomem *creg;
|
||||
|
||||
unsigned maxpacket:16;
|
||||
u8 int_mask;
|
||||
unsigned is_pingpong:1;
|
||||
|
||||
unsigned stopped:1;
|
||||
unsigned is_in:1;
|
||||
unsigned is_iso:1;
|
||||
unsigned fifo_bank:1;
|
||||
|
||||
const struct usb_endpoint_descriptor
|
||||
*desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* driver is non-SMP, and just blocks IRQs whenever it needs
|
||||
* access protection for chip registers or driver state
|
||||
*/
|
||||
struct at91_udc {
|
||||
struct usb_gadget gadget;
|
||||
struct at91_ep ep[NUM_ENDPOINTS];
|
||||
struct usb_gadget_driver *driver;
|
||||
unsigned vbus:1;
|
||||
unsigned enabled:1;
|
||||
unsigned clocked:1;
|
||||
unsigned suspended:1;
|
||||
unsigned req_pending:1;
|
||||
unsigned wait_for_addr_ack:1;
|
||||
unsigned wait_for_config_ack:1;
|
||||
unsigned selfpowered:1;
|
||||
u8 addr;
|
||||
struct at91_udc_data board;
|
||||
struct clk *iclk, *fclk;
|
||||
struct platform_device *pdev;
|
||||
struct proc_dir_entry *pde;
|
||||
};
|
||||
|
||||
static inline struct at91_udc *to_udc(struct usb_gadget *g)
|
||||
{
|
||||
return container_of(g, struct at91_udc, gadget);
|
||||
}
|
||||
|
||||
struct at91_request {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff)
|
||||
#else
|
||||
#define DBG(stuff...) do{}while(0)
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE
|
||||
# define VDBG DBG
|
||||
#else
|
||||
# define VDBG(stuff...) do{}while(0)
|
||||
#endif
|
||||
|
||||
#ifdef PACKET_TRACE
|
||||
# define PACKET VDBG
|
||||
#else
|
||||
# define PACKET(stuff...) do{}while(0)
|
||||
#endif
|
||||
|
||||
#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
|
||||
#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
|
||||
#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
|
||||
|
||||
#endif
|
||||
|
@ -478,10 +478,9 @@ dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
|
||||
return NULL;
|
||||
ep = usb_ep_to_dummy_ep (_ep);
|
||||
|
||||
req = kmalloc (sizeof *req, mem_flags);
|
||||
req = kzalloc(sizeof(*req), mem_flags);
|
||||
if (!req)
|
||||
return NULL;
|
||||
memset (req, 0, sizeof *req);
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
return &req->req;
|
||||
}
|
||||
|
@ -182,33 +182,37 @@ struct eth_dev {
|
||||
* parameters are in UTF-8 (superset of ASCII's 7 bit characters).
|
||||
*/
|
||||
|
||||
static ushort __initdata idVendor;
|
||||
static ushort idVendor;
|
||||
module_param(idVendor, ushort, S_IRUGO);
|
||||
MODULE_PARM_DESC(idVendor, "USB Vendor ID");
|
||||
|
||||
static ushort __initdata idProduct;
|
||||
static ushort idProduct;
|
||||
module_param(idProduct, ushort, S_IRUGO);
|
||||
MODULE_PARM_DESC(idProduct, "USB Product ID");
|
||||
|
||||
static ushort __initdata bcdDevice;
|
||||
static ushort bcdDevice;
|
||||
module_param(bcdDevice, ushort, S_IRUGO);
|
||||
MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
|
||||
|
||||
static char *__initdata iManufacturer;
|
||||
static char *iManufacturer;
|
||||
module_param(iManufacturer, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
|
||||
|
||||
static char *__initdata iProduct;
|
||||
static char *iProduct;
|
||||
module_param(iProduct, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(iProduct, "USB Product string");
|
||||
|
||||
static char *iSerialNumber;
|
||||
module_param(iSerialNumber, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
|
||||
|
||||
/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
|
||||
static char *__initdata dev_addr;
|
||||
static char *dev_addr;
|
||||
module_param(dev_addr, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
|
||||
|
||||
/* this address is invisible to ifconfig */
|
||||
static char *__initdata host_addr;
|
||||
static char *host_addr;
|
||||
module_param(host_addr, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
|
||||
|
||||
@ -253,6 +257,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
|
||||
#define DEV_CONFIG_CDC
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHSFC
|
||||
#define DEV_CONFIG_CDC
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHDRC
|
||||
#define DEV_CONFIG_CDC
|
||||
#endif
|
||||
|
||||
|
||||
/* For CDC-incapable hardware, choose the simple cdc subset.
|
||||
* Anything that talks bulk (without notable bugs) can do this.
|
||||
@ -395,6 +407,7 @@ static inline int BITRATE(struct usb_gadget *g)
|
||||
#define STRING_CDC 7
|
||||
#define STRING_SUBSET 8
|
||||
#define STRING_RNDIS 9
|
||||
#define STRING_SERIALNUMBER 10
|
||||
|
||||
/* holds our biggest descriptor (or RNDIS response) */
|
||||
#define USB_BUFSIZ 256
|
||||
@ -862,6 +875,7 @@ static inline void __init hs_subset_descriptors(void)
|
||||
|
||||
static char manufacturer [50];
|
||||
static char product_desc [40] = DRIVER_DESC;
|
||||
static char serial_number [20];
|
||||
|
||||
#ifdef DEV_CONFIG_CDC
|
||||
/* address that the host will use ... usually assigned at random */
|
||||
@ -872,6 +886,7 @@ static char ethaddr [2 * ETH_ALEN + 1];
|
||||
static struct usb_string strings [] = {
|
||||
{ STRING_MANUFACTURER, manufacturer, },
|
||||
{ STRING_PRODUCT, product_desc, },
|
||||
{ STRING_SERIALNUMBER, serial_number, },
|
||||
{ STRING_DATA, "Ethernet Data", },
|
||||
#ifdef DEV_CONFIG_CDC
|
||||
{ STRING_CDC, "CDC Ethernet", },
|
||||
@ -1549,7 +1564,8 @@ static int eth_change_mtu (struct net_device *net, int new_mtu)
|
||||
{
|
||||
struct eth_dev *dev = netdev_priv(net);
|
||||
|
||||
// FIXME if rndis, don't change while link's live
|
||||
if (dev->rndis)
|
||||
return -EBUSY;
|
||||
|
||||
if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
|
||||
return -ERANGE;
|
||||
@ -2116,7 +2132,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static void __exit
|
||||
eth_unbind (struct usb_gadget *gadget)
|
||||
{
|
||||
struct eth_dev *dev = get_gadget_data (gadget);
|
||||
@ -2153,7 +2169,7 @@ static u8 __init nibble (unsigned char c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init get_ether_addr (const char *str, u8 *dev_addr)
|
||||
static int __init get_ether_addr(const char *str, u8 *dev_addr)
|
||||
{
|
||||
if (str) {
|
||||
unsigned i;
|
||||
@ -2168,9 +2184,10 @@ static void __init get_ether_addr (const char *str, u8 *dev_addr)
|
||||
dev_addr [i] = num;
|
||||
}
|
||||
if (is_valid_ether_addr (dev_addr))
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
random_ether_addr(dev_addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init
|
||||
@ -2268,6 +2285,10 @@ eth_bind (struct usb_gadget *gadget)
|
||||
strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
|
||||
if (iProduct)
|
||||
strlcpy (product_desc, iProduct, sizeof product_desc);
|
||||
if (iSerialNumber) {
|
||||
device_desc.iSerialNumber = STRING_SERIALNUMBER,
|
||||
strlcpy(serial_number, iSerialNumber, sizeof serial_number);
|
||||
}
|
||||
|
||||
/* all we really need is bulk IN/OUT */
|
||||
usb_ep_autoconfig_reset (gadget);
|
||||
@ -2377,9 +2398,13 @@ autoconf_fail:
|
||||
* The host side address is used with CDC and RNDIS, and commonly
|
||||
* ends up in a persistent config database.
|
||||
*/
|
||||
get_ether_addr(dev_addr, net->dev_addr);
|
||||
if (get_ether_addr(dev_addr, net->dev_addr))
|
||||
dev_warn(&gadget->dev,
|
||||
"using random %s ethernet address\n", "self");
|
||||
if (cdc || rndis) {
|
||||
get_ether_addr(host_addr, dev->host_mac);
|
||||
if (get_ether_addr(host_addr, dev->host_mac))
|
||||
dev_warn(&gadget->dev,
|
||||
"using random %s ethernet address\n", "host");
|
||||
#ifdef DEV_CONFIG_CDC
|
||||
snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
|
||||
dev->host_mac [0], dev->host_mac [1],
|
||||
@ -2523,7 +2548,7 @@ static struct usb_gadget_driver eth_driver = {
|
||||
|
||||
.function = (char *) driver_desc,
|
||||
.bind = eth_bind,
|
||||
.unbind = eth_unbind,
|
||||
.unbind = __exit_p(eth_unbind),
|
||||
|
||||
.setup = eth_setup,
|
||||
.disconnect = eth_disconnect,
|
||||
|
@ -3678,7 +3678,7 @@ static void lun_release(struct device *dev)
|
||||
kref_put(&fsg->ref, fsg_release);
|
||||
}
|
||||
|
||||
static void fsg_unbind(struct usb_gadget *gadget)
|
||||
static void __exit fsg_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct fsg_dev *fsg = get_gadget_data(gadget);
|
||||
int i;
|
||||
@ -4064,7 +4064,7 @@ static struct usb_gadget_driver fsg_driver = {
|
||||
#endif
|
||||
.function = (char *) longname,
|
||||
.bind = fsg_bind,
|
||||
.unbind = fsg_unbind,
|
||||
.unbind = __exit_p(fsg_unbind),
|
||||
.disconnect = fsg_disconnect,
|
||||
.setup = fsg_setup,
|
||||
.suspend = fsg_suspend,
|
||||
|
@ -3,9 +3,9 @@
|
||||
* gadget drivers or other code that needs to deal with them, and which
|
||||
* autoconfigures instead of using early binding to the hardware.
|
||||
*
|
||||
* This could eventually work like the ARM mach_is_*() stuff, driven by
|
||||
* This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
|
||||
* some config file that gets updated as new hardware is supported.
|
||||
* (And avoiding the runtime comparisons in typical one-choice cases.)
|
||||
* (And avoiding all runtime comparisons in typical one-choice configs!)
|
||||
*
|
||||
* NOTE: some of these controller drivers may not be available yet.
|
||||
*/
|
||||
@ -93,6 +93,26 @@
|
||||
#define gadget_is_imx(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed function controller */
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHSFC
|
||||
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhsfc(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed "dual role" controller, peripheral mode */
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHDRC
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musbhdrc_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhdrc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MPC8272
|
||||
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_mpc8272(g) 0
|
||||
#endif
|
||||
|
||||
// CONFIG_USB_GADGET_SX2
|
||||
// CONFIG_USB_GADGET_AU1X00
|
||||
// ...
|
||||
@ -143,5 +163,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
||||
return 0x13;
|
||||
else if (gadget_is_imx(gadget))
|
||||
return 0x14;
|
||||
else if (gadget_is_musbhsfc(gadget))
|
||||
return 0x15;
|
||||
else if (gadget_is_musbhdrc(gadget))
|
||||
return 0x16;
|
||||
else if (gadget_is_mpc8272(gadget))
|
||||
return 0x17;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -275,11 +275,10 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
|
||||
|
||||
if (!_ep)
|
||||
return NULL;
|
||||
req = kmalloc(sizeof *req, gfp_flags);
|
||||
req = kzalloc(sizeof *req, gfp_flags);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
memset(req, 0, sizeof *req);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
return &req->req;
|
||||
|
@ -170,10 +170,9 @@ static struct dev_data *dev_new (void)
|
||||
{
|
||||
struct dev_data *dev;
|
||||
|
||||
dev = kmalloc (sizeof *dev, GFP_KERNEL);
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
memset (dev, 0, sizeof *dev);
|
||||
dev->state = STATE_DEV_DISABLED;
|
||||
atomic_set (&dev->count, 1);
|
||||
spin_lock_init (&dev->lock);
|
||||
@ -1592,10 +1591,9 @@ static int activate_ep_files (struct dev_data *dev)
|
||||
gadget_for_each_ep (ep, dev->gadget) {
|
||||
struct ep_data *data;
|
||||
|
||||
data = kmalloc (sizeof *data, GFP_KERNEL);
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
goto enomem;
|
||||
memset (data, 0, sizeof data);
|
||||
data->state = STATE_EP_DISABLED;
|
||||
init_MUTEX (&data->lock);
|
||||
init_waitqueue_head (&data->wait);
|
||||
|
@ -1114,11 +1114,10 @@ static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
|
||||
|
||||
DEBUG("%s, %p\n", __FUNCTION__, ep);
|
||||
|
||||
req = kmalloc(sizeof *req, gfp_flags);
|
||||
req = kzalloc(sizeof(*req), gfp_flags);
|
||||
if (!req)
|
||||
return 0;
|
||||
|
||||
memset(req, 0, sizeof *req);
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
|
||||
return &req->req;
|
||||
|
@ -386,11 +386,10 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
|
||||
return NULL;
|
||||
ep = container_of (_ep, struct net2280_ep, ep);
|
||||
|
||||
req = kmalloc (sizeof *req, gfp_flags);
|
||||
req = kzalloc(sizeof(*req), gfp_flags);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
memset (req, 0, sizeof *req);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
|
||||
|
@ -273,9 +273,8 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
|
||||
{
|
||||
struct omap_req *req;
|
||||
|
||||
req = kmalloc(sizeof *req, gfp_flags);
|
||||
req = kzalloc(sizeof(*req), gfp_flags);
|
||||
if (req) {
|
||||
memset (req, 0, sizeof *req);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
}
|
||||
@ -2586,11 +2585,10 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
|
||||
/* UDC_PULLUP_EN gates the chip clock */
|
||||
// OTG_SYSCON_1_REG |= DEV_IDLE_EN;
|
||||
|
||||
udc = kmalloc (sizeof *udc, SLAB_KERNEL);
|
||||
udc = kzalloc(sizeof(*udc), SLAB_KERNEL);
|
||||
if (!udc)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(udc, 0, sizeof *udc);
|
||||
spin_lock_init (&udc->lock);
|
||||
|
||||
udc->gadget.ops = &omap_gadget_ops;
|
||||
|
@ -335,11 +335,10 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
|
||||
{
|
||||
struct pxa2xx_request *req;
|
||||
|
||||
req = kmalloc (sizeof *req, gfp_flags);
|
||||
req = kzalloc(sizeof(*req), gfp_flags);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
memset (req, 0, sizeof *req);
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
return &req->req;
|
||||
}
|
||||
|
@ -369,7 +369,7 @@ static struct usb_gadget_driver gs_gadget_driver = {
|
||||
#endif /* CONFIG_USB_GADGET_DUALSPEED */
|
||||
.function = GS_LONG_NAME,
|
||||
.bind = gs_bind,
|
||||
.unbind = gs_unbind,
|
||||
.unbind = __exit_p(gs_unbind),
|
||||
.setup = gs_setup,
|
||||
.disconnect = gs_disconnect,
|
||||
.driver = {
|
||||
@ -1413,7 +1413,7 @@ requeue:
|
||||
* Called on module load. Allocates and initializes the device
|
||||
* structure and a control request.
|
||||
*/
|
||||
static int gs_bind(struct usb_gadget *gadget)
|
||||
static int __init gs_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret;
|
||||
struct usb_ep *ep;
|
||||
@ -1538,7 +1538,7 @@ autoconf_fail:
|
||||
* Called on module unload. Frees the control request and device
|
||||
* structure.
|
||||
*/
|
||||
static void gs_unbind(struct usb_gadget *gadget)
|
||||
static void __exit gs_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct gs_dev *dev = get_gadget_data(gadget);
|
||||
|
||||
@ -2178,10 +2178,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
|
||||
return -EIO;
|
||||
|
||||
for (i=0; i<GS_NUM_PORTS; i++) {
|
||||
if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
|
||||
if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(port, 0, sizeof(struct gs_port));
|
||||
port->port_dev = dev;
|
||||
port->port_num = i;
|
||||
port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
|
||||
|
@ -1119,7 +1119,7 @@ zero_autoresume (unsigned long _dev)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
static void __exit
|
||||
zero_unbind (struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
@ -1136,7 +1136,7 @@ zero_unbind (struct usb_gadget *gadget)
|
||||
set_gadget_data (gadget, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
static int __init
|
||||
zero_bind (struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev;
|
||||
@ -1188,10 +1188,9 @@ autoconf_fail:
|
||||
|
||||
|
||||
/* ok, we made sense of the hardware ... */
|
||||
dev = kmalloc (sizeof *dev, SLAB_KERNEL);
|
||||
dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
memset (dev, 0, sizeof *dev);
|
||||
spin_lock_init (&dev->lock);
|
||||
dev->gadget = gadget;
|
||||
set_gadget_data (gadget, dev);
|
||||
@ -1224,12 +1223,6 @@ autoconf_fail:
|
||||
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
if (gadget->is_otg) {
|
||||
otg_descriptor.bmAttributes |= USB_OTG_HNP,
|
||||
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
usb_gadget_set_selfpowered (gadget);
|
||||
|
||||
init_timer (&dev->resume);
|
||||
@ -1294,7 +1287,7 @@ static struct usb_gadget_driver zero_driver = {
|
||||
#endif
|
||||
.function = (char *) longname,
|
||||
.bind = zero_bind,
|
||||
.unbind = zero_unbind,
|
||||
.unbind = __exit_p(zero_unbind),
|
||||
|
||||
.setup = zero_setup,
|
||||
.disconnect = zero_disconnect,
|
||||
|
@ -6,7 +6,7 @@ comment "USB Host Controller Drivers"
|
||||
|
||||
config USB_EHCI_HCD
|
||||
tristate "EHCI HCD (USB 2.0) support"
|
||||
depends on USB && PCI
|
||||
depends on USB && USB_ARCH_HAS_EHCI
|
||||
---help---
|
||||
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
|
||||
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
|
||||
|
297
drivers/usb/host/ehci-au1xxx.c
Normal file
297
drivers/usb/host/ehci-au1xxx.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* EHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
* Bus Glue for AMD Alchemy Au1xxx
|
||||
*
|
||||
* Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Modified for AMD Alchemy Au1200 EHC
|
||||
* by K.Boge <karsten.boge@amd.com>
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
|
||||
#ifndef CONFIG_SOC_AU1200
|
||||
#error "this Alchemy chip doesn't have EHCI"
|
||||
#else /* Au1200 */
|
||||
|
||||
#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG)
|
||||
#define USB_MCFG_PFEN (1<<31)
|
||||
#define USB_MCFG_RDCOMB (1<<30)
|
||||
#define USB_MCFG_SSDEN (1<<23)
|
||||
#define USB_MCFG_PHYPLLEN (1<<19)
|
||||
#define USB_MCFG_EHCCLKEN (1<<17)
|
||||
#define USB_MCFG_UCAM (1<<7)
|
||||
#define USB_MCFG_EBMEN (1<<3)
|
||||
#define USB_MCFG_EMEMEN (1<<2)
|
||||
|
||||
#define USBH_ENABLE_CE (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
|
||||
|
||||
#ifdef CONFIG_DMA_COHERENT
|
||||
#define USBH_ENABLE_INIT (USBH_ENABLE_CE \
|
||||
| USB_MCFG_PFEN | USB_MCFG_RDCOMB \
|
||||
| USB_MCFG_SSDEN | USB_MCFG_UCAM \
|
||||
| USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
|
||||
#else
|
||||
#define USBH_ENABLE_INIT (USBH_ENABLE_CE \
|
||||
| USB_MCFG_PFEN | USB_MCFG_RDCOMB \
|
||||
| USB_MCFG_SSDEN \
|
||||
| USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
|
||||
#endif
|
||||
#define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
|
||||
|
||||
#endif /* Au1200 */
|
||||
|
||||
extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void au1xxx_start_ehc(struct platform_device *dev)
|
||||
{
|
||||
pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
|
||||
|
||||
/* write HW defaults again in case Yamon cleared them */
|
||||
if (au_readl(USB_HOST_CONFIG) == 0) {
|
||||
au_writel(0x00d02000, USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
}
|
||||
/* enable host controller */
|
||||
au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
|
||||
USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
|
||||
pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
|
||||
}
|
||||
|
||||
static void au1xxx_stop_ehc(struct platform_device *dev)
|
||||
{
|
||||
pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
|
||||
|
||||
/* Disable mem */
|
||||
au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
/* Disable clock */
|
||||
au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
|
||||
USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* configure so an HC device and id are always provided */
|
||||
/* always called with process context; sleeping is OK */
|
||||
|
||||
/**
|
||||
* usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocates basic resources for this USB host controller, and
|
||||
* then invokes the start() method for the HCD associated with it
|
||||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
*/
|
||||
int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
|
||||
struct usb_hcd **hcd_out, struct platform_device *dev)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
|
||||
#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
|
||||
|
||||
/* Au1200 AB USB does not support coherent memory */
|
||||
if (!(read_c0_prid() & 0xff)) {
|
||||
pr_info("%s: this is chip revision AB!\n", dev->dev.name);
|
||||
pr_info("%s: update your board or re-configure the kernel\n",
|
||||
dev->dev.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
au1xxx_start_ehc(dev);
|
||||
|
||||
if (dev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
pr_debug("resource[1] is not IORESOURCE_IRQ");
|
||||
retval = -ENOMEM;
|
||||
}
|
||||
hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
hcd->rsrc_start = dev->resource[0].start;
|
||||
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
pr_debug("request_mem_region failed");
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
pr_debug("ioremap failed");
|
||||
retval = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
/* ehci_hcd_init(hcd_to_ehci(hcd)); */
|
||||
|
||||
retval =
|
||||
usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
au1xxx_stop_ehc(dev);
|
||||
iounmap(hcd->regs);
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err1:
|
||||
usb_put_hcd(hcd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* may be called without controller electrically present */
|
||||
/* may be called with controller, bus, and devices active */
|
||||
|
||||
/**
|
||||
* usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
|
||||
* @dev: USB Host Controller being removed
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
|
||||
* the HCD's stop() method. It is always called from a thread
|
||||
* context, normally "rmmod", "apmd", or something similar.
|
||||
*
|
||||
*/
|
||||
void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
au1xxx_stop_ehc(dev);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static const struct hc_driver ehci_au1xxx_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Au1xxx EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.hub_suspend = ehci_hub_suspend,
|
||||
.hub_resume = ehci_hub_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct usb_hcd *hcd = NULL;
|
||||
int ret;
|
||||
|
||||
pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
usb_ehci_au1xxx_remove(hcd, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*TBD*/
|
||||
/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
static struct device_driver ehci_hcd_au1xxx_driver = {
|
||||
.name = "au1xxx-ehci",
|
||||
.bus = &platform_bus_type,
|
||||
.probe = ehci_hcd_au1xxx_drv_probe,
|
||||
.remove = ehci_hcd_au1xxx_drv_remove,
|
||||
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
|
||||
/*.resume = ehci_hcd_au1xxx_drv_resume, */
|
||||
};
|
||||
|
||||
static int __init ehci_hcd_au1xxx_init(void)
|
||||
{
|
||||
pr_debug(DRIVER_INFO " (Au1xxx)\n");
|
||||
|
||||
return driver_register(&ehci_hcd_au1xxx_driver);
|
||||
}
|
||||
|
||||
static void __exit ehci_hcd_au1xxx_cleanup(void)
|
||||
{
|
||||
driver_unregister(&ehci_hcd_au1xxx_driver);
|
||||
}
|
||||
|
||||
module_init(ehci_hcd_au1xxx_init);
|
||||
module_exit(ehci_hcd_au1xxx_cleanup);
|
366
drivers/usb/host/ehci-fsl.c
Normal file
366
drivers/usb/host/ehci-fsl.c
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* (C) Copyright David Brownell 2000-2002
|
||||
* Copyright (c) 2005 MontaVista Software
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
|
||||
* by Hunter Wu.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
|
||||
#include "ehci-fsl.h"
|
||||
|
||||
/* FIXME: Power Managment is un-ported so temporarily disable it */
|
||||
#undef CONFIG_PM
|
||||
|
||||
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
|
||||
|
||||
/* configure so an HC device and id are always provided */
|
||||
/* always called with process context; sleeping is OK */
|
||||
|
||||
/**
|
||||
* usb_hcd_fsl_probe - initialize FSL-based HCDs
|
||||
* @drvier: Driver to be used for this HCD
|
||||
* @pdev: USB Host Controller being probed
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocates basic resources for this USB host controller.
|
||||
*
|
||||
*/
|
||||
int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int retval;
|
||||
unsigned int temp;
|
||||
|
||||
pr_debug("initializing FSL-SOC USB Controller\n");
|
||||
|
||||
/* Need platform data for setup */
|
||||
pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev,
|
||||
"No platform data for %s.\n", pdev->dev.bus_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a host mode driver, verify that we're supposed to be
|
||||
* in host mode.
|
||||
*/
|
||||
if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
|
||||
(pdata->operating_mode == FSL_USB2_MPH_HOST))) {
|
||||
dev_err(&pdev->dev,
|
||||
"Non Host Mode configured for %s. Wrong driver linked.\n",
|
||||
pdev->dev.bus_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no IRQ. Check %s setup!\n",
|
||||
pdev->dev.bus_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no register addr. Check %s setup!\n",
|
||||
pdev->dev.bus_id);
|
||||
retval = -ENODEV;
|
||||
goto err2;
|
||||
}
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/* Enable USB controller */
|
||||
temp = in_be32(hcd->regs + 0x500);
|
||||
out_be32(hcd->regs + 0x500, temp | 0x4);
|
||||
|
||||
/* Set to Host mode */
|
||||
temp = in_le32(hcd->regs + 0x1a8);
|
||||
out_le32(hcd->regs + 0x1a8, temp | 0x3);
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, SA_SHIRQ);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
err3:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err2:
|
||||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* may be called without controller electrically present */
|
||||
/* may be called with controller, bus, and devices active */
|
||||
|
||||
/**
|
||||
* usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
|
||||
* @dev: USB Host Controller being removed
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Reverses the effect of usb_hcd_fsl_probe().
|
||||
*
|
||||
*/
|
||||
void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
}
|
||||
|
||||
static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
|
||||
enum fsl_usb2_phy_modes phy_mode,
|
||||
unsigned int port_offset)
|
||||
{
|
||||
u32 portsc = 0;
|
||||
switch (phy_mode) {
|
||||
case FSL_USB2_PHY_ULPI:
|
||||
portsc |= PORT_PTS_ULPI;
|
||||
break;
|
||||
case FSL_USB2_PHY_SERIAL:
|
||||
portsc |= PORT_PTS_SERIAL;
|
||||
break;
|
||||
case FSL_USB2_PHY_UTMI_WIDE:
|
||||
portsc |= PORT_PTS_PTW;
|
||||
/* fall through */
|
||||
case FSL_USB2_PHY_UTMI:
|
||||
portsc |= PORT_PTS_UTMI;
|
||||
break;
|
||||
case FSL_USB2_PHY_NONE:
|
||||
break;
|
||||
}
|
||||
writel(portsc, &ehci->regs->port_status[port_offset]);
|
||||
}
|
||||
|
||||
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
pdata =
|
||||
(struct fsl_usb2_platform_data *)hcd->self.controller->
|
||||
platform_data;
|
||||
/* Enable PHY interface in the control reg. */
|
||||
out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
|
||||
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
|
||||
|
||||
if (pdata->operating_mode == FSL_USB2_DR_HOST)
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
|
||||
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
|
||||
unsigned int chip, rev, svr;
|
||||
|
||||
svr = mfspr(SPRN_SVR);
|
||||
chip = svr >> 16;
|
||||
rev = (svr >> 4) & 0xf;
|
||||
|
||||
/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
|
||||
if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
|
||||
ehci->has_fsl_port_bug = 1;
|
||||
|
||||
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
|
||||
}
|
||||
|
||||
/* put controller in host mode. */
|
||||
writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
|
||||
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
|
||||
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
|
||||
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
|
||||
}
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
|
||||
{
|
||||
mpc83xx_usb_setup(ehci_to_hcd(ehci));
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_fsl_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->is_tdi_rh_tt = 1;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
retval = ehci_fsl_reinit(ehci);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_fsl_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Freescale On-Chip EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_fsl_setup,
|
||||
.start = ehci_run,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ehci_bus_suspend,
|
||||
.resume = ehci_bus_resume,
|
||||
#endif
|
||||
.stop = ehci_stop,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
};
|
||||
|
||||
static int ehci_fsl_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
|
||||
}
|
||||
|
||||
static int ehci_fsl_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_hcd_fsl_remove(hcd, pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ehci_fsl_dr_driver = {
|
||||
.probe = ehci_fsl_drv_probe,
|
||||
.remove = ehci_fsl_drv_remove,
|
||||
.driver = {
|
||||
.name = "fsl-usb2-dr",
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_driver ehci_fsl_mph_driver = {
|
||||
.probe = ehci_fsl_drv_probe,
|
||||
.remove = ehci_fsl_drv_remove,
|
||||
.driver = {
|
||||
.name = "fsl-usb2-mph",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ehci_fsl_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
|
||||
hcd_name,
|
||||
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
|
||||
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
|
||||
|
||||
retval = platform_driver_register(&ehci_fsl_dr_driver);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return platform_driver_register(&ehci_fsl_mph_driver);
|
||||
}
|
||||
|
||||
static void __exit ehci_fsl_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&ehci_fsl_mph_driver);
|
||||
platform_driver_unregister(&ehci_fsl_dr_driver);
|
||||
}
|
||||
|
||||
module_init(ehci_fsl_init);
|
||||
module_exit(ehci_fsl_cleanup);
|
37
drivers/usb/host/ehci-fsl.h
Normal file
37
drivers/usb/host/ehci-fsl.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2005 freescale semiconductor
|
||||
* Copyright (c) 2005 MontaVista Software
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef _EHCI_FSL_H
|
||||
#define _EHCI_FSL_H
|
||||
|
||||
/* offsets for the non-ehci registers in the FSL SOC USB controller */
|
||||
#define FSL_SOC_USB_ULPIVP 0x170
|
||||
#define FSL_SOC_USB_PORTSC1 0x184
|
||||
#define PORT_PTS_MSK (3<<30)
|
||||
#define PORT_PTS_UTMI (0<<30)
|
||||
#define PORT_PTS_ULPI (2<<30)
|
||||
#define PORT_PTS_SERIAL (3<<30)
|
||||
#define PORT_PTS_PTW (1<<28)
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_SICTRL 0x40c /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_PRICTRL 0x410 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
|
||||
#endif /* _EHCI_FSL_H */
|
@ -889,8 +889,19 @@ MODULE_LICENSE ("GPL");
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include "ehci-pci.c"
|
||||
#define EHCI_BUS_GLUED
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_PCI)
|
||||
#ifdef CONFIG_PPC_83xx
|
||||
#include "ehci-fsl.c"
|
||||
#define EHCI_BUS_GLUED
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_AU1X00
|
||||
#include "ehci-au1xxx.c"
|
||||
#define EHCI_BUS_GLUED
|
||||
#endif
|
||||
|
||||
#ifndef EHCI_BUS_GLUED
|
||||
#error "missing bus glue for ehci-hcd"
|
||||
#endif
|
||||
|
@ -359,6 +359,8 @@ static int ehci_hub_control (
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
if (temp & PORT_RESET)
|
||||
goto error;
|
||||
if (ehci->no_selective_suspend)
|
||||
break;
|
||||
if (temp & PORT_SUSPEND) {
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
@ -514,6 +516,8 @@ static int ehci_hub_control (
|
||||
temp &= ~PORT_RWC_BITS;
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
if (ehci->no_selective_suspend)
|
||||
break;
|
||||
if ((temp & PORT_PE) == 0
|
||||
|| (temp & PORT_RESET) != 0)
|
||||
goto error;
|
||||
|
@ -75,7 +75,6 @@ static void qh_destroy (struct kref *kref)
|
||||
}
|
||||
if (qh->dummy)
|
||||
ehci_qtd_free (ehci, qh->dummy);
|
||||
usb_put_dev (qh->dev);
|
||||
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
|
||||
}
|
||||
|
||||
@ -221,13 +220,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
||||
ehci->periodic [i] = EHCI_LIST_END;
|
||||
|
||||
/* software shadow of hardware table */
|
||||
ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
|
||||
if (ehci->pshadow == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
|
||||
|
||||
return 0;
|
||||
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
|
||||
if (ehci->pshadow != NULL)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ehci_dbg (ehci, "couldn't init memory\n");
|
||||
|
@ -106,11 +106,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
switch (pdev->device) {
|
||||
/* NVidia reports that certain chips don't handle
|
||||
* QH, ITD, or SITD addresses above 2GB. (But TD,
|
||||
* data buffer, and periodic schedule are normal.)
|
||||
*/
|
||||
switch (pdev->device) {
|
||||
case 0x003c: /* MCP04 */
|
||||
case 0x005b: /* CK804 */
|
||||
case 0x00d8: /* CK8 */
|
||||
@ -120,6 +120,14 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
ehci_warn(ehci, "can't enable NVidia "
|
||||
"workaround for >2GB RAM\n");
|
||||
break;
|
||||
/* Some NForce2 chips have problems with selective suspend;
|
||||
* fixed in newer silicon.
|
||||
*/
|
||||
case 0x0068:
|
||||
pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
|
||||
if ((temp & 0xff) < 0xa4)
|
||||
ehci->no_selective_suspend = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -163,6 +171,21 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
/* REVISIT: the controller works fine for wakeup iff the root hub
|
||||
* itself is "globally" suspended, but usbcore currently doesn't
|
||||
* understand such things.
|
||||
*
|
||||
* System suspend currently expects to be able to suspend the entire
|
||||
* device tree, device-at-a-time. If we failed selective suspend
|
||||
* reports, system suspend would fail; so the root hub code must claim
|
||||
* success. That's lying to usbcore, and it matters for for runtime
|
||||
* PM scenarios with selective suspend and remote wakeup...
|
||||
*/
|
||||
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
|
||||
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
|
||||
#endif
|
||||
|
||||
retval = ehci_pci_reinit(ehci, pdev);
|
||||
done:
|
||||
return retval;
|
||||
|
@ -702,7 +702,7 @@ qh_make (
|
||||
}
|
||||
|
||||
/* support for tt scheduling, and access to toggles */
|
||||
qh->dev = usb_get_dev (urb->dev);
|
||||
qh->dev = urb->dev;
|
||||
|
||||
/* using TT? */
|
||||
switch (urb->dev->speed) {
|
||||
@ -721,7 +721,14 @@ qh_make (
|
||||
info1 |= maxp << 16;
|
||||
|
||||
info2 |= (EHCI_TUNE_MULT_TT << 30);
|
||||
info2 |= urb->dev->ttport << 23;
|
||||
|
||||
/* Some Freescale processors have an erratum in which the
|
||||
* port number in the queue head was 0..N-1 instead of 1..N.
|
||||
*/
|
||||
if (ehci_has_fsl_portno_bug(ehci))
|
||||
info2 |= (urb->dev->ttport-1) << 23;
|
||||
else
|
||||
info2 |= urb->dev->ttport << 23;
|
||||
|
||||
/* set the address of the TT; for TDI's integrated
|
||||
* root hub tt, leave it zeroed.
|
||||
@ -1015,12 +1022,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
/* stop async schedule right now? */
|
||||
if (unlikely (qh == ehci->async)) {
|
||||
/* can't get here without STS_ASS set */
|
||||
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
|
||||
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
|
||||
&& !ehci->reclaim) {
|
||||
/* ... and CMD_IAAD clear */
|
||||
writel (cmd & ~CMD_ASE, &ehci->regs->command);
|
||||
wmb ();
|
||||
// handshake later, if we need to
|
||||
timer_action_done (ehci, TIMER_ASYNC_OFF);
|
||||
}
|
||||
timer_action_done (ehci, TIMER_ASYNC_OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -707,6 +707,7 @@ iso_stream_init (
|
||||
} else {
|
||||
u32 addr;
|
||||
int think_time;
|
||||
int hs_transfers;
|
||||
|
||||
addr = dev->ttport << 24;
|
||||
if (!ehci_is_TDI(ehci)
|
||||
@ -719,6 +720,7 @@ iso_stream_init (
|
||||
think_time = dev->tt ? dev->tt->think_time : 0;
|
||||
stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
|
||||
dev->speed, is_input, 1, maxp));
|
||||
hs_transfers = max (1u, (maxp + 187) / 188);
|
||||
if (is_input) {
|
||||
u32 tmp;
|
||||
|
||||
@ -727,12 +729,11 @@ iso_stream_init (
|
||||
stream->usecs = HS_USECS_ISO (1);
|
||||
stream->raw_mask = 1;
|
||||
|
||||
/* pessimistic c-mask */
|
||||
tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
|
||||
/ (125 * 1000);
|
||||
stream->raw_mask |= 3 << (tmp + 9);
|
||||
/* c-mask as specified in USB 2.0 11.18.4 3.c */
|
||||
tmp = (1 << (hs_transfers + 2)) - 1;
|
||||
stream->raw_mask |= tmp << (8 + 2);
|
||||
} else
|
||||
stream->raw_mask = smask_out [maxp / 188];
|
||||
stream->raw_mask = smask_out [hs_transfers - 1];
|
||||
bandwidth = stream->usecs + stream->c_usecs;
|
||||
bandwidth /= 1 << (interval + 2);
|
||||
|
||||
@ -863,9 +864,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
|
||||
int size = sizeof *iso_sched;
|
||||
|
||||
size += packets * sizeof (struct ehci_iso_packet);
|
||||
iso_sched = kmalloc (size, mem_flags);
|
||||
iso_sched = kzalloc(size, mem_flags);
|
||||
if (likely (iso_sched != NULL)) {
|
||||
memset(iso_sched, 0, size);
|
||||
INIT_LIST_HEAD (&iso_sched->td_list);
|
||||
}
|
||||
return iso_sched;
|
||||
@ -1398,7 +1398,7 @@ itd_complete (
|
||||
*/
|
||||
|
||||
/* give urb back to the driver ... can be out-of-order */
|
||||
dev = usb_get_dev (urb->dev);
|
||||
dev = urb->dev;
|
||||
ehci_urb_done (ehci, urb, regs);
|
||||
urb = NULL;
|
||||
|
||||
@ -1417,7 +1417,6 @@ itd_complete (
|
||||
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
|
||||
}
|
||||
iso_stream_put (ehci, stream);
|
||||
usb_put_dev (dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1764,7 +1763,7 @@ sitd_complete (
|
||||
*/
|
||||
|
||||
/* give urb back to the driver */
|
||||
dev = usb_get_dev (urb->dev);
|
||||
dev = urb->dev;
|
||||
ehci_urb_done (ehci, urb, regs);
|
||||
urb = NULL;
|
||||
|
||||
@ -1783,7 +1782,6 @@ sitd_complete (
|
||||
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
|
||||
}
|
||||
iso_stream_put (ehci, stream);
|
||||
usb_put_dev (dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -88,7 +88,12 @@ struct ehci_hcd { /* one per controller */
|
||||
unsigned long next_statechange;
|
||||
u32 command;
|
||||
|
||||
/* SILICON QUIRKS */
|
||||
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
|
||||
unsigned no_selective_suspend:1;
|
||||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||
|
||||
u8 sbrn; /* packed release number */
|
||||
|
||||
/* irq statistics */
|
||||
#ifdef EHCI_STATS
|
||||
@ -97,7 +102,6 @@ struct ehci_hcd { /* one per controller */
|
||||
#else
|
||||
# define COUNT(x) do {} while (0)
|
||||
#endif
|
||||
u8 sbrn; /* packed release number */
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
@ -636,6 +640,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
||||
#define ehci_port_speed(ehci, portsc) (1<<USB_PORT_FEAT_HIGHSPEED)
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PPC_83xx
|
||||
/* Some Freescale processors have an erratum in which the TT
|
||||
* port number in the queue head was 0..N-1 instead of 1..N.
|
||||
*/
|
||||
#define ehci_has_fsl_portno_bug(e) ((e)->has_fsl_port_bug)
|
||||
#else
|
||||
#define ehci_has_fsl_portno_bug(e) (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef DEBUG
|
||||
|
@ -2137,10 +2137,9 @@ static int etrax_usb_submit_bulk_urb(struct urb *urb)
|
||||
urb->status = -EINPROGRESS;
|
||||
|
||||
/* Setup the hcpriv data. */
|
||||
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
assert(urb_priv != NULL);
|
||||
/* This sets rx_offset to 0. */
|
||||
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
|
||||
urb_priv->urb_state = NOT_STARTED;
|
||||
urb->hcpriv = urb_priv;
|
||||
|
||||
@ -2475,10 +2474,9 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb)
|
||||
urb->status = -EINPROGRESS;
|
||||
|
||||
/* Setup the hcpriv data. */
|
||||
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
assert(urb_priv != NULL);
|
||||
/* This sets rx_offset to 0. */
|
||||
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
|
||||
urb_priv->urb_state = NOT_STARTED;
|
||||
urb->hcpriv = urb_priv;
|
||||
|
||||
@ -2767,9 +2765,8 @@ static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
|
||||
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
|
||||
interval = urb->interval;
|
||||
|
||||
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
|
||||
assert(urb_priv != NULL);
|
||||
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
|
||||
urb->hcpriv = urb_priv;
|
||||
|
||||
first_ep = &TxIntrEPList[0];
|
||||
@ -2997,9 +2994,8 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
|
||||
|
||||
prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
|
||||
|
||||
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
|
||||
urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
|
||||
assert(urb_priv != NULL);
|
||||
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
|
||||
|
||||
urb->hcpriv = urb_priv;
|
||||
urb_priv->epid = epid;
|
||||
|
@ -724,7 +724,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
|
||||
ep = hep->hcpriv;
|
||||
else {
|
||||
INIT_LIST_HEAD(&ep->schedule);
|
||||
ep->udev = usb_get_dev(udev);
|
||||
ep->udev = udev;
|
||||
ep->epnum = epnum;
|
||||
ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
|
||||
usb_settoggle(udev, epnum, is_out, 0);
|
||||
@ -891,7 +891,6 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd,
|
||||
if (!list_empty(&hep->urb_list))
|
||||
WARN("ep %p not empty?\n", ep);
|
||||
|
||||
usb_put_dev(ep->udev);
|
||||
kfree(ep);
|
||||
hep->hcpriv = NULL;
|
||||
}
|
||||
@ -1553,7 +1552,7 @@ static struct hc_driver isp116x_hc_driver = {
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
static int __init_or_module isp116x_remove(struct platform_device *pdev)
|
||||
static int isp116x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct isp116x *isp116x;
|
||||
|
306
drivers/usb/host/ohci-at91.c
Normal file
306
drivers/usb/host/ohci-at91.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* Copyright (C) 2004 SAN People (Pty) Ltd.
|
||||
* Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
|
||||
*
|
||||
* AT91RM9200 Bus Glue
|
||||
*
|
||||
* Based on fragments of 2.4 driver by Rick Bronson.
|
||||
* Based on ohci-omap.c
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/arch/board.h>
|
||||
|
||||
#ifndef CONFIG_ARCH_AT91RM9200
|
||||
#error "This file is AT91RM9200 bus glue. CONFIG_ARCH_AT91RM9200 must be defined."
|
||||
#endif
|
||||
|
||||
/* interface and function clocks */
|
||||
static struct clk *iclk, *fclk;
|
||||
|
||||
extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void at91_start_hc(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_regs __iomem *regs = hcd->regs;
|
||||
|
||||
dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
|
||||
|
||||
/*
|
||||
* Start the USB clocks.
|
||||
*/
|
||||
clk_enable(iclk);
|
||||
clk_enable(fclk);
|
||||
|
||||
/*
|
||||
* The USB host controller must remain in reset.
|
||||
*/
|
||||
writel(0, ®s->control);
|
||||
}
|
||||
|
||||
static void at91_stop_hc(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_regs __iomem *regs = hcd->regs;
|
||||
|
||||
dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
|
||||
|
||||
/*
|
||||
* Put the USB host controller into reset.
|
||||
*/
|
||||
writel(0, ®s->control);
|
||||
|
||||
/*
|
||||
* Stop the USB clocks.
|
||||
*/
|
||||
clk_disable(fclk);
|
||||
clk_disable(iclk);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
|
||||
|
||||
/* configure so an HC device and id are always provided */
|
||||
/* always called with process context; sleeping is OK */
|
||||
|
||||
|
||||
/**
|
||||
* usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocates basic resources for this USB host controller, and
|
||||
* then invokes the start() method for the HCD associated with it
|
||||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
* Store this function in the HCD's struct pci_driver as probe().
|
||||
*/
|
||||
int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd = NULL;
|
||||
|
||||
if (pdev->num_resources != 2) {
|
||||
pr_debug("hcd probe: invalid num_resources");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
|
||||
pr_debug("hcd probe: invalid resource type\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
hcd->rsrc_start = pdev->resource[0].start;
|
||||
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
pr_debug("request_mem_region failed\n");
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
pr_debug("ioremap failed\n");
|
||||
retval = -EIO;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
iclk = clk_get(&pdev->dev, "ohci_clk");
|
||||
fclk = clk_get(&pdev->dev, "uhpck");
|
||||
|
||||
at91_start_hc(pdev);
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
/* Error handling */
|
||||
at91_stop_hc(pdev);
|
||||
|
||||
clk_put(fclk);
|
||||
clk_put(iclk);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
err1:
|
||||
usb_put_hcd(hcd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* may be called without controller electrically present */
|
||||
/* may be called with controller, bus, and devices active */
|
||||
|
||||
/**
|
||||
* usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
|
||||
* @dev: USB Host Controller being removed
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Reverses the effect of usb_hcd_at91_probe(), first invoking
|
||||
* the HCD's stop() method. It is always called from a thread
|
||||
* context, normally "rmmod", "apmd", or something similar.
|
||||
*
|
||||
*/
|
||||
static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
at91_stop_hc(pdev);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
clk_put(fclk);
|
||||
clk_put(iclk);
|
||||
fclk = iclk = NULL;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit
|
||||
ohci_at91_start (struct usb_hcd *hcd)
|
||||
{
|
||||
// struct at91_ohci_data *board = hcd->self.controller->platform_data;
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
int ret;
|
||||
|
||||
if ((ret = ohci_init(ohci)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = ohci_run(ohci)) < 0) {
|
||||
err("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
// hcd->self.root_hub->maxchild = board->ports;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static const struct hc_driver ohci_at91_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "AT91RM9200 OHCI",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_USB11 | HCD_MEMORY,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.start = ohci_at91_start,
|
||||
.stop = ohci_stop,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ohci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.hub_suspend = ohci_hub_suspend,
|
||||
.hub_resume = ohci_hub_resume,
|
||||
#endif
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
|
||||
{
|
||||
return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
|
||||
}
|
||||
|
||||
static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
|
||||
{
|
||||
return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level)
|
||||
{
|
||||
printk("%s(%s:%d): not implemented yet\n",
|
||||
__func__, __FILE__, __LINE__);
|
||||
|
||||
clk_disable(fclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state)
|
||||
{
|
||||
printk("%s(%s:%d): not implemented yet\n",
|
||||
__func__, __FILE__, __LINE__);
|
||||
|
||||
clk_enable(fclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ohci_hcd_at91_drv_suspend NULL
|
||||
#define ohci_hcd_at91_drv_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver ohci_hcd_at91_driver = {
|
||||
.probe = ohci_hcd_at91_drv_probe,
|
||||
.remove = ohci_hcd_at91_drv_remove,
|
||||
.suspend = ohci_hcd_at91_drv_suspend,
|
||||
.resume = ohci_hcd_at91_drv_resume,
|
||||
.driver = {
|
||||
.name = "at91rm9200-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ohci_hcd_at91_init (void)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
return platform_driver_register(&ohci_hcd_at91_driver);
|
||||
}
|
||||
|
||||
static void __exit ohci_hcd_at91_cleanup (void)
|
||||
{
|
||||
platform_driver_unregister(&ohci_hcd_at91_driver);
|
||||
}
|
||||
|
||||
module_init (ohci_hcd_at91_init);
|
||||
module_exit (ohci_hcd_at91_cleanup);
|
@ -23,6 +23,8 @@
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
|
||||
#ifndef CONFIG_SOC_AU1200
|
||||
|
||||
#define USBH_ENABLE_BE (1<<0)
|
||||
#define USBH_ENABLE_C (1<<1)
|
||||
#define USBH_ENABLE_E (1<<2)
|
||||
@ -37,21 +39,68 @@
|
||||
#error not byte order defined
|
||||
#endif
|
||||
|
||||
#else /* Au1200 */
|
||||
|
||||
#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG)
|
||||
#define USB_MCFG_PFEN (1<<31)
|
||||
#define USB_MCFG_RDCOMB (1<<30)
|
||||
#define USB_MCFG_SSDEN (1<<23)
|
||||
#define USB_MCFG_OHCCLKEN (1<<16)
|
||||
#define USB_MCFG_UCAM (1<<7)
|
||||
#define USB_MCFG_OBMEN (1<<1)
|
||||
#define USB_MCFG_OMEMEN (1<<0)
|
||||
|
||||
#define USBH_ENABLE_CE USB_MCFG_OHCCLKEN
|
||||
#ifdef CONFIG_DMA_COHERENT
|
||||
#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \
|
||||
| USB_MCFG_PFEN | USB_MCFG_RDCOMB \
|
||||
| USB_MCFG_SSDEN | USB_MCFG_UCAM \
|
||||
| USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
|
||||
#else
|
||||
#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \
|
||||
| USB_MCFG_PFEN | USB_MCFG_RDCOMB \
|
||||
| USB_MCFG_SSDEN \
|
||||
| USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
|
||||
#endif
|
||||
#define USBH_DISABLE (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
|
||||
|
||||
#endif /* Au1200 */
|
||||
|
||||
extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void au1xxx_start_hc(struct platform_device *dev)
|
||||
static void au1xxx_start_ohc(struct platform_device *dev)
|
||||
{
|
||||
printk(KERN_DEBUG __FILE__
|
||||
": starting Au1xxx OHCI USB Controller\n");
|
||||
|
||||
/* enable host controller */
|
||||
|
||||
#ifndef CONFIG_SOC_AU1200
|
||||
|
||||
au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
|
||||
#else /* Au1200 */
|
||||
|
||||
/* write HW defaults again in case Yamon cleared them */
|
||||
if (au_readl(USB_HOST_CONFIG) == 0) {
|
||||
au_writel(0x00d02000, USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
}
|
||||
au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
|
||||
#endif /* Au1200 */
|
||||
|
||||
/* wait for reset complete (read register twice; see au1500 errata) */
|
||||
while (au_readl(USB_HOST_CONFIG),
|
||||
!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
|
||||
@ -61,13 +110,25 @@ static void au1xxx_start_hc(struct platform_device *dev)
|
||||
": Clock to USB host has been enabled \n");
|
||||
}
|
||||
|
||||
static void au1xxx_stop_hc(struct platform_device *dev)
|
||||
static void au1xxx_stop_ohc(struct platform_device *dev)
|
||||
{
|
||||
printk(KERN_DEBUG __FILE__
|
||||
": stopping Au1xxx OHCI USB Controller\n");
|
||||
|
||||
#ifndef CONFIG_SOC_AU1200
|
||||
|
||||
/* Disable clock */
|
||||
au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
|
||||
|
||||
#else /* Au1200 */
|
||||
|
||||
/* Disable mem */
|
||||
au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
udelay(1000);
|
||||
/* Disable clock */
|
||||
au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
|
||||
au_readl(USB_HOST_CONFIG);
|
||||
#endif /* Au1200 */
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +139,7 @@ static void au1xxx_stop_hc(struct platform_device *dev)
|
||||
|
||||
|
||||
/**
|
||||
* usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
|
||||
* usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocates basic resources for this USB host controller, and
|
||||
@ -86,14 +147,25 @@ static void au1xxx_stop_hc(struct platform_device *dev)
|
||||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
*/
|
||||
int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
|
||||
static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
if(dev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
pr_debug ("resource[1] is not IORESOURCE_IRQ");
|
||||
#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
|
||||
/* Au1200 AB USB does not support coherent memory */
|
||||
if (!(read_c0_prid() & 0xff)) {
|
||||
pr_info("%s: this is chip revision AB !!\n",
|
||||
dev->dev.name);
|
||||
pr_info("%s: update your board or re-configure the kernel\n",
|
||||
dev->dev.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
pr_debug("resource[1] is not IORESOURCE_IRQ\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -104,26 +176,26 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
|
||||
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
pr_debug("request_mem_region failed");
|
||||
pr_debug("request_mem_region failed\n");
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
pr_debug("ioremap failed");
|
||||
pr_debug("ioremap failed\n");
|
||||
retval = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
au1xxx_start_hc(dev);
|
||||
au1xxx_start_ohc(dev);
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
au1xxx_stop_hc(dev);
|
||||
au1xxx_stop_ohc(dev);
|
||||
iounmap(hcd->regs);
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
@ -146,10 +218,10 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
|
||||
* context, normally "rmmod", "apmd", or something similar.
|
||||
*
|
||||
*/
|
||||
void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
|
||||
static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
au1xxx_stop_hc(dev);
|
||||
au1xxx_stop_ohc(dev);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
@ -235,7 +307,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
|
||||
ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -243,7 +315,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_hcd_au1xxx_remove(hcd, pdev);
|
||||
usb_ohci_au1xxx_remove(hcd, pdev);
|
||||
return 0;
|
||||
}
|
||||
/*TBD*/
|
||||
|
@ -443,11 +443,16 @@ ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
|
||||
static int ohci_init (struct ohci_hcd *ohci)
|
||||
{
|
||||
int ret;
|
||||
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
||||
|
||||
disable (ohci);
|
||||
ohci->regs = ohci_to_hcd(ohci)->regs;
|
||||
ohci->regs = hcd->regs;
|
||||
ohci->next_statechange = jiffies;
|
||||
|
||||
/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
|
||||
* was never needed for most non-PCI systems ... remove the code?
|
||||
*/
|
||||
|
||||
#ifndef IR_DISABLE
|
||||
/* SMM owns the HC? not for long! */
|
||||
if (!no_handshake && ohci_readl (ohci,
|
||||
@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci)
|
||||
|
||||
/* Disable HC interrupts */
|
||||
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||
// flush the writes
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
|
||||
/* flush the writes, and save key bits like RWC */
|
||||
if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC)
|
||||
ohci->hc_control |= OHCI_CTRL_RWC;
|
||||
|
||||
/* Read the number of ports unless overridden */
|
||||
if (ohci->num_ports == 0)
|
||||
@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci)
|
||||
if (ohci->hcca)
|
||||
return 0;
|
||||
|
||||
ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
|
||||
ohci->hcca = dma_alloc_coherent (hcd->self.controller,
|
||||
sizeof *ohci->hcca, &ohci->hcca_dma, 0);
|
||||
if (!ohci->hcca)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((ret = ohci_mem_init (ohci)) < 0)
|
||||
ohci_stop (ohci_to_hcd(ohci));
|
||||
ohci_stop (hcd);
|
||||
else {
|
||||
register_reboot_notifier (&ohci->reboot_notifier);
|
||||
create_debug_files (ohci);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
{
|
||||
u32 mask, temp;
|
||||
int first = ohci->fminterval == 0;
|
||||
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
||||
|
||||
disable (ohci);
|
||||
|
||||
@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
/* also: power/overcurrent flags in roothub.a */
|
||||
}
|
||||
|
||||
/* Reset USB nearly "by the book". RemoteWakeupConnected
|
||||
* saved if boot firmware (BIOS/SMM/...) told us it's connected
|
||||
* (for OHCI integrated on mainboard, it normally is)
|
||||
/* Reset USB nearly "by the book". RemoteWakeupConnected was
|
||||
* saved if boot firmware (BIOS/SMM/...) told us it's connected,
|
||||
* or if bus glue did the same (e.g. for PCI add-in cards with
|
||||
* PCI PM support).
|
||||
*/
|
||||
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
|
||||
ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
|
||||
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
|
||||
ohci->hc_control);
|
||||
|
||||
if (ohci->hc_control & OHCI_CTRL_RWC
|
||||
&& !(ohci->flags & OHCI_QUIRK_AMD756))
|
||||
ohci_to_hcd(ohci)->can_wakeup = 1;
|
||||
ohci_readl (ohci, &ohci->regs->control));
|
||||
if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
|
||||
&& !device_may_wakeup(hcd->self.controller))
|
||||
device_init_wakeup(hcd->self.controller, 1);
|
||||
|
||||
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
||||
case OHCI_USB_OPER:
|
||||
@ -632,7 +642,7 @@ retry:
|
||||
ohci->hc_control &= OHCI_CTRL_RWC;
|
||||
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
|
||||
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
|
||||
ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
/* wake on ConnectStatusChange, matching external hubs */
|
||||
ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
|
||||
@ -667,15 +677,10 @@ retry:
|
||||
|
||||
// POTPGT delay is bits 24-31, in 2 ms units.
|
||||
mdelay ((temp >> 23) & 0x1fe);
|
||||
ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
ohci_dump (ohci, 1);
|
||||
|
||||
if (ohci_to_hcd(ohci)->self.root_hub == NULL) {
|
||||
register_reboot_notifier (&ohci->reboot_notifier);
|
||||
create_debug_files (ohci);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -905,6 +910,10 @@ MODULE_LICENSE ("GPL");
|
||||
#include "ohci-ppc-soc.c"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_AT91RM9200
|
||||
#include "ohci-at91.c"
|
||||
#endif
|
||||
|
||||
#if !(defined(CONFIG_PCI) \
|
||||
|| defined(CONFIG_SA1111) \
|
||||
|| defined(CONFIG_ARCH_S3C2410) \
|
||||
@ -913,6 +922,7 @@ MODULE_LICENSE ("GPL");
|
||||
|| defined (CONFIG_PXA27x) \
|
||||
|| defined (CONFIG_SOC_AU1X00) \
|
||||
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|
||||
|| defined (CONFIG_ARCH_AT91RM9200) \
|
||||
)
|
||||
#error "missing bus glue for ohci-hcd"
|
||||
#endif
|
||||
|
@ -107,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
|
||||
&ohci->regs->intrstatus);
|
||||
|
||||
/* maybe resume can wake root hub */
|
||||
if (hcd->remote_wakeup)
|
||||
if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
|
||||
ohci->hc_control |= OHCI_CTRL_RWE;
|
||||
else
|
||||
ohci->hc_control &= ~OHCI_CTRL_RWE;
|
||||
@ -246,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
msleep (3);
|
||||
|
||||
temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
|
||||
if (hcd->can_wakeup)
|
||||
temp |= OHCI_CTRL_RWC;
|
||||
temp = ohci->hc_control;
|
||||
temp &= OHCI_CTRL_RWC;
|
||||
temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
|
||||
ohci->hc_control = temp;
|
||||
ohci_writel (ohci, temp, &ohci->regs->control);
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
@ -302,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
int i, changed = 0, length = 1;
|
||||
int can_suspend = hcd->can_wakeup;
|
||||
int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
@ -354,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||
*/
|
||||
if (!(status & RH_PS_CCS))
|
||||
continue;
|
||||
if ((status & RH_PS_PSS) && hcd->remote_wakeup)
|
||||
if ((status & RH_PS_PSS) && can_suspend)
|
||||
continue;
|
||||
can_suspend = 0;
|
||||
}
|
||||
|
@ -35,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd)
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
int ret;
|
||||
|
||||
if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
|
||||
/* REVISIT this whole block should move to reset(), which handles
|
||||
* all the other one-time init.
|
||||
*/
|
||||
if (hcd->self.controller) {
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
|
||||
/* AMD 756, for most chips (early revs), corrupts register
|
||||
@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd)
|
||||
&& pdev->device == 0x740c) {
|
||||
ohci->flags = OHCI_QUIRK_AMD756;
|
||||
ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
|
||||
// also somewhat erratum 10 (suspend/resume issues)
|
||||
/* also erratum 10 (suspend/resume issues) */
|
||||
device_init_wakeup(&hcd->self.root_hub->dev, 0);
|
||||
}
|
||||
|
||||
/* FIXME for some of the early AMD 760 southbridges, OHCI
|
||||
@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd)
|
||||
ohci_dbg (ohci,
|
||||
"enabled Compaq ZFMicro chipset quirk\n");
|
||||
}
|
||||
|
||||
/* RWC may not be set for add-in PCI cards, since boot
|
||||
* firmware probably ignored them. This transfers PCI
|
||||
* PM wakeup capabilities (once the PCI layer is fixed).
|
||||
*/
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
ohci->hc_control |= OHCI_CTRL_RWC;
|
||||
}
|
||||
|
||||
/* NOTE: there may have already been a first reset, to
|
||||
|
@ -853,7 +853,7 @@ static int sl811h_urb_enqueue(
|
||||
|
||||
} else {
|
||||
INIT_LIST_HEAD(&ep->schedule);
|
||||
ep->udev = usb_get_dev(udev);
|
||||
ep->udev = udev;
|
||||
ep->epnum = epnum;
|
||||
ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
|
||||
ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
|
||||
@ -1052,7 +1052,6 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
|
||||
if (!list_empty(&hep->urb_list))
|
||||
WARN("ep %p not empty?\n", ep);
|
||||
|
||||
usb_put_dev(ep->udev);
|
||||
kfree(ep);
|
||||
hep->hcpriv = NULL;
|
||||
}
|
||||
|
@ -17,10 +17,13 @@
|
||||
|
||||
#include "uhci-hcd.h"
|
||||
|
||||
static struct dentry *uhci_debugfs_root = NULL;
|
||||
#define uhci_debug_operations (* (struct file_operations *) NULL)
|
||||
static struct dentry *uhci_debugfs_root;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* Handle REALLY large printks so we don't overflow buffers */
|
||||
static inline void lprintk(char *buf)
|
||||
static void lprintk(char *buf)
|
||||
{
|
||||
char *p;
|
||||
|
||||
@ -90,13 +93,59 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
struct uhci_td *td;
|
||||
int i, nactive, ninactive;
|
||||
|
||||
if (len < 200)
|
||||
return 0;
|
||||
|
||||
out += sprintf(out, "urb_priv [%p] ", urbp);
|
||||
out += sprintf(out, "urb [%p] ", urbp->urb);
|
||||
out += sprintf(out, "qh [%p] ", urbp->qh);
|
||||
out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
|
||||
out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
|
||||
(usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
|
||||
|
||||
switch (usb_pipetype(urbp->urb->pipe)) {
|
||||
case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
|
||||
case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
|
||||
case PIPE_BULK: out += sprintf(out, "BLK"); break;
|
||||
case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
|
||||
}
|
||||
|
||||
out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
|
||||
|
||||
if (urbp->urb->status != -EINPROGRESS)
|
||||
out += sprintf(out, " Status=%d", urbp->urb->status);
|
||||
out += sprintf(out, "\n");
|
||||
|
||||
i = nactive = ninactive = 0;
|
||||
list_for_each_entry(td, &urbp->td_list, list) {
|
||||
if (++i <= 10 || debug > 2) {
|
||||
out += sprintf(out, "%*s%d: ", space + 2, "", i);
|
||||
out += uhci_show_td(td, out, len - (out - buf), 0);
|
||||
} else {
|
||||
if (td_status(td) & TD_CTRL_ACTIVE)
|
||||
++nactive;
|
||||
else
|
||||
++ninactive;
|
||||
}
|
||||
}
|
||||
if (nactive + ninactive > 0)
|
||||
out += sprintf(out, "%*s[skipped %d inactive and %d active "
|
||||
"TDs]\n",
|
||||
space, "", ninactive, nactive);
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
struct urb_priv *urbp;
|
||||
struct list_head *head, *tmp;
|
||||
struct uhci_td *td;
|
||||
int i = 0, checked = 0, prevactive = 0;
|
||||
int i, nurbs;
|
||||
__le32 element = qh_element(qh);
|
||||
|
||||
/* Try to make sure there's enough memory */
|
||||
@ -118,86 +167,40 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
|
||||
if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
|
||||
out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
|
||||
|
||||
if (!qh->urbp) {
|
||||
out += sprintf(out, "%*s urbp == NULL\n", space, "");
|
||||
goto out;
|
||||
}
|
||||
if (list_empty(&qh->queue)) {
|
||||
out += sprintf(out, "%*s queue is empty\n", space, "");
|
||||
} else {
|
||||
struct urb_priv *urbp = list_entry(qh->queue.next,
|
||||
struct urb_priv, node);
|
||||
struct uhci_td *td = list_entry(urbp->td_list.next,
|
||||
struct uhci_td, list);
|
||||
|
||||
urbp = qh->urbp;
|
||||
|
||||
head = &urbp->td_list;
|
||||
tmp = head->next;
|
||||
|
||||
td = list_entry(tmp, struct uhci_td, list);
|
||||
|
||||
if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
|
||||
out += sprintf(out, "%*s Element != First TD\n", space, "");
|
||||
|
||||
while (tmp != head) {
|
||||
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
|
||||
|
||||
tmp = tmp->next;
|
||||
|
||||
out += sprintf(out, "%*s%d: ", space + 2, "", i++);
|
||||
out += uhci_show_td(td, out, len - (out - buf), 0);
|
||||
|
||||
if (i > 10 && !checked && prevactive && tmp != head &&
|
||||
debug <= 2) {
|
||||
struct list_head *ntmp = tmp;
|
||||
struct uhci_td *ntd = td;
|
||||
int active = 1, ni = i;
|
||||
|
||||
checked = 1;
|
||||
|
||||
while (ntmp != head && ntmp->next != head && active) {
|
||||
ntd = list_entry(ntmp, struct uhci_td, list);
|
||||
|
||||
ntmp = ntmp->next;
|
||||
|
||||
active = td_status(ntd) & TD_CTRL_ACTIVE;
|
||||
|
||||
ni++;
|
||||
}
|
||||
|
||||
if (active && ni > i) {
|
||||
out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
|
||||
tmp = ntmp;
|
||||
td = ntd;
|
||||
i = ni;
|
||||
}
|
||||
if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
|
||||
out += sprintf(out, "%*s Element != First TD\n",
|
||||
space, "");
|
||||
i = nurbs = 0;
|
||||
list_for_each_entry(urbp, &qh->queue, node) {
|
||||
if (++i <= 10)
|
||||
out += uhci_show_urbp(urbp, out,
|
||||
len - (out - buf), space + 2);
|
||||
else
|
||||
++nurbs;
|
||||
}
|
||||
|
||||
prevactive = td_status(td) & TD_CTRL_ACTIVE;
|
||||
if (nurbs > 0)
|
||||
out += sprintf(out, "%*s Skipped %d URBs\n",
|
||||
space, "", nurbs);
|
||||
}
|
||||
|
||||
if (list_empty(&urbp->queue_list) || urbp->queued)
|
||||
goto out;
|
||||
|
||||
out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
|
||||
|
||||
head = &urbp->queue_list;
|
||||
tmp = head->next;
|
||||
|
||||
while (tmp != head) {
|
||||
struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
|
||||
queue_list);
|
||||
tmp = tmp->next;
|
||||
|
||||
out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
|
||||
if (qh->udev) {
|
||||
out += sprintf(out, "%*s Dummy TD\n", space, "");
|
||||
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
|
||||
}
|
||||
|
||||
out:
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
#define show_frame_num() \
|
||||
if (!shown) { \
|
||||
shown = 1; \
|
||||
out += sprintf(out, "- Frame %d\n", i); \
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static const char * const qh_names[] = {
|
||||
"skel_unlink_qh", "skel_iso_qh",
|
||||
"skel_int128_qh", "skel_int64_qh",
|
||||
"skel_int32_qh", "skel_int16_qh",
|
||||
"skel_int8_qh", "skel_int4_qh",
|
||||
@ -206,12 +209,6 @@ static const char * const qh_names[] = {
|
||||
"skel_bulk_qh", "skel_term_qh"
|
||||
};
|
||||
|
||||
#define show_qh_name() \
|
||||
if (!shown) { \
|
||||
shown = 1; \
|
||||
out += sprintf(out, "- %s\n", qh_names[i]); \
|
||||
}
|
||||
|
||||
static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
|
||||
{
|
||||
char *out = buf;
|
||||
@ -321,139 +318,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
char *out = buf;
|
||||
int count = 0;
|
||||
|
||||
if (len < 200)
|
||||
return 0;
|
||||
|
||||
out += sprintf(out, "urb_priv [%p] ", urbp);
|
||||
out += sprintf(out, "urb [%p] ", urbp->urb);
|
||||
out += sprintf(out, "qh [%p] ", urbp->qh);
|
||||
out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
|
||||
out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
|
||||
|
||||
switch (usb_pipetype(urbp->urb->pipe)) {
|
||||
case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
|
||||
case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
|
||||
case PIPE_BULK: out += sprintf(out, "BLK "); break;
|
||||
case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
|
||||
}
|
||||
|
||||
out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
|
||||
out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
|
||||
|
||||
if (urbp->urb->status != -EINPROGRESS)
|
||||
out += sprintf(out, "Status=%d ", urbp->urb->status);
|
||||
//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
|
||||
|
||||
count = 0;
|
||||
list_for_each(tmp, &urbp->td_list)
|
||||
count++;
|
||||
out += sprintf(out, "TDs=%d ",count);
|
||||
|
||||
if (urbp->queued)
|
||||
out += sprintf(out, "queued\n");
|
||||
else {
|
||||
count = 0;
|
||||
list_for_each(tmp, &urbp->queue_list)
|
||||
count++;
|
||||
out += sprintf(out, "queued URBs=%d\n", count);
|
||||
}
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
|
||||
{
|
||||
char *out = buf;
|
||||
struct list_head *head, *tmp;
|
||||
int count;
|
||||
|
||||
out += sprintf(out, "Main list URBs:");
|
||||
if (list_empty(&uhci->urb_list))
|
||||
out += sprintf(out, " Empty\n");
|
||||
else {
|
||||
out += sprintf(out, "\n");
|
||||
count = 0;
|
||||
head = &uhci->urb_list;
|
||||
tmp = head->next;
|
||||
while (tmp != head) {
|
||||
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
|
||||
|
||||
out += sprintf(out, " %d: ", ++count);
|
||||
out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
out += sprintf(out, "Remove list URBs:");
|
||||
if (list_empty(&uhci->urb_remove_list))
|
||||
out += sprintf(out, " Empty\n");
|
||||
else {
|
||||
out += sprintf(out, "\n");
|
||||
count = 0;
|
||||
head = &uhci->urb_remove_list;
|
||||
tmp = head->next;
|
||||
while (tmp != head) {
|
||||
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
|
||||
|
||||
out += sprintf(out, " %d: ", ++count);
|
||||
out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
out += sprintf(out, "Complete list URBs:");
|
||||
if (list_empty(&uhci->complete_list))
|
||||
out += sprintf(out, " Empty\n");
|
||||
else {
|
||||
out += sprintf(out, "\n");
|
||||
count = 0;
|
||||
head = &uhci->complete_list;
|
||||
tmp = head->next;
|
||||
while (tmp != head) {
|
||||
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
|
||||
|
||||
out += sprintf(out, " %d: ", ++count);
|
||||
out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
{
|
||||
unsigned long flags;
|
||||
char *out = buf;
|
||||
int i, j;
|
||||
struct uhci_qh *qh;
|
||||
struct uhci_td *td;
|
||||
struct list_head *tmp, *head;
|
||||
|
||||
spin_lock_irqsave(&uhci->lock, flags);
|
||||
|
||||
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
|
||||
out += sprintf(out, "HC status\n");
|
||||
out += uhci_show_status(uhci, out, len - (out - buf));
|
||||
if (debug <= 1)
|
||||
return out - buf;
|
||||
|
||||
out += sprintf(out, "Frame List\n");
|
||||
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
|
||||
int shown = 0;
|
||||
td = uhci->frame_cpu[i];
|
||||
if (!td)
|
||||
continue;
|
||||
|
||||
if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
|
||||
show_frame_num();
|
||||
out += sprintf(out, "- Frame %d\n", i); \
|
||||
if (td->dma_handle != (dma_addr_t)uhci->frame[i])
|
||||
out += sprintf(out, " frame list does not match td->dma_handle!\n");
|
||||
}
|
||||
show_frame_num();
|
||||
|
||||
head = &td->fl_list;
|
||||
tmp = head;
|
||||
@ -467,14 +354,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
out += sprintf(out, "Skeleton QHs\n");
|
||||
|
||||
for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
|
||||
int shown = 0;
|
||||
int cnt = 0;
|
||||
|
||||
qh = uhci->skelqh[i];
|
||||
|
||||
if (debug > 1) {
|
||||
show_qh_name();
|
||||
out += uhci_show_qh(qh, out, len - (out - buf), 4);
|
||||
}
|
||||
out += sprintf(out, "- %s\n", qh_names[i]); \
|
||||
out += uhci_show_qh(qh, out, len - (out - buf), 4);
|
||||
|
||||
/* Last QH is the Terminating QH, it's different */
|
||||
if (i == UHCI_NUM_SKELQH - 1) {
|
||||
@ -487,53 +371,37 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
continue;
|
||||
}
|
||||
|
||||
j = (i < 7) ? 7 : i+1; /* Next skeleton */
|
||||
if (list_empty(&qh->list)) {
|
||||
if (i < UHCI_NUM_SKELQH - 1) {
|
||||
if (qh->link !=
|
||||
(cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
|
||||
show_qh_name();
|
||||
out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n");
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
show_qh_name();
|
||||
|
||||
head = &qh->list;
|
||||
j = (i < 9) ? 9 : i+1; /* Next skeleton */
|
||||
head = &qh->node;
|
||||
tmp = head->next;
|
||||
|
||||
while (tmp != head) {
|
||||
qh = list_entry(tmp, struct uhci_qh, list);
|
||||
|
||||
qh = list_entry(tmp, struct uhci_qh, node);
|
||||
tmp = tmp->next;
|
||||
|
||||
out += uhci_show_qh(qh, out, len - (out - buf), 4);
|
||||
if (++cnt <= 10)
|
||||
out += uhci_show_qh(qh, out,
|
||||
len - (out - buf), 4);
|
||||
}
|
||||
if ((cnt -= 10) > 0)
|
||||
out += sprintf(out, " Skipped %d QHs\n", cnt);
|
||||
|
||||
if (i < UHCI_NUM_SKELQH - 1) {
|
||||
if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
|
||||
if (qh->link !=
|
||||
(cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
|
||||
out += sprintf(out, " last QH not linked to next skeleton!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (debug > 2)
|
||||
out += uhci_show_lists(uhci, out, len - (out - buf));
|
||||
|
||||
spin_unlock_irqrestore(&uhci->lock, flags);
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#define MAX_OUTPUT (64 * 1024)
|
||||
|
||||
struct uhci_debug {
|
||||
int size;
|
||||
char *data;
|
||||
struct uhci_hcd *uhci;
|
||||
};
|
||||
|
||||
static int uhci_debug_open(struct inode *inode, struct file *file)
|
||||
@ -541,6 +409,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
|
||||
struct uhci_hcd *uhci = inode->u.generic_ip;
|
||||
struct uhci_debug *up;
|
||||
int ret = -ENOMEM;
|
||||
unsigned long flags;
|
||||
|
||||
lock_kernel();
|
||||
up = kmalloc(sizeof(*up), GFP_KERNEL);
|
||||
@ -553,7 +422,11 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
|
||||
goto out;
|
||||
}
|
||||
|
||||
up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
|
||||
up->size = 0;
|
||||
spin_lock_irqsave(&uhci->lock, flags);
|
||||
if (uhci->is_initialized)
|
||||
up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
|
||||
spin_unlock_irqrestore(&uhci->lock, flags);
|
||||
|
||||
file->private_data = up;
|
||||
|
||||
@ -604,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef uhci_debug_operations
|
||||
static struct file_operations uhci_debug_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = uhci_debug_open,
|
||||
.llseek = uhci_debug_lseek,
|
||||
.read = uhci_debug_read,
|
||||
.release = uhci_debug_release,
|
||||
};
|
||||
|
||||
#else /* CONFIG_DEBUG_FS */
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
#define uhci_debug_operations (* (struct file_operations *) NULL)
|
||||
#else /* DEBUG */
|
||||
|
||||
static inline void lprintk(char *buf)
|
||||
{}
|
||||
|
||||
static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
|
||||
int len, int space)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
|
||||
char *buf, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -54,7 +54,7 @@
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v2.3"
|
||||
#define DRIVER_VERSION "v3.0"
|
||||
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
|
||||
Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
|
||||
Alan Stern"
|
||||
@ -68,12 +68,16 @@ Alan Stern"
|
||||
* debug = 3, show all TDs in URBs when dumping
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_CONFIGURED 1
|
||||
static int debug = 1;
|
||||
#else
|
||||
static int debug = 0;
|
||||
#endif
|
||||
module_param(debug, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Debug level");
|
||||
|
||||
#else
|
||||
#define DEBUG_CONFIGURED 0
|
||||
#define debug 0
|
||||
#endif
|
||||
|
||||
static char *errbuf;
|
||||
#define ERRBUF_LEN (32 * 1024)
|
||||
|
||||
@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
|
||||
dev_err(uhci_dev(uhci),
|
||||
"host controller halted, "
|
||||
"very bad!\n");
|
||||
if (debug > 1 && errbuf) {
|
||||
/* Print the schedule for debugging */
|
||||
uhci_sprint_schedule(uhci,
|
||||
errbuf, ERRBUF_LEN);
|
||||
lprintk(errbuf);
|
||||
}
|
||||
hc_died(uhci);
|
||||
|
||||
/* Force a callback in case there are
|
||||
@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (DEBUG_CONFIGURED) {
|
||||
spin_lock_irq(&uhci->lock);
|
||||
uhci->is_initialized = 0;
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
|
||||
debugfs_remove(uhci->dentry);
|
||||
}
|
||||
|
||||
for (i = 0; i < UHCI_NUM_SKELQH; i++)
|
||||
uhci_free_qh(uhci, uhci->skelqh[i]);
|
||||
|
||||
@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd *uhci)
|
||||
dma_free_coherent(uhci_dev(uhci),
|
||||
UHCI_NUMFRAMES * sizeof(*uhci->frame),
|
||||
uhci->frame, uhci->frame_dma_handle);
|
||||
|
||||
debugfs_remove(uhci->dentry);
|
||||
}
|
||||
|
||||
static int uhci_reset(struct usb_hcd *hcd)
|
||||
@ -474,33 +490,29 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
|
||||
dentry = debugfs_create_file(hcd->self.bus_name,
|
||||
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
|
||||
&uhci_debug_operations);
|
||||
if (!dentry) {
|
||||
dev_err(uhci_dev(uhci),
|
||||
"couldn't create uhci debugfs entry\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_create_debug_entry;
|
||||
}
|
||||
uhci->dentry = dentry;
|
||||
|
||||
uhci->fsbr = 0;
|
||||
uhci->fsbrtimeout = 0;
|
||||
|
||||
spin_lock_init(&uhci->lock);
|
||||
INIT_LIST_HEAD(&uhci->qh_remove_list);
|
||||
|
||||
INIT_LIST_HEAD(&uhci->td_remove_list);
|
||||
|
||||
INIT_LIST_HEAD(&uhci->urb_remove_list);
|
||||
|
||||
INIT_LIST_HEAD(&uhci->urb_list);
|
||||
|
||||
INIT_LIST_HEAD(&uhci->complete_list);
|
||||
INIT_LIST_HEAD(&uhci->idle_qh_list);
|
||||
|
||||
init_waitqueue_head(&uhci->waitqh);
|
||||
|
||||
if (DEBUG_CONFIGURED) {
|
||||
dentry = debugfs_create_file(hcd->self.bus_name,
|
||||
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
|
||||
uhci, &uhci_debug_operations);
|
||||
if (!dentry) {
|
||||
dev_err(uhci_dev(uhci), "couldn't create uhci "
|
||||
"debugfs entry\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_create_debug_entry;
|
||||
}
|
||||
uhci->dentry = dentry;
|
||||
}
|
||||
|
||||
uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
|
||||
UHCI_NUMFRAMES * sizeof(*uhci->frame),
|
||||
&uhci->frame_dma_handle, 0);
|
||||
@ -540,7 +552,7 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
for (i = 0; i < UHCI_NUM_SKELQH; i++) {
|
||||
uhci->skelqh[i] = uhci_alloc_qh(uhci);
|
||||
uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
|
||||
if (!uhci->skelqh[i]) {
|
||||
dev_err(uhci_dev(uhci), "unable to allocate QH\n");
|
||||
goto err_alloc_skelqh;
|
||||
@ -557,13 +569,17 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
uhci->skel_int16_qh->link =
|
||||
uhci->skel_int8_qh->link =
|
||||
uhci->skel_int4_qh->link =
|
||||
uhci->skel_int2_qh->link =
|
||||
cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
|
||||
uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
|
||||
uhci->skel_int2_qh->link = UHCI_PTR_QH |
|
||||
cpu_to_le32(uhci->skel_int1_qh->dma_handle);
|
||||
|
||||
uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
|
||||
uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
|
||||
uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
|
||||
uhci->skel_int1_qh->link = UHCI_PTR_QH |
|
||||
cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
|
||||
uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
|
||||
cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
|
||||
uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
|
||||
cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
|
||||
uhci->skel_bulk_qh->link = UHCI_PTR_QH |
|
||||
cpu_to_le32(uhci->skel_term_qh->dma_handle);
|
||||
|
||||
/* This dummy TD is to work around a bug in Intel PIIX controllers */
|
||||
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
|
||||
@ -589,15 +605,15 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
|
||||
/*
|
||||
* ffs (Find First bit Set) does exactly what we need:
|
||||
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6],
|
||||
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
|
||||
* ffs > 6 => not on any high-period queue, so use
|
||||
* skel_int1_qh = skelqh[7].
|
||||
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
|
||||
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
|
||||
* ffs >= 7 => not on any high-period queue, so use
|
||||
* skel_int1_qh = skelqh[9].
|
||||
* Add UHCI_NUMFRAMES to insure at least one bit is set.
|
||||
*/
|
||||
irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
|
||||
if (irq < 0)
|
||||
irq = 7;
|
||||
irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
|
||||
if (irq <= 1)
|
||||
irq = 9;
|
||||
|
||||
/* Only place we don't use the frame list routines */
|
||||
uhci->frame[i] = UHCI_PTR_QH |
|
||||
@ -611,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
mb();
|
||||
|
||||
configure_hc(uhci);
|
||||
uhci->is_initialized = 1;
|
||||
start_rh(uhci);
|
||||
return 0;
|
||||
|
||||
@ -767,13 +784,30 @@ static int uhci_resume(struct usb_hcd *hcd)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wait until all the URBs for a particular device/endpoint are gone */
|
||||
/* Wait until a particular device/endpoint's QH is idle, and free it */
|
||||
static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep)
|
||||
struct usb_host_endpoint *hep)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
struct uhci_qh *qh;
|
||||
|
||||
wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
|
||||
spin_lock_irq(&uhci->lock);
|
||||
qh = (struct uhci_qh *) hep->hcpriv;
|
||||
if (qh == NULL)
|
||||
goto done;
|
||||
|
||||
while (qh->state != QH_STATE_IDLE) {
|
||||
++uhci->num_waiting;
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
wait_event_interruptible(uhci->waitqh,
|
||||
qh->state == QH_STATE_IDLE);
|
||||
spin_lock_irq(&uhci->lock);
|
||||
--uhci->num_waiting;
|
||||
}
|
||||
|
||||
uhci_free_qh(uhci, qh);
|
||||
done:
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
}
|
||||
|
||||
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
|
||||
@ -857,16 +891,15 @@ static int __init uhci_hcd_init(void)
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
if (debug) {
|
||||
if (DEBUG_CONFIGURED) {
|
||||
errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
|
||||
if (!errbuf)
|
||||
goto errbuf_failed;
|
||||
uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
|
||||
if (!uhci_debugfs_root)
|
||||
goto debug_failed;
|
||||
}
|
||||
|
||||
uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
|
||||
if (!uhci_debugfs_root)
|
||||
goto debug_failed;
|
||||
|
||||
uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
|
||||
sizeof(struct urb_priv), 0, 0, NULL, NULL);
|
||||
if (!uhci_up_cachep)
|
||||
|
@ -28,8 +28,9 @@
|
||||
#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
|
||||
#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
|
||||
#define USBSTS_RD 0x0004 /* Resume Detect */
|
||||
#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */
|
||||
#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */
|
||||
#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */
|
||||
#define USBSTS_HCPE 0x0010 /* Host Controller Process Error:
|
||||
* the schedule is buggy */
|
||||
#define USBSTS_HCH 0x0020 /* HC Halted */
|
||||
|
||||
/* Interrupt enable register */
|
||||
@ -47,7 +48,8 @@
|
||||
/* USB port status and control registers */
|
||||
#define USBPORTSC1 16
|
||||
#define USBPORTSC2 18
|
||||
#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */
|
||||
#define USBPORTSC_CCS 0x0001 /* Current Connect Status
|
||||
* ("device present") */
|
||||
#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
|
||||
#define USBPORTSC_PE 0x0004 /* Port Enable */
|
||||
#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
|
||||
@ -71,15 +73,16 @@
|
||||
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
|
||||
#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
|
||||
|
||||
#define UHCI_PTR_BITS cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH cpu_to_le32(0x0002)
|
||||
#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
|
||||
#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
|
||||
#define UHCI_PTR_BITS __constant_cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM __constant_cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH __constant_cpu_to_le32(0x0002)
|
||||
#define UHCI_PTR_DEPTH __constant_cpu_to_le32(0x0004)
|
||||
#define UHCI_PTR_BREADTH __constant_cpu_to_le32(0x0000)
|
||||
|
||||
#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
|
||||
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
|
||||
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
|
||||
#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
|
||||
* can be scheduled */
|
||||
|
||||
|
||||
/*
|
||||
@ -87,38 +90,59 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* One role of a QH is to hold a queue of TDs for some endpoint. Each QH is
|
||||
* used with one URB, and qh->element (updated by the HC) is either:
|
||||
* - the next unprocessed TD for the URB, or
|
||||
* - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
|
||||
* - the QH for the next URB queued to the same endpoint.
|
||||
* One role of a QH is to hold a queue of TDs for some endpoint. One QH goes
|
||||
* with each endpoint, and qh->element (updated by the HC) is either:
|
||||
* - the next unprocessed TD in the endpoint's queue, or
|
||||
* - UHCI_PTR_TERM (when there's no more traffic for this endpoint).
|
||||
*
|
||||
* The other role of a QH is to serve as a "skeleton" framelist entry, so we
|
||||
* can easily splice a QH for some endpoint into the schedule at the right
|
||||
* place. Then qh->element is UHCI_PTR_TERM.
|
||||
*
|
||||
* In the frame list, qh->link maintains a list of QHs seen by the HC:
|
||||
* In the schedule, qh->link maintains a list of QHs seen by the HC:
|
||||
* skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
|
||||
*
|
||||
* qh->node is the software equivalent of qh->link. The differences
|
||||
* are that the software list is doubly-linked and QHs in the UNLINKING
|
||||
* state are on the software list but not the hardware schedule.
|
||||
*
|
||||
* For bookkeeping purposes we maintain QHs even for Isochronous endpoints,
|
||||
* but they never get added to the hardware schedule.
|
||||
*/
|
||||
#define QH_STATE_IDLE 1 /* QH is not being used */
|
||||
#define QH_STATE_UNLINKING 2 /* QH has been removed from the
|
||||
* schedule but the hardware may
|
||||
* still be using it */
|
||||
#define QH_STATE_ACTIVE 3 /* QH is on the schedule */
|
||||
|
||||
struct uhci_qh {
|
||||
/* Hardware fields */
|
||||
__le32 link; /* Next queue */
|
||||
__le32 element; /* Queue element pointer */
|
||||
__le32 link; /* Next QH in the schedule */
|
||||
__le32 element; /* Queue element (TD) pointer */
|
||||
|
||||
/* Software fields */
|
||||
dma_addr_t dma_handle;
|
||||
|
||||
struct urb_priv *urbp;
|
||||
struct list_head node; /* Node in the list of QHs */
|
||||
struct usb_host_endpoint *hep; /* Endpoint information */
|
||||
struct usb_device *udev;
|
||||
struct list_head queue; /* Queue of urbps for this QH */
|
||||
struct uhci_qh *skel; /* Skeleton for this QH */
|
||||
struct uhci_td *dummy_td; /* Dummy TD to end the queue */
|
||||
|
||||
struct list_head list;
|
||||
struct list_head remove_list;
|
||||
unsigned int unlink_frame; /* When the QH was unlinked */
|
||||
int state; /* QH_STATE_xxx; see above */
|
||||
|
||||
unsigned int initial_toggle:1; /* Endpoint's current toggle value */
|
||||
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
|
||||
unsigned int is_stopped:1; /* Queue was stopped by an error */
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
/*
|
||||
* We need a special accessor for the element pointer because it is
|
||||
* subject to asynchronous updates by the controller.
|
||||
*/
|
||||
static __le32 inline qh_element(struct uhci_qh *qh) {
|
||||
static inline __le32 qh_element(struct uhci_qh *qh) {
|
||||
__le32 element = qh->element;
|
||||
|
||||
barrier();
|
||||
@ -149,11 +173,13 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
|
||||
#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */
|
||||
|
||||
#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
|
||||
TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
|
||||
TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \
|
||||
TD_CTRL_BITSTUFF)
|
||||
|
||||
#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
|
||||
#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000)
|
||||
#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
|
||||
#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & \
|
||||
TD_CTRL_ACTLEN_MASK) /* 1-based */
|
||||
|
||||
/*
|
||||
* for TD <info>: (a.k.a. Token)
|
||||
@ -163,7 +189,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
|
||||
#define TD_TOKEN_TOGGLE_SHIFT 19
|
||||
#define TD_TOKEN_TOGGLE (1 << 19)
|
||||
#define TD_TOKEN_EXPLEN_SHIFT 21
|
||||
#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */
|
||||
#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */
|
||||
#define TD_TOKEN_PID_MASK 0xFF
|
||||
|
||||
#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
|
||||
@ -187,7 +213,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
|
||||
* sw space after the TD entry.
|
||||
*
|
||||
* td->link points to either another TD (not necessarily for the same urb or
|
||||
* even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
|
||||
* even the same endpoint), or nothing (PTR_TERM), or a QH.
|
||||
*/
|
||||
struct uhci_td {
|
||||
/* Hardware fields */
|
||||
@ -210,7 +236,7 @@ struct uhci_td {
|
||||
* We need a special accessor for the control/status word because it is
|
||||
* subject to asynchronous updates by the controller.
|
||||
*/
|
||||
static u32 inline td_status(struct uhci_td *td) {
|
||||
static inline u32 td_status(struct uhci_td *td) {
|
||||
__le32 status = td->status;
|
||||
|
||||
barrier();
|
||||
@ -223,17 +249,14 @@ static u32 inline td_status(struct uhci_td *td) {
|
||||
*/
|
||||
|
||||
/*
|
||||
* The UHCI driver places Interrupt, Control and Bulk into QHs both
|
||||
* to group together TDs for one transfer, and also to facilitate queuing
|
||||
* of URBs. To make it easy to insert entries into the schedule, we have
|
||||
* a skeleton of QHs for each predefined Interrupt latency, low-speed
|
||||
* control, full-speed control and terminating QH (see explanation for
|
||||
* the terminating QH below).
|
||||
* The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
|
||||
* automatic queuing. To make it easy to insert entries into the schedule,
|
||||
* we have a skeleton of QHs for each predefined Interrupt latency,
|
||||
* low-speed control, full-speed control, bulk, and terminating QH
|
||||
* (see explanation for the terminating QH below).
|
||||
*
|
||||
* When we want to add a new QH, we add it to the end of the list for the
|
||||
* skeleton QH.
|
||||
*
|
||||
* For instance, the queue can look like this:
|
||||
* skeleton QH. For instance, the schedule list can look like this:
|
||||
*
|
||||
* skel int128 QH
|
||||
* dev 1 interrupt QH
|
||||
@ -256,26 +279,31 @@ static u32 inline td_status(struct uhci_td *td) {
|
||||
* - To loop back to the full-speed control queue for full-speed bandwidth
|
||||
* reclamation.
|
||||
*
|
||||
* Isochronous transfers are stored before the start of the skeleton
|
||||
* schedule and don't use QHs. While the UHCI spec doesn't forbid the
|
||||
* use of QHs for Isochronous, it doesn't use them either. And the spec
|
||||
* says that queues never advance on an error completion status, which
|
||||
* makes them totally unsuitable for Isochronous transfers.
|
||||
* There's a special skeleton QH for Isochronous QHs. It never appears
|
||||
* on the schedule, and Isochronous TDs go on the schedule before the
|
||||
* the skeleton QHs. The hardware accesses them directly rather than
|
||||
* through their QH, which is used only for bookkeeping purposes.
|
||||
* While the UHCI spec doesn't forbid the use of QHs for Isochronous,
|
||||
* it doesn't use them either. And the spec says that queues never
|
||||
* advance on an error completion status, which makes them totally
|
||||
* unsuitable for Isochronous transfers.
|
||||
*/
|
||||
|
||||
#define UHCI_NUM_SKELQH 12
|
||||
#define skel_int128_qh skelqh[0]
|
||||
#define skel_int64_qh skelqh[1]
|
||||
#define skel_int32_qh skelqh[2]
|
||||
#define skel_int16_qh skelqh[3]
|
||||
#define skel_int8_qh skelqh[4]
|
||||
#define skel_int4_qh skelqh[5]
|
||||
#define skel_int2_qh skelqh[6]
|
||||
#define skel_int1_qh skelqh[7]
|
||||
#define skel_ls_control_qh skelqh[8]
|
||||
#define skel_fs_control_qh skelqh[9]
|
||||
#define skel_bulk_qh skelqh[10]
|
||||
#define skel_term_qh skelqh[11]
|
||||
#define UHCI_NUM_SKELQH 14
|
||||
#define skel_unlink_qh skelqh[0]
|
||||
#define skel_iso_qh skelqh[1]
|
||||
#define skel_int128_qh skelqh[2]
|
||||
#define skel_int64_qh skelqh[3]
|
||||
#define skel_int32_qh skelqh[4]
|
||||
#define skel_int16_qh skelqh[5]
|
||||
#define skel_int8_qh skelqh[6]
|
||||
#define skel_int4_qh skelqh[7]
|
||||
#define skel_int2_qh skelqh[8]
|
||||
#define skel_int1_qh skelqh[9]
|
||||
#define skel_ls_control_qh skelqh[10]
|
||||
#define skel_fs_control_qh skelqh[11]
|
||||
#define skel_bulk_qh skelqh[12]
|
||||
#define skel_term_qh skelqh[13]
|
||||
|
||||
/*
|
||||
* Search tree for determining where <interval> fits in the skelqh[]
|
||||
@ -293,21 +321,21 @@ static inline int __interval_to_skel(int interval)
|
||||
if (interval < 16) {
|
||||
if (interval < 4) {
|
||||
if (interval < 2)
|
||||
return 7; /* int1 for 0-1 ms */
|
||||
return 6; /* int2 for 2-3 ms */
|
||||
return 9; /* int1 for 0-1 ms */
|
||||
return 8; /* int2 for 2-3 ms */
|
||||
}
|
||||
if (interval < 8)
|
||||
return 5; /* int4 for 4-7 ms */
|
||||
return 4; /* int8 for 8-15 ms */
|
||||
return 7; /* int4 for 4-7 ms */
|
||||
return 6; /* int8 for 8-15 ms */
|
||||
}
|
||||
if (interval < 64) {
|
||||
if (interval < 32)
|
||||
return 3; /* int16 for 16-31 ms */
|
||||
return 2; /* int32 for 32-63 ms */
|
||||
return 5; /* int16 for 16-31 ms */
|
||||
return 4; /* int32 for 32-63 ms */
|
||||
}
|
||||
if (interval < 128)
|
||||
return 1; /* int64 for 64-127 ms */
|
||||
return 0; /* int128 for 128-255 ms (Max.) */
|
||||
return 3; /* int64 for 64-127 ms */
|
||||
return 2; /* int128 for 128-255 ms (Max.) */
|
||||
}
|
||||
|
||||
|
||||
@ -360,15 +388,16 @@ struct uhci_hcd {
|
||||
|
||||
struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
|
||||
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */
|
||||
struct uhci_qh *next_qh; /* Next QH to scan */
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
dma_addr_t frame_dma_handle; /* Hardware frame list */
|
||||
dma_addr_t frame_dma_handle; /* Hardware frame list */
|
||||
__le32 *frame;
|
||||
void **frame_cpu; /* CPU's frame list */
|
||||
void **frame_cpu; /* CPU's frame list */
|
||||
|
||||
int fsbr; /* Full-speed bandwidth reclamation */
|
||||
unsigned long fsbrtimeout; /* FSBR delay */
|
||||
int fsbr; /* Full-speed bandwidth reclamation */
|
||||
unsigned long fsbrtimeout; /* FSBR delay */
|
||||
|
||||
enum uhci_rh_state rh_state;
|
||||
unsigned long auto_stop_time; /* When to AUTO_STOP */
|
||||
@ -382,6 +411,7 @@ struct uhci_hcd {
|
||||
unsigned int hc_inaccessible:1; /* HC is suspended or dead */
|
||||
unsigned int working_RD:1; /* Suspended root hub doesn't
|
||||
need to be polled */
|
||||
unsigned int is_initialized:1; /* Data structure is usable */
|
||||
|
||||
/* Support for port suspend/resume/reset */
|
||||
unsigned long port_c_suspend; /* Bit-arrays of ports */
|
||||
@ -389,27 +419,16 @@ struct uhci_hcd {
|
||||
unsigned long resuming_ports;
|
||||
unsigned long ports_timeout; /* Time to stop signalling */
|
||||
|
||||
/* Main list of URBs currently controlled by this HC */
|
||||
struct list_head urb_list;
|
||||
|
||||
/* List of QHs that are done, but waiting to be unlinked (race) */
|
||||
struct list_head qh_remove_list;
|
||||
unsigned int qh_remove_age; /* Age in frames */
|
||||
|
||||
/* List of TDs that are done, but waiting to be freed (race) */
|
||||
struct list_head td_remove_list;
|
||||
unsigned int td_remove_age; /* Age in frames */
|
||||
|
||||
/* List of asynchronously unlinked URBs */
|
||||
struct list_head urb_remove_list;
|
||||
unsigned int urb_remove_age; /* Age in frames */
|
||||
|
||||
/* List of URBs awaiting completion callback */
|
||||
struct list_head complete_list;
|
||||
struct list_head idle_qh_list; /* Where the idle QHs live */
|
||||
|
||||
int rh_numports; /* Number of root-hub ports */
|
||||
|
||||
wait_queue_head_t waitqh; /* endpoint_disable waiters */
|
||||
int num_waiting; /* Number of waiters */
|
||||
};
|
||||
|
||||
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
|
||||
@ -429,7 +448,7 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
|
||||
* Private per-URB data
|
||||
*/
|
||||
struct urb_priv {
|
||||
struct list_head urb_list;
|
||||
struct list_head node; /* Node in the QH's urbp list */
|
||||
|
||||
struct urb *urb;
|
||||
|
||||
@ -437,15 +456,8 @@ struct urb_priv {
|
||||
struct list_head td_list;
|
||||
|
||||
unsigned fsbr : 1; /* URB turned on FSBR */
|
||||
unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
|
||||
unsigned queued : 1; /* QH was queued (not linked in) */
|
||||
unsigned short_control_packet : 1; /* If we get a short packet during */
|
||||
/* a control transfer, retrigger */
|
||||
/* the status phase */
|
||||
|
||||
unsigned long fsbrtime; /* In jiffies */
|
||||
|
||||
struct list_head queue_list;
|
||||
unsigned short_transfer : 1; /* URB got a short transfer, no
|
||||
* need to rescan */
|
||||
};
|
||||
|
||||
|
||||
|
@ -99,6 +99,21 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the UHCI controller in HP's iLO2 server management chip.
|
||||
* It can take up to 250 us to finish a reset and set the CSC bit.
|
||||
*/
|
||||
static void wait_for_HP(unsigned long port_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 10; i < 250; i += 10) {
|
||||
if (inw(port_addr) & USBPORTSC_CSC)
|
||||
return;
|
||||
udelay(10);
|
||||
}
|
||||
/* Log a warning? */
|
||||
}
|
||||
|
||||
static void uhci_check_ports(struct uhci_hcd *uhci)
|
||||
{
|
||||
unsigned int port;
|
||||
@ -113,6 +128,12 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
|
||||
CLR_RH_PORTSTAT(USBPORTSC_PR);
|
||||
udelay(10);
|
||||
|
||||
/* HP's server management chip requires
|
||||
* a longer delay. */
|
||||
if (to_pci_dev(uhci_dev(uhci))->vendor ==
|
||||
PCI_VENDOR_ID_HP)
|
||||
wait_for_HP(port_addr);
|
||||
|
||||
/* If the port was enabled before, turning
|
||||
* reset on caused a port enable change.
|
||||
* Turning reset off causes a port connect
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -96,6 +96,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/fs.h>
|
||||
@ -169,7 +170,7 @@ struct mdc800_data
|
||||
int out_count; // Bytes in the buffer
|
||||
|
||||
int open; // Camera device open ?
|
||||
struct semaphore io_lock; // IO -lock
|
||||
struct mutex io_lock; // IO -lock
|
||||
|
||||
char in [8]; // Command Input Buffer
|
||||
int in_count;
|
||||
@ -497,7 +498,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
|
||||
|
||||
info ("Found Mustek MDC800 on USB.");
|
||||
|
||||
down (&mdc800->io_lock);
|
||||
mutex_lock(&mdc800->io_lock);
|
||||
|
||||
retval = usb_register_dev(intf, &mdc800_class);
|
||||
if (retval) {
|
||||
@ -542,7 +543,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
|
||||
|
||||
mdc800->state=READY;
|
||||
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
|
||||
usb_set_intfdata(intf, mdc800);
|
||||
return 0;
|
||||
@ -620,7 +621,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
|
||||
int retval=0;
|
||||
int errn=0;
|
||||
|
||||
down (&mdc800->io_lock);
|
||||
mutex_lock(&mdc800->io_lock);
|
||||
|
||||
if (mdc800->state == NOT_CONNECTED)
|
||||
{
|
||||
@ -656,7 +657,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
|
||||
dbg ("Mustek MDC800 device opened.");
|
||||
|
||||
error_out:
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return errn;
|
||||
}
|
||||
|
||||
@ -669,7 +670,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
|
||||
int retval=0;
|
||||
dbg ("Mustek MDC800 device closed.");
|
||||
|
||||
down (&mdc800->io_lock);
|
||||
mutex_lock(&mdc800->io_lock);
|
||||
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
|
||||
{
|
||||
usb_kill_urb(mdc800->irq_urb);
|
||||
@ -682,7 +683,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
|
||||
retval=-EIO;
|
||||
}
|
||||
|
||||
up(&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -695,21 +696,21 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
size_t left=len, sts=len; /* single transfer size */
|
||||
char __user *ptr = buf;
|
||||
|
||||
down (&mdc800->io_lock);
|
||||
mutex_lock(&mdc800->io_lock);
|
||||
if (mdc800->state == NOT_CONNECTED)
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (mdc800->state == WORKING)
|
||||
{
|
||||
warn ("Illegal State \"working\" reached during read ?!");
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!mdc800->open)
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -717,7 +718,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
{
|
||||
if (signal_pending (current))
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
@ -736,7 +737,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
|
||||
{
|
||||
err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return len-left;
|
||||
}
|
||||
wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
|
||||
@ -745,14 +746,14 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
if (mdc800->download_urb->status != 0)
|
||||
{
|
||||
err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return len-left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more bytes -> that's an error*/
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -761,7 +762,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
/* Copy Bytes */
|
||||
if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
|
||||
sts)) {
|
||||
up(&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
ptr+=sts;
|
||||
@ -770,7 +771,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
|
||||
}
|
||||
}
|
||||
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return len-left;
|
||||
}
|
||||
|
||||
@ -785,15 +786,15 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
{
|
||||
size_t i=0;
|
||||
|
||||
down (&mdc800->io_lock);
|
||||
mutex_lock(&mdc800->io_lock);
|
||||
if (mdc800->state != READY)
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!mdc800->open )
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -802,13 +803,13 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
unsigned char c;
|
||||
if (signal_pending (current))
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if(get_user(c, buf+i))
|
||||
{
|
||||
up(&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
@ -829,7 +830,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
}
|
||||
else
|
||||
{
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -841,7 +842,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
|
||||
{
|
||||
err ("Camera didn't get ready.\n");
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -853,7 +854,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
|
||||
{
|
||||
err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
|
||||
@ -861,7 +862,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
if (mdc800->state == WORKING)
|
||||
{
|
||||
usb_kill_urb(mdc800->write_urb);
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -873,7 +874,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
{
|
||||
err ("call 0x07 before 0x05,0x3e");
|
||||
mdc800->state=READY;
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
mdc800->pic_len=-1;
|
||||
@ -892,7 +893,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
|
||||
{
|
||||
err ("requesting answer from irq fails");
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -920,7 +921,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
|
||||
{
|
||||
err ("Command Timeout.");
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -930,7 +931,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
|
||||
}
|
||||
i++;
|
||||
}
|
||||
up (&mdc800->io_lock);
|
||||
mutex_unlock(&mdc800->io_lock);
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -978,15 +979,13 @@ static int __init usb_mdc800_init (void)
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
/* Allocate Memory */
|
||||
mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
|
||||
mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
|
||||
if (!mdc800)
|
||||
goto cleanup_on_fail;
|
||||
|
||||
memset(mdc800, 0, sizeof(struct mdc800_data));
|
||||
mdc800->dev = NULL;
|
||||
mdc800->open=0;
|
||||
mdc800->state=NOT_CONNECTED;
|
||||
init_MUTEX (&mdc800->io_lock);
|
||||
mutex_init (&mdc800->io_lock);
|
||||
|
||||
init_waitqueue_head (&mdc800->irq_wait);
|
||||
init_waitqueue_head (&mdc800->write_wait);
|
||||
|
@ -159,8 +159,6 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
|
||||
*/
|
||||
#define FILTER_TIME (HZ / 20)
|
||||
|
||||
static DECLARE_MUTEX(disconnect_sem);
|
||||
|
||||
struct ati_remote {
|
||||
struct input_dev *idev;
|
||||
struct usb_device *udev;
|
||||
|
@ -66,9 +66,8 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
|
||||
if (report_enum->report_id_hash[id])
|
||||
return report_enum->report_id_hash[id];
|
||||
|
||||
if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
|
||||
if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(report, 0, sizeof(struct hid_report));
|
||||
|
||||
if (id != 0)
|
||||
report_enum->numbered = 1;
|
||||
@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
|
||||
if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
|
||||
+ values * sizeof(unsigned), GFP_KERNEL))) return NULL;
|
||||
|
||||
memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
|
||||
+ values * sizeof(unsigned));
|
||||
|
||||
field->index = report->maxfield++;
|
||||
report->field[field->index] = field;
|
||||
field->usage = (struct hid_usage *)(field + 1);
|
||||
@ -651,17 +647,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
|
||||
hid_parser_reserved
|
||||
};
|
||||
|
||||
if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
|
||||
if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(device, 0, sizeof(struct hid_device));
|
||||
|
||||
if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
|
||||
if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
|
||||
HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
|
||||
kfree(device);
|
||||
return NULL;
|
||||
}
|
||||
memset(device->collection, 0, sizeof(struct hid_collection) *
|
||||
HID_DEFAULT_NUM_COLLECTIONS);
|
||||
device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
|
||||
|
||||
for (i = 0; i < HID_REPORT_TYPES; i++)
|
||||
@ -675,13 +668,12 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
|
||||
memcpy(device->rdesc, start, size);
|
||||
device->rsize = size;
|
||||
|
||||
if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
|
||||
if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
|
||||
kfree(device->rdesc);
|
||||
kfree(device->collection);
|
||||
kfree(device);
|
||||
return NULL;
|
||||
}
|
||||
memset(parser, 0, sizeof(struct hid_parser));
|
||||
parser->device = device;
|
||||
|
||||
end = start + size;
|
||||
@ -910,6 +902,99 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input submission and I/O error handler.
|
||||
*/
|
||||
|
||||
static void hid_io_error(struct hid_device *hid);
|
||||
|
||||
/* Start up the input URB */
|
||||
static int hid_start_in(struct hid_device *hid)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_irqsave(&hid->inlock, flags);
|
||||
if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
|
||||
!test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
|
||||
rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
|
||||
if (rc != 0)
|
||||
clear_bit(HID_IN_RUNNING, &hid->iofl);
|
||||
}
|
||||
spin_unlock_irqrestore(&hid->inlock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* I/O retry timer routine */
|
||||
static void hid_retry_timeout(unsigned long _hid)
|
||||
{
|
||||
struct hid_device *hid = (struct hid_device *) _hid;
|
||||
|
||||
dev_dbg(&hid->intf->dev, "retrying intr urb\n");
|
||||
if (hid_start_in(hid))
|
||||
hid_io_error(hid);
|
||||
}
|
||||
|
||||
/* Workqueue routine to reset the device */
|
||||
static void hid_reset(void *_hid)
|
||||
{
|
||||
struct hid_device *hid = (struct hid_device *) _hid;
|
||||
int rc_lock, rc;
|
||||
|
||||
dev_dbg(&hid->intf->dev, "resetting device\n");
|
||||
rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
|
||||
if (rc_lock >= 0) {
|
||||
rc = usb_reset_device(hid->dev);
|
||||
if (rc_lock)
|
||||
usb_unlock_device(hid->dev);
|
||||
}
|
||||
clear_bit(HID_RESET_PENDING, &hid->iofl);
|
||||
|
||||
if (rc == 0) {
|
||||
hid->retry_delay = 0;
|
||||
if (hid_start_in(hid))
|
||||
hid_io_error(hid);
|
||||
} else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))
|
||||
err("can't reset device, %s-%s/input%d, status %d",
|
||||
hid->dev->bus->bus_name,
|
||||
hid->dev->devpath,
|
||||
hid->ifnum, rc);
|
||||
}
|
||||
|
||||
/* Main I/O error handler */
|
||||
static void hid_io_error(struct hid_device *hid)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hid->inlock, flags);
|
||||
|
||||
/* Stop when disconnected */
|
||||
if (usb_get_intfdata(hid->intf) == NULL)
|
||||
goto done;
|
||||
|
||||
/* When an error occurs, retry at increasing intervals */
|
||||
if (hid->retry_delay == 0) {
|
||||
hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
|
||||
hid->stop_retry = jiffies + msecs_to_jiffies(1000);
|
||||
} else if (hid->retry_delay < 100)
|
||||
hid->retry_delay *= 2;
|
||||
|
||||
if (time_after(jiffies, hid->stop_retry)) {
|
||||
|
||||
/* Retries failed, so do a port reset */
|
||||
if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
|
||||
if (schedule_work(&hid->reset_work))
|
||||
goto done;
|
||||
clear_bit(HID_RESET_PENDING, &hid->iofl);
|
||||
}
|
||||
}
|
||||
|
||||
mod_timer(&hid->io_retry,
|
||||
jiffies + msecs_to_jiffies(hid->retry_delay));
|
||||
done:
|
||||
spin_unlock_irqrestore(&hid->inlock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input interrupt completion handler.
|
||||
*/
|
||||
@ -921,25 +1006,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
|
||||
|
||||
switch (urb->status) {
|
||||
case 0: /* success */
|
||||
hid->retry_delay = 0;
|
||||
hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
|
||||
break;
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -EPERM:
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
case -EILSEQ: /* unplug timeout on uhci */
|
||||
clear_bit(HID_IN_RUNNING, &hid->iofl);
|
||||
return;
|
||||
case -EILSEQ: /* protocol error or unplug */
|
||||
case -EPROTO: /* protocol error or unplug */
|
||||
case -ETIMEDOUT: /* NAK */
|
||||
break;
|
||||
clear_bit(HID_IN_RUNNING, &hid->iofl);
|
||||
hid_io_error(hid);
|
||||
return;
|
||||
default: /* error */
|
||||
warn("input irq status %d received", urb->status);
|
||||
}
|
||||
|
||||
status = usb_submit_urb(urb, SLAB_ATOMIC);
|
||||
if (status)
|
||||
err("can't resubmit intr, %s-%s/input%d, status %d",
|
||||
hid->dev->bus->bus_name, hid->dev->devpath,
|
||||
hid->ifnum, status);
|
||||
if (status) {
|
||||
clear_bit(HID_IN_RUNNING, &hid->iofl);
|
||||
if (status != -EPERM) {
|
||||
err("can't resubmit intr, %s-%s/input%d, status %d",
|
||||
hid->dev->bus->bus_name,
|
||||
hid->dev->devpath,
|
||||
hid->ifnum, status);
|
||||
hid_io_error(hid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1101,8 +1196,9 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
|
||||
case 0: /* success */
|
||||
break;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
case -EILSEQ: /* unplug timeout on uhci */
|
||||
unplug = 1;
|
||||
case -EILSEQ: /* protocol error or unplug */
|
||||
case -EPROTO: /* protocol error or unplug */
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
break;
|
||||
@ -1149,8 +1245,9 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
|
||||
hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
|
||||
break;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
case -EILSEQ: /* unplug timectrl on uhci */
|
||||
unplug = 1;
|
||||
case -EILSEQ: /* protocol error or unplug */
|
||||
case -EPROTO: /* protocol error or unplug */
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -EPIPE: /* report not available */
|
||||
@ -1263,14 +1360,9 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
|
||||
|
||||
int hid_open(struct hid_device *hid)
|
||||
{
|
||||
if (hid->open++)
|
||||
return 0;
|
||||
|
||||
hid->urbin->dev = hid->dev;
|
||||
|
||||
if (usb_submit_urb(hid->urbin, GFP_KERNEL))
|
||||
return -EIO;
|
||||
|
||||
++hid->open;
|
||||
if (hid_start_in(hid))
|
||||
hid_io_error(hid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1460,6 +1552,9 @@ void hid_init_reports(struct hid_device *hid)
|
||||
#define USB_VENDOR_ID_HP 0x03f0
|
||||
#define USB_DEVICE_ID_HP_USBHUB_KB 0x020c
|
||||
|
||||
#define USB_VENDOR_ID_CREATIVELABS 0x062a
|
||||
#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201
|
||||
|
||||
/*
|
||||
* Alphabetically sorted blacklist by quirk type.
|
||||
*/
|
||||
@ -1576,6 +1671,7 @@ static const struct hid_blacklist {
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
|
||||
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
|
||||
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
@ -1795,6 +1891,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
||||
|
||||
init_waitqueue_head(&hid->wait);
|
||||
|
||||
INIT_WORK(&hid->reset_work, hid_reset, hid);
|
||||
setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
|
||||
|
||||
spin_lock_init(&hid->inlock);
|
||||
spin_lock_init(&hid->outlock);
|
||||
spin_lock_init(&hid->ctrllock);
|
||||
|
||||
@ -1863,11 +1963,16 @@ static void hid_disconnect(struct usb_interface *intf)
|
||||
if (!hid)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&hid->inlock); /* Sync with error handler */
|
||||
usb_set_intfdata(intf, NULL);
|
||||
spin_unlock_irq(&hid->inlock);
|
||||
usb_kill_urb(hid->urbin);
|
||||
usb_kill_urb(hid->urbout);
|
||||
usb_kill_urb(hid->urbctrl);
|
||||
|
||||
del_timer_sync(&hid->io_retry);
|
||||
flush_scheduled_work();
|
||||
|
||||
if (hid->claimed & HID_CLAIMED_INPUT)
|
||||
hidinput_disconnect(hid);
|
||||
if (hid->claimed & HID_CLAIMED_HIDDEV)
|
||||
@ -1942,6 +2047,10 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct hid_device *hid = usb_get_intfdata (intf);
|
||||
|
||||
spin_lock_irq(&hid->inlock); /* Sync with error handler */
|
||||
set_bit(HID_SUSPENDED, &hid->iofl);
|
||||
spin_unlock_irq(&hid->inlock);
|
||||
del_timer(&hid->io_retry);
|
||||
usb_kill_urb(hid->urbin);
|
||||
dev_dbg(&intf->dev, "suspend\n");
|
||||
return 0;
|
||||
@ -1952,10 +2061,8 @@ static int hid_resume(struct usb_interface *intf)
|
||||
struct hid_device *hid = usb_get_intfdata (intf);
|
||||
int status;
|
||||
|
||||
if (hid->open)
|
||||
status = usb_submit_urb(hid->urbin, GFP_NOIO);
|
||||
else
|
||||
status = 0;
|
||||
clear_bit(HID_SUSPENDED, &hid->iofl);
|
||||
status = hid_start_in(hid);
|
||||
dev_dbg(&intf->dev, "resume status %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
|
||||
private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
|
||||
if (!private)
|
||||
return -1;
|
||||
memset(private, 0, sizeof(struct lgff_device));
|
||||
hid->ff_private = private;
|
||||
|
||||
/* Input init */
|
||||
@ -228,13 +227,12 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
|
||||
}
|
||||
*ret->field[0] = *report->field[0];
|
||||
|
||||
ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
|
||||
ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
|
||||
if (!ret->field[0]->value) {
|
||||
kfree(ret->field[0]);
|
||||
kfree(ret);
|
||||
return NULL;
|
||||
}
|
||||
memset(ret->field[0]->value, 0, sizeof(s32[8]));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -113,11 +113,10 @@ int hid_tmff_init(struct hid_device *hid)
|
||||
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
|
||||
struct input_dev *input_dev = hidinput->input;
|
||||
|
||||
private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
|
||||
private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
|
||||
if (!private)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(private, 0, sizeof(struct tmff_device));
|
||||
hid->ff_private = private;
|
||||
|
||||
/* Find the report to use */
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/*
|
||||
* USB HID (Human Interface Device) interface class code
|
||||
@ -370,6 +372,9 @@ struct hid_control_fifo {
|
||||
|
||||
#define HID_CTRL_RUNNING 1
|
||||
#define HID_OUT_RUNNING 2
|
||||
#define HID_IN_RUNNING 3
|
||||
#define HID_RESET_PENDING 4
|
||||
#define HID_SUSPENDED 5
|
||||
|
||||
struct hid_input {
|
||||
struct list_head list;
|
||||
@ -393,12 +398,17 @@ struct hid_device { /* device report descriptor */
|
||||
int ifnum; /* USB interface number */
|
||||
|
||||
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
|
||||
struct timer_list io_retry; /* Retry timer */
|
||||
unsigned long stop_retry; /* Time to give up, in jiffies */
|
||||
unsigned int retry_delay; /* Delay length in ms */
|
||||
struct work_struct reset_work; /* Task context for resets */
|
||||
|
||||
unsigned int bufsize; /* URB buffer size */
|
||||
|
||||
struct urb *urbin; /* Input URB */
|
||||
char *inbuf; /* Input buffer */
|
||||
dma_addr_t inbuf_dma; /* Input buffer dma */
|
||||
spinlock_t inlock; /* Input fifo spinlock */
|
||||
|
||||
struct urb *urbctrl; /* Control URB */
|
||||
struct usb_ctrlrequest *cr; /* Control request struct */
|
||||
|
@ -257,9 +257,8 @@ static int hiddev_open(struct inode * inode, struct file * file) {
|
||||
if (i >= HIDDEV_MINORS || !hiddev_table[i])
|
||||
return -ENODEV;
|
||||
|
||||
if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
|
||||
if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
memset(list, 0, sizeof(struct hiddev_list));
|
||||
|
||||
list->hiddev = hiddev_table[i];
|
||||
list->next = hiddev_table[i]->list;
|
||||
@ -754,9 +753,8 @@ int hiddev_connect(struct hid_device *hid)
|
||||
if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
|
||||
return -1;
|
||||
|
||||
if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
|
||||
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
|
||||
return -1;
|
||||
memset(hiddev, 0, sizeof(struct hiddev));
|
||||
|
||||
retval = usb_register_dev(hid->intf, &hiddev_class);
|
||||
if (retval) {
|
||||
|
@ -191,6 +191,21 @@ config USB_W9968CF
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called w9968cf.
|
||||
|
||||
config USB_ZC0301
|
||||
tristate "USB ZC0301 Image Processor and Control Chip support"
|
||||
depends on USB && VIDEO_DEV
|
||||
---help---
|
||||
Say Y here if you want support for cameras based on the ZC0301
|
||||
Image Processor and Control Chip.
|
||||
|
||||
See <file:Documentation/usb/zc0301.txt> for more informations.
|
||||
|
||||
This driver uses the Video For Linux API. You must say Y or M to
|
||||
"Video For Linux" to use this driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zc0301.
|
||||
|
||||
config USB_PWC
|
||||
tristate "USB Philips Cameras"
|
||||
depends on USB && VIDEO_DEV
|
||||
|
@ -2,8 +2,12 @@
|
||||
# Makefile for USB Media drivers
|
||||
#
|
||||
|
||||
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
|
||||
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
|
||||
sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
|
||||
sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
|
||||
sn9c102_tas5130d1b.o
|
||||
et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o
|
||||
zc0301-objs := zc0301_core.o zc0301_pas202bcb.o
|
||||
|
||||
obj-$(CONFIG_USB_DABUSB) += dabusb.o
|
||||
obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
||||
@ -16,4 +20,5 @@ obj-$(CONFIG_USB_SN9C102) += sn9c102.o
|
||||
obj-$(CONFIG_USB_STV680) += stv680.o
|
||||
obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o
|
||||
obj-$(CONFIG_USB_W9968CF) += w9968cf.o
|
||||
obj-$(CONFIG_USB_ZC0301) += zc0301.o
|
||||
obj-$(CONFIG_USB_PWC) += pwc/
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "dabusb.h"
|
||||
#include "dabfirmware.h"
|
||||
@ -217,12 +218,11 @@ static int dabusb_alloc_buffers (pdabusb_t s)
|
||||
pipesize, packets, transfer_buffer_length);
|
||||
|
||||
while (buffers < (s->total_buffer_size << 10)) {
|
||||
b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
|
||||
b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
|
||||
if (!b) {
|
||||
err("kmalloc(sizeof(buff_t))==NULL");
|
||||
err("kzalloc(sizeof(buff_t))==NULL");
|
||||
goto err;
|
||||
}
|
||||
memset (b, 0, sizeof (buff_t));
|
||||
b->s = s;
|
||||
b->purb = usb_alloc_urb(packets, GFP_KERNEL);
|
||||
if (!b->purb) {
|
||||
@ -571,7 +571,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
|
||||
s->readptr = 0;
|
||||
}
|
||||
}
|
||||
err: //up(&s->mutex);
|
||||
err: //mutex_unlock(&s->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -586,10 +586,10 @@ static int dabusb_open (struct inode *inode, struct file *file)
|
||||
s = &dabusb[devnum - DABUSB_MINOR];
|
||||
|
||||
dbg("dabusb_open");
|
||||
down (&s->mutex);
|
||||
mutex_lock(&s->mutex);
|
||||
|
||||
while (!s->usbdev || s->opened) {
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
return -EBUSY;
|
||||
@ -599,15 +599,15 @@ static int dabusb_open (struct inode *inode, struct file *file)
|
||||
if (signal_pending (current)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
down (&s->mutex);
|
||||
mutex_lock(&s->mutex);
|
||||
}
|
||||
if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
|
||||
up(&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
err("set_interface failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
s->opened = 1;
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
|
||||
file->f_pos = 0;
|
||||
file->private_data = s;
|
||||
@ -621,10 +621,10 @@ static int dabusb_release (struct inode *inode, struct file *file)
|
||||
|
||||
dbg("dabusb_release");
|
||||
|
||||
down (&s->mutex);
|
||||
mutex_lock(&s->mutex);
|
||||
dabusb_stop (s);
|
||||
dabusb_free_buffers (s);
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
|
||||
if (!s->remove_pending) {
|
||||
if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
|
||||
@ -649,10 +649,10 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
|
||||
if (s->remove_pending)
|
||||
return -EIO;
|
||||
|
||||
down (&s->mutex);
|
||||
mutex_lock(&s->mutex);
|
||||
|
||||
if (!s->usbdev) {
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -692,7 +692,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
}
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -738,7 +738,7 @@ static int dabusb_probe (struct usb_interface *intf,
|
||||
|
||||
s = &dabusb[intf->minor];
|
||||
|
||||
down (&s->mutex);
|
||||
mutex_lock(&s->mutex);
|
||||
s->remove_pending = 0;
|
||||
s->usbdev = usbdev;
|
||||
s->devnum = intf->minor;
|
||||
@ -761,7 +761,7 @@ static int dabusb_probe (struct usb_interface *intf,
|
||||
}
|
||||
dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
|
||||
usb_set_intfdata (intf, s);
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
|
||||
retval = usb_register_dev(intf, &dabusb_class);
|
||||
if (retval) {
|
||||
@ -772,7 +772,7 @@ static int dabusb_probe (struct usb_interface *intf,
|
||||
return 0;
|
||||
|
||||
reject:
|
||||
up (&s->mutex);
|
||||
mutex_unlock(&s->mutex);
|
||||
s->usbdev = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -829,7 +829,7 @@ static int __init dabusb_init (void)
|
||||
for (u = 0; u < NRDABUSB; u++) {
|
||||
pdabusb_t s = &dabusb[u];
|
||||
memset (s, 0, sizeof (dabusb_t));
|
||||
init_MUTEX (&s->mutex);
|
||||
mutex_init (&s->mutex);
|
||||
s->usbdev = NULL;
|
||||
s->total_buffer_size = buffers;
|
||||
init_waitqueue_head (&s->wait);
|
||||
|
@ -18,7 +18,7 @@ typedef enum { _stopped=0, _started } driver_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct semaphore mutex;
|
||||
struct mutex mutex;
|
||||
struct usb_device *usbdev;
|
||||
wait_queue_head_t wait;
|
||||
wait_queue_head_t remove_ok;
|
||||
|
@ -33,7 +33,9 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "et61x251_sensor.h"
|
||||
|
||||
@ -51,6 +53,7 @@
|
||||
#define ET61X251_ALTERNATE_SETTING 13
|
||||
#define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
|
||||
#define ET61X251_CTRL_TIMEOUT 100
|
||||
#define ET61X251_FRAME_TIMEOUT 2
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -127,15 +130,16 @@ struct et61x251_sysfs_attr {
|
||||
|
||||
struct et61x251_module_param {
|
||||
u8 force_munmap;
|
||||
u16 frame_timeout;
|
||||
};
|
||||
|
||||
static DECLARE_MUTEX(et61x251_sysfs_lock);
|
||||
static DEFINE_MUTEX(et61x251_sysfs_lock);
|
||||
static DECLARE_RWSEM(et61x251_disconnect);
|
||||
|
||||
struct et61x251_device {
|
||||
struct video_device* v4ldev;
|
||||
|
||||
struct et61x251_sensor* sensor;
|
||||
struct et61x251_sensor sensor;
|
||||
|
||||
struct usb_device* usbdev;
|
||||
struct urb* urb[ET61X251_URBS];
|
||||
@ -157,19 +161,28 @@ struct et61x251_device {
|
||||
enum et61x251_dev_state state;
|
||||
u8 users;
|
||||
|
||||
struct semaphore dev_sem, fileop_sem;
|
||||
struct mutex dev_mutex, fileop_mutex;
|
||||
spinlock_t queue_lock;
|
||||
wait_queue_head_t open, wait_frame, wait_stream;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct et61x251_device*
|
||||
et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
|
||||
{
|
||||
if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
|
||||
return cam;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
et61x251_attach_sensor(struct et61x251_device* cam,
|
||||
struct et61x251_sensor* sensor)
|
||||
{
|
||||
cam->sensor = sensor;
|
||||
cam->sensor->usbdev = cam->usbdev;
|
||||
memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -212,7 +225,8 @@ do { \
|
||||
|
||||
#undef PDBG
|
||||
#define PDBG(fmt, args...) \
|
||||
dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
|
||||
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
|
||||
__FUNCTION__, __LINE__ , ## args)
|
||||
|
||||
#undef PDBGG
|
||||
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
|
||||
|
@ -25,11 +25,9 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/poll.h>
|
||||
@ -50,8 +48,8 @@
|
||||
#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
|
||||
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
|
||||
#define ET61X251_MODULE_LICENSE "GPL"
|
||||
#define ET61X251_MODULE_VERSION "1:1.01"
|
||||
#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1)
|
||||
#define ET61X251_MODULE_VERSION "1:1.02"
|
||||
#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -90,6 +88,16 @@ MODULE_PARM_DESC(force_munmap,
|
||||
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
|
||||
"\n");
|
||||
|
||||
static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
|
||||
ET61X251_FRAME_TIMEOUT};
|
||||
module_param_array(frame_timeout, uint, NULL, 0644);
|
||||
MODULE_PARM_DESC(frame_timeout,
|
||||
"\n<n[,...]> Timeout for a video frame in seconds."
|
||||
"\nThis parameter is specific for each detected camera."
|
||||
"\nDefault value is "
|
||||
__MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
|
||||
"\n");
|
||||
|
||||
#ifdef ET61X251_DEBUG
|
||||
static unsigned short debug = ET61X251_DEBUG_LEVEL;
|
||||
module_param(debug, ushort, 0644);
|
||||
@ -111,8 +119,8 @@ static u32
|
||||
et61x251_request_buffers(struct et61x251_device* cam, u32 count,
|
||||
enum et61x251_io_method io)
|
||||
{
|
||||
struct v4l2_pix_format* p = &(cam->sensor->pix_format);
|
||||
struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
|
||||
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
|
||||
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
|
||||
const size_t imagesize = cam->module_param.force_munmap ||
|
||||
io == IO_READ ?
|
||||
(p->width * p->height * p->priv) / 8 :
|
||||
@ -268,8 +276,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
|
||||
int err = 0, res;
|
||||
|
||||
data[0] = address;
|
||||
data[1] = cam->sensor->i2c_slave_id;
|
||||
data[2] = cam->sensor->rsta | 0x10;
|
||||
data[1] = cam->sensor.i2c_slave_id;
|
||||
data[2] = cam->sensor.rsta | 0x10;
|
||||
data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
|
||||
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
|
||||
0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
|
||||
@ -301,8 +309,8 @@ et61x251_i2c_try_write(struct et61x251_device* cam,
|
||||
int err = 0, res;
|
||||
|
||||
data[0] = address;
|
||||
data[1] = cam->sensor->i2c_slave_id;
|
||||
data[2] = cam->sensor->rsta | 0x12;
|
||||
data[1] = cam->sensor.i2c_slave_id;
|
||||
data[2] = cam->sensor.rsta | 0x12;
|
||||
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
|
||||
0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
|
||||
if (res < 0)
|
||||
@ -334,9 +342,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
|
||||
u8* data = cam->control_buffer;
|
||||
int err = 0, res;
|
||||
|
||||
if (!cam->sensor)
|
||||
return -1;
|
||||
|
||||
data[0] = data2;
|
||||
data[1] = data3;
|
||||
data[2] = data4;
|
||||
@ -350,8 +355,8 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
|
||||
err += res;
|
||||
|
||||
data[0] = address;
|
||||
data[1] = cam->sensor->i2c_slave_id;
|
||||
data[2] = cam->sensor->rsta | 0x02 | (n << 4);
|
||||
data[1] = cam->sensor.i2c_slave_id;
|
||||
data[2] = cam->sensor.rsta | 0x02 | (n << 4);
|
||||
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
|
||||
0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
|
||||
if (res < 0)
|
||||
@ -364,11 +369,11 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
|
||||
if (res < 0)
|
||||
err += res;
|
||||
|
||||
err += et61x251_i2c_wait(cam, cam->sensor);
|
||||
err += et61x251_i2c_wait(cam, &cam->sensor);
|
||||
|
||||
if (err)
|
||||
DBG(3, "I2C raw write failed for %s image sensor",
|
||||
cam->sensor->name);
|
||||
cam->sensor.name);
|
||||
|
||||
PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
|
||||
"data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
|
||||
@ -382,19 +387,13 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
|
||||
|
||||
int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
|
||||
{
|
||||
if (!cam->sensor)
|
||||
return -1;
|
||||
|
||||
return et61x251_i2c_try_read(cam, cam->sensor, address);
|
||||
return et61x251_i2c_try_read(cam, &cam->sensor, address);
|
||||
}
|
||||
|
||||
|
||||
int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
|
||||
{
|
||||
if (!cam->sensor)
|
||||
return -1;
|
||||
|
||||
return et61x251_i2c_try_write(cam, cam->sensor, address, value);
|
||||
return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -417,7 +416,7 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
|
||||
if ((*f))
|
||||
(*f)->state = F_QUEUED;
|
||||
DBG(3, "Stream interrupted");
|
||||
wake_up_interruptible(&cam->wait_stream);
|
||||
wake_up(&cam->wait_stream);
|
||||
}
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
@ -435,9 +434,9 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
|
||||
(*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
|
||||
frame);
|
||||
|
||||
imagesize = (cam->sensor->pix_format.width *
|
||||
cam->sensor->pix_format.height *
|
||||
cam->sensor->pix_format.priv) / 8;
|
||||
imagesize = (cam->sensor.pix_format.width *
|
||||
cam->sensor.pix_format.height *
|
||||
cam->sensor.pix_format.priv) / 8;
|
||||
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
unsigned int len, status;
|
||||
@ -476,7 +475,7 @@ start_of_frame:
|
||||
|
||||
if ((*f)->state == F_GRABBING) {
|
||||
if (sof && (*f)->buf.bytesused) {
|
||||
if (cam->sensor->pix_format.pixelformat ==
|
||||
if (cam->sensor.pix_format.pixelformat ==
|
||||
V4L2_PIX_FMT_ET61X251)
|
||||
goto end_of_frame;
|
||||
else {
|
||||
@ -521,7 +520,7 @@ end_of_frame:
|
||||
goto resubmit_urb;
|
||||
|
||||
if (sof &&
|
||||
cam->sensor->pix_format.pixelformat ==
|
||||
cam->sensor.pix_format.pixelformat ==
|
||||
V4L2_PIX_FMT_ET61X251)
|
||||
goto start_of_frame;
|
||||
}
|
||||
@ -650,21 +649,21 @@ static int et61x251_stop_transfer(struct et61x251_device* cam)
|
||||
|
||||
static int et61x251_stream_interrupt(struct et61x251_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
long timeout;
|
||||
|
||||
cam->stream = STREAM_INTERRUPT;
|
||||
err = wait_event_timeout(cam->wait_stream,
|
||||
(cam->stream == STREAM_OFF) ||
|
||||
(cam->state & DEV_DISCONNECTED),
|
||||
ET61X251_URB_TIMEOUT);
|
||||
timeout = wait_event_timeout(cam->wait_stream,
|
||||
(cam->stream == STREAM_OFF) ||
|
||||
(cam->state & DEV_DISCONNECTED),
|
||||
ET61X251_URB_TIMEOUT);
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
return -ENODEV;
|
||||
else if (err) {
|
||||
else if (cam->stream != STREAM_OFF) {
|
||||
cam->state |= DEV_MISCONFIGURED;
|
||||
DBG(1, "URB timeout reached. The camera is misconfigured. To "
|
||||
"use it, close and open /dev/video%d again.",
|
||||
cam->v4ldev->minor);
|
||||
return err;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -709,18 +708,18 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
|
||||
struct et61x251_device* cam;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
count = sprintf(buf, "%u\n", cam->sysfs.reg);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -733,18 +732,18 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
u8 index;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
index = et61x251_strtou8(buf, len, &count);
|
||||
if (index > 0x8e || !count) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -753,7 +752,7 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -765,17 +764,17 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
|
||||
ssize_t count;
|
||||
int val;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -783,7 +782,7 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -797,24 +796,24 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
|
||||
ssize_t count;
|
||||
int err;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
value = et61x251_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = et61x251_write_reg(cam, value, cam->sysfs.reg);
|
||||
if (err) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -822,7 +821,7 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
|
||||
cam->sysfs.reg, value);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -833,12 +832,12 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
|
||||
struct et61x251_device* cam;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -846,7 +845,7 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -859,18 +858,18 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
u8 index;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
index = et61x251_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -879,7 +878,7 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -891,22 +890,22 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
|
||||
ssize_t count;
|
||||
int val;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -914,7 +913,7 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -928,29 +927,29 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
|
||||
ssize_t count;
|
||||
int err;
|
||||
|
||||
if (down_interruptible(&et61x251_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&et61x251_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
value = et61x251_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
|
||||
if (err) {
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -958,7 +957,7 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
|
||||
cam->sysfs.i2c_reg, value);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -980,7 +979,7 @@ static void et61x251_create_sysfs(struct et61x251_device* cam)
|
||||
|
||||
video_device_create_file(v4ldev, &class_device_attr_reg);
|
||||
video_device_create_file(v4ldev, &class_device_attr_val);
|
||||
if (cam->sensor && cam->sensor->sysfs_ops) {
|
||||
if (cam->sensor.sysfs_ops) {
|
||||
video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
|
||||
video_device_create_file(v4ldev, &class_device_attr_i2c_val);
|
||||
}
|
||||
@ -1048,7 +1047,7 @@ static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
|
||||
static int
|
||||
et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
|
||||
s->active_pixel.left),
|
||||
fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
|
||||
@ -1076,7 +1075,7 @@ et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
|
||||
|
||||
static int et61x251_init(struct et61x251_device* cam)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
struct v4l2_queryctrl *qctrl;
|
||||
struct v4l2_rect* rect;
|
||||
@ -1143,7 +1142,7 @@ static int et61x251_init(struct et61x251_device* cam)
|
||||
}
|
||||
|
||||
if (!(cam->state & DEV_INITIALIZED)) {
|
||||
init_MUTEX(&cam->fileop_sem);
|
||||
mutex_init(&cam->fileop_mutex);
|
||||
spin_lock_init(&cam->queue_lock);
|
||||
init_waitqueue_head(&cam->wait_frame);
|
||||
init_waitqueue_head(&cam->wait_stream);
|
||||
@ -1161,13 +1160,15 @@ static int et61x251_init(struct et61x251_device* cam)
|
||||
|
||||
static void et61x251_release_resources(struct et61x251_device* cam)
|
||||
{
|
||||
down(&et61x251_sysfs_lock);
|
||||
mutex_lock(&et61x251_sysfs_lock);
|
||||
|
||||
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
|
||||
video_set_drvdata(cam->v4ldev, NULL);
|
||||
video_unregister_device(cam->v4ldev);
|
||||
|
||||
up(&et61x251_sysfs_lock);
|
||||
usb_put_dev(cam->usbdev);
|
||||
|
||||
mutex_unlock(&et61x251_sysfs_lock);
|
||||
|
||||
kfree(cam->control_buffer);
|
||||
}
|
||||
@ -1188,7 +1189,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
|
||||
|
||||
cam = video_get_drvdata(video_devdata(filp));
|
||||
|
||||
if (down_interruptible(&cam->dev_sem)) {
|
||||
if (mutex_lock_interruptible(&cam->dev_mutex)) {
|
||||
up_read(&et61x251_disconnect);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
@ -1200,7 +1201,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
|
||||
err = -EWOULDBLOCK;
|
||||
goto out;
|
||||
}
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
err = wait_event_interruptible_exclusive(cam->open,
|
||||
cam->state & DEV_DISCONNECTED
|
||||
|| !cam->users);
|
||||
@ -1212,7 +1213,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
|
||||
up_read(&et61x251_disconnect);
|
||||
return -ENODEV;
|
||||
}
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -1240,7 +1241,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
|
||||
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
|
||||
|
||||
out:
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
up_read(&et61x251_disconnect);
|
||||
return err;
|
||||
}
|
||||
@ -1250,7 +1251,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
|
||||
{
|
||||
struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
|
||||
down(&cam->dev_sem); /* prevent disconnect() to be called */
|
||||
mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
|
||||
|
||||
et61x251_stop_transfer(cam);
|
||||
|
||||
@ -1258,7 +1259,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
et61x251_release_resources(cam);
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
kfree(cam);
|
||||
return 0;
|
||||
}
|
||||
@ -1268,7 +1269,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
|
||||
|
||||
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1281,28 +1282,29 @@ et61x251_read(struct file* filp, char __user * buf,
|
||||
struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
struct et61x251_frame_t* f, * i;
|
||||
unsigned long lock_flags;
|
||||
long timeout;
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->io == IO_MMAP) {
|
||||
DBG(3, "Close and open the device again to choose the read "
|
||||
"method");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1310,7 +1312,7 @@ et61x251_read(struct file* filp, char __user * buf,
|
||||
if (!et61x251_request_buffers(cam, cam->nreadbuffers,
|
||||
IO_READ)) {
|
||||
DBG(1, "read() failed, not enough memory");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cam->io = IO_READ;
|
||||
@ -1324,30 +1326,32 @@ et61x251_read(struct file* filp, char __user * buf,
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(&cam->outqueue)) {
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
err = wait_event_interruptible
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED) );
|
||||
if (err) {
|
||||
up(&cam->fileop_sem);
|
||||
return err;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return timeout;
|
||||
}
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
up(&cam->fileop_sem);
|
||||
if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -1375,7 +1379,7 @@ exit:
|
||||
PDBGG("Frame #%lu, bytes read: %zu",
|
||||
(unsigned long)f->buf.index, count);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return err ? err : count;
|
||||
}
|
||||
@ -1388,7 +1392,7 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
|
||||
unsigned long lock_flags;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return POLLERR;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
@ -1426,12 +1430,12 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
|
||||
if (!list_empty(&cam->outqueue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return mask;
|
||||
|
||||
error:
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return POLLERR;
|
||||
}
|
||||
|
||||
@ -1465,25 +1469,25 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
void *pos;
|
||||
u32 i;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
|
||||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1492,7 +1496,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
break;
|
||||
}
|
||||
if (i == cam->nbuffers) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1502,7 +1506,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
pos = cam->frame[i].bufmem;
|
||||
while (size > 0) { /* size is page-aligned */
|
||||
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
start += PAGE_SIZE;
|
||||
@ -1515,7 +1519,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
|
||||
et61x251_vm_open(vma);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1557,6 +1561,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
strcpy(i.name, "Camera");
|
||||
i.type = V4L2_INPUT_TYPE_CAMERA;
|
||||
|
||||
if (copy_to_user(arg, &i, sizeof(i)))
|
||||
return -EFAULT;
|
||||
@ -1566,7 +1571,19 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
|
||||
|
||||
|
||||
static int
|
||||
et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
|
||||
et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if (copy_to_user(arg, &index, sizeof(index)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
int index;
|
||||
|
||||
@ -1583,7 +1600,7 @@ et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
|
||||
static int
|
||||
et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_queryctrl qc;
|
||||
u8 i;
|
||||
|
||||
@ -1605,7 +1622,7 @@ et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
static int
|
||||
et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
int err = 0;
|
||||
u8 i;
|
||||
@ -1637,7 +1654,7 @@ exit:
|
||||
static int
|
||||
et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
u8 i;
|
||||
int err = 0;
|
||||
@ -1650,6 +1667,8 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
|
||||
if (ctrl.id == s->qctrl[i].id) {
|
||||
if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
|
||||
return -EINVAL;
|
||||
if (ctrl.value < s->qctrl[i].minimum ||
|
||||
ctrl.value > s->qctrl[i].maximum)
|
||||
return -ERANGE;
|
||||
@ -1669,7 +1688,7 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
|
||||
static int
|
||||
et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
|
||||
struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
|
||||
|
||||
cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
cc->pixelaspect.numerator = 1;
|
||||
@ -1685,7 +1704,7 @@ et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
|
||||
static int
|
||||
et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_crop crop = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
};
|
||||
@ -1702,7 +1721,7 @@ et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
|
||||
static int
|
||||
et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_crop crop;
|
||||
struct v4l2_rect* rect;
|
||||
struct v4l2_rect* bounds = &(s->cropcap.bounds);
|
||||
@ -1843,7 +1862,7 @@ static int
|
||||
et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct v4l2_format format;
|
||||
struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
|
||||
struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
|
||||
|
||||
if (copy_from_user(&format, arg, sizeof(format)))
|
||||
return -EFAULT;
|
||||
@ -1868,7 +1887,7 @@ static int
|
||||
et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
|
||||
void __user * arg)
|
||||
{
|
||||
struct et61x251_sensor* s = cam->sensor;
|
||||
struct et61x251_sensor* s = &cam->sensor;
|
||||
struct v4l2_format format;
|
||||
struct v4l2_pix_format* pix;
|
||||
struct v4l2_pix_format* pfmt = &(s->pix_format);
|
||||
@ -2155,7 +2174,7 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
|
||||
struct v4l2_buffer b;
|
||||
struct et61x251_frame_t *f;
|
||||
unsigned long lock_flags;
|
||||
int err = 0;
|
||||
long timeout;
|
||||
|
||||
if (copy_from_user(&b, arg, sizeof(b)))
|
||||
return -EFAULT;
|
||||
@ -2168,16 +2187,18 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
|
||||
return -EINVAL;
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
err = wait_event_interruptible
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED) );
|
||||
if (err)
|
||||
return err;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0)
|
||||
return timeout;
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
return -ENODEV;
|
||||
if (cam->state & DEV_MISCONFIGURED)
|
||||
if (!timeout || (cam->state & DEV_MISCONFIGURED))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -2309,8 +2330,10 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
|
||||
return et61x251_vidioc_enuminput(cam, arg);
|
||||
|
||||
case VIDIOC_G_INPUT:
|
||||
return et61x251_vidioc_g_input(cam, arg);
|
||||
|
||||
case VIDIOC_S_INPUT:
|
||||
return et61x251_vidioc_gs_input(cam, arg);
|
||||
return et61x251_vidioc_s_input(cam, arg);
|
||||
|
||||
case VIDIOC_QUERYCTRL:
|
||||
return et61x251_vidioc_query_ctrl(cam, arg);
|
||||
@ -2393,19 +2416,19 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
|
||||
struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -2413,7 +2436,7 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
|
||||
|
||||
err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -2459,7 +2482,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_MUTEX(&cam->dev_sem);
|
||||
mutex_init(&cam->dev_mutex);
|
||||
|
||||
DBG(2, "ET61X[12]51 PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
|
||||
@ -2470,8 +2493,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err && cam->sensor)
|
||||
DBG(2, "%s image sensor detected", cam->sensor->name);
|
||||
if (!err)
|
||||
DBG(2, "%s image sensor detected", cam->sensor.name);
|
||||
else {
|
||||
DBG(1, "No supported image sensor detected");
|
||||
err = -ENODEV;
|
||||
@ -2492,7 +2515,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
cam->v4ldev->release = video_device_release;
|
||||
video_set_drvdata(cam->v4ldev, cam);
|
||||
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
|
||||
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
|
||||
video_nr[dev_nr]);
|
||||
@ -2502,13 +2525,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
DBG(1, "Free /dev/videoX node not found");
|
||||
video_nr[dev_nr] = -1;
|
||||
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
|
||||
|
||||
cam->module_param.force_munmap = force_munmap[dev_nr];
|
||||
cam->module_param.frame_timeout = frame_timeout[dev_nr];
|
||||
|
||||
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
|
||||
|
||||
@ -2519,7 +2543,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
|
||||
usb_set_intfdata(intf, cam);
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2543,7 +2567,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf)
|
||||
|
||||
down_write(&et61x251_disconnect);
|
||||
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
|
||||
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
|
||||
|
||||
@ -2557,13 +2581,14 @@ static void et61x251_usb_disconnect(struct usb_interface* intf)
|
||||
et61x251_stop_transfer(cam);
|
||||
cam->state |= DEV_DISCONNECTED;
|
||||
wake_up_interruptible(&cam->wait_frame);
|
||||
wake_up_interruptible(&cam->wait_stream);
|
||||
wake_up(&cam->wait_stream);
|
||||
usb_get_dev(cam->usbdev);
|
||||
} else {
|
||||
cam->state |= DEV_DISCONNECTED;
|
||||
et61x251_release_resources(cam);
|
||||
}
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
if (!cam->users)
|
||||
kfree(cam);
|
||||
|
@ -42,6 +42,9 @@ static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \
|
||||
NULL, \
|
||||
};
|
||||
|
||||
extern struct et61x251_device*
|
||||
et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
|
||||
|
||||
extern void
|
||||
et61x251_attach_sensor(struct et61x251_device* cam,
|
||||
struct et61x251_sensor* sensor);
|
||||
@ -105,8 +108,6 @@ struct et61x251_sensor {
|
||||
int (*set_pix_format)(struct et61x251_device* cam,
|
||||
const struct v4l2_pix_format* pix);
|
||||
|
||||
const struct usb_device* usbdev;
|
||||
|
||||
/* Private */
|
||||
struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
|
||||
struct v4l2_rect _rect;
|
||||
|
@ -126,12 +126,16 @@ static struct et61x251_sensor tas5130d1b = {
|
||||
|
||||
int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
|
||||
{
|
||||
/* This sensor has no identifiers, so let's attach it anyway */
|
||||
et61x251_attach_sensor(cam, &tas5130d1b);
|
||||
const struct usb_device_id tas5130d1b_id_table[] = {
|
||||
{ USB_DEVICE(0x102c, 0x6251), },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Sensor detection is based on USB pid/vid */
|
||||
if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
|
||||
if (!et61x251_match_id(cam, tas5130d1b_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
et61x251_attach_sensor(cam, &tas5130d1b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -365,14 +365,14 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
|
||||
|
||||
PDEBUG(5, "0x%02X:0x%02X", reg, value);
|
||||
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
ov->cbuf[0] = value;
|
||||
rc = usb_control_msg(ov->dev,
|
||||
usb_sndctrlpipe(ov->dev, 0),
|
||||
(ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0, (__u16)reg, &ov->cbuf[0], 1, 1000);
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
|
||||
if (rc < 0)
|
||||
err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
|
||||
@ -387,7 +387,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
rc = usb_control_msg(ov->dev,
|
||||
usb_rcvctrlpipe(ov->dev, 0),
|
||||
(ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
|
||||
@ -401,7 +401,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
|
||||
PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
|
||||
}
|
||||
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -444,7 +444,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
|
||||
|
||||
PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
|
||||
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
|
||||
*((__le32 *)ov->cbuf) = __cpu_to_le32(val);
|
||||
|
||||
@ -453,7 +453,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
|
||||
1 /* REG_IO */,
|
||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0, (__u16)reg, ov->cbuf, n, 1000);
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
|
||||
if (rc < 0)
|
||||
err("reg write multiple: error %d: %s", rc,
|
||||
@ -768,14 +768,14 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
|
||||
if (ov->bclass == BCL_OV518)
|
||||
rc = ov518_i2c_read_internal(ov, reg);
|
||||
else
|
||||
rc = ov511_i2c_read_internal(ov, reg);
|
||||
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -785,14 +785,14 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
|
||||
if (ov->bclass == BCL_OV518)
|
||||
rc = ov518_i2c_write_internal(ov, reg, value);
|
||||
else
|
||||
rc = ov511_i2c_write_internal(ov, reg, value);
|
||||
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -842,9 +842,9 @@ i2c_w_mask(struct usb_ov511 *ov,
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -880,7 +880,7 @@ i2c_w_slave(struct usb_ov511 *ov,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
|
||||
/* Set new slave IDs */
|
||||
rc = i2c_set_slave_internal(ov, slave);
|
||||
@ -894,7 +894,7 @@ out:
|
||||
if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
|
||||
err("Couldn't restore primary I2C slave");
|
||||
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -906,7 +906,7 @@ i2c_r_slave(struct usb_ov511 *ov,
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
|
||||
/* Set new slave IDs */
|
||||
rc = i2c_set_slave_internal(ov, slave);
|
||||
@ -923,7 +923,7 @@ out:
|
||||
if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
|
||||
err("Couldn't restore primary I2C slave");
|
||||
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -933,7 +933,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
down(&ov->i2c_lock);
|
||||
mutex_lock(&ov->i2c_lock);
|
||||
|
||||
rc = i2c_set_slave_internal(ov, sid);
|
||||
if (rc < 0)
|
||||
@ -942,7 +942,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
|
||||
// FIXME: Is this actually necessary?
|
||||
rc = ov51x_reset(ov, OV511_RESET_NOREGS);
|
||||
out:
|
||||
up(&ov->i2c_lock);
|
||||
mutex_unlock(&ov->i2c_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3832,7 +3832,7 @@ ov51x_alloc(struct usb_ov511 *ov)
|
||||
const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
|
||||
|
||||
PDEBUG(4, "entered");
|
||||
down(&ov->buf_lock);
|
||||
mutex_lock(&ov->buf_lock);
|
||||
|
||||
if (ov->buf_state == BUF_ALLOCATED)
|
||||
goto out;
|
||||
@ -3879,12 +3879,12 @@ ov51x_alloc(struct usb_ov511 *ov)
|
||||
|
||||
ov->buf_state = BUF_ALLOCATED;
|
||||
out:
|
||||
up(&ov->buf_lock);
|
||||
mutex_unlock(&ov->buf_lock);
|
||||
PDEBUG(4, "leaving");
|
||||
return 0;
|
||||
error:
|
||||
ov51x_do_dealloc(ov);
|
||||
up(&ov->buf_lock);
|
||||
mutex_unlock(&ov->buf_lock);
|
||||
PDEBUG(4, "errored");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -3893,9 +3893,9 @@ static void
|
||||
ov51x_dealloc(struct usb_ov511 *ov)
|
||||
{
|
||||
PDEBUG(4, "entered");
|
||||
down(&ov->buf_lock);
|
||||
mutex_lock(&ov->buf_lock);
|
||||
ov51x_do_dealloc(ov);
|
||||
up(&ov->buf_lock);
|
||||
mutex_unlock(&ov->buf_lock);
|
||||
PDEBUG(4, "leaving");
|
||||
}
|
||||
|
||||
@ -3914,7 +3914,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
|
||||
|
||||
PDEBUG(4, "opening");
|
||||
|
||||
down(&ov->lock);
|
||||
mutex_lock(&ov->lock);
|
||||
|
||||
err = -EBUSY;
|
||||
if (ov->user)
|
||||
@ -3958,7 +3958,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
|
||||
ov51x_led_control(ov, 1);
|
||||
|
||||
out:
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3970,7 +3970,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
|
||||
|
||||
PDEBUG(4, "ov511_close");
|
||||
|
||||
down(&ov->lock);
|
||||
mutex_lock(&ov->lock);
|
||||
|
||||
ov->user--;
|
||||
ov51x_stop_isoc(ov);
|
||||
@ -3981,15 +3981,15 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
|
||||
if (ov->dev)
|
||||
ov51x_dealloc(ov);
|
||||
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
|
||||
/* Device unplugged while open. Only a minimum of unregistration is done
|
||||
* here; the disconnect callback already did the rest. */
|
||||
if (!ov->dev) {
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
kfree(ov->cbuf);
|
||||
ov->cbuf = NULL;
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
|
||||
ov51x_dealloc(ov);
|
||||
kfree(ov);
|
||||
@ -4449,12 +4449,12 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
|
||||
struct usb_ov511 *ov = video_get_drvdata(vdev);
|
||||
int rc;
|
||||
|
||||
if (down_interruptible(&ov->lock))
|
||||
if (mutex_lock_interruptible(&ov->lock))
|
||||
return -EINTR;
|
||||
|
||||
rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
|
||||
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4468,7 +4468,7 @@ ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
|
||||
int i, rc = 0, frmx = -1;
|
||||
struct ov511_frame *frame;
|
||||
|
||||
if (down_interruptible(&ov->lock))
|
||||
if (mutex_lock_interruptible(&ov->lock))
|
||||
return -EINTR;
|
||||
|
||||
PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
|
||||
@ -4604,11 +4604,11 @@ restart:
|
||||
|
||||
PDEBUG(4, "read finished, returning %ld (sweet)", count);
|
||||
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return count;
|
||||
|
||||
error:
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4631,14 +4631,14 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
+ PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
|
||||
return -EINVAL;
|
||||
|
||||
if (down_interruptible(&ov->lock))
|
||||
if (mutex_lock_interruptible(&ov->lock))
|
||||
return -EINTR;
|
||||
|
||||
pos = (unsigned long)ov->fbuf;
|
||||
while (size > 0) {
|
||||
page = vmalloc_to_pfn((void *)pos);
|
||||
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
start += PAGE_SIZE;
|
||||
@ -4649,7 +4649,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
size = 0;
|
||||
}
|
||||
|
||||
up(&ov->lock);
|
||||
mutex_unlock(&ov->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5639,7 +5639,7 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
|
||||
static ssize_t show_exposure(struct class_device *cd, char *buf)
|
||||
{
|
||||
struct usb_ov511 *ov = cd_to_ov(cd);
|
||||
unsigned char exp;
|
||||
unsigned char exp = 0;
|
||||
|
||||
if (!ov->dev)
|
||||
return -ENODEV;
|
||||
@ -5686,13 +5686,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if (idesc->bInterfaceSubClass != 0x00)
|
||||
return -ENODEV;
|
||||
|
||||
if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
|
||||
if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
|
||||
err("couldn't kmalloc ov struct");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
memset(ov, 0, sizeof(*ov));
|
||||
|
||||
ov->dev = dev;
|
||||
ov->iface = idesc->bInterfaceNumber;
|
||||
ov->led_policy = led;
|
||||
@ -5738,11 +5736,10 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
|
||||
init_waitqueue_head(&ov->wq);
|
||||
|
||||
init_MUTEX(&ov->lock); /* to 1 == available */
|
||||
init_MUTEX(&ov->buf_lock);
|
||||
init_MUTEX(&ov->param_lock);
|
||||
init_MUTEX(&ov->i2c_lock);
|
||||
init_MUTEX(&ov->cbuf_lock);
|
||||
mutex_init(&ov->lock); /* to 1 == available */
|
||||
mutex_init(&ov->buf_lock);
|
||||
mutex_init(&ov->i2c_lock);
|
||||
mutex_init(&ov->cbuf_lock);
|
||||
|
||||
ov->buf_state = BUF_NOT_ALLOCATED;
|
||||
|
||||
@ -5833,10 +5830,10 @@ error:
|
||||
}
|
||||
|
||||
if (ov->cbuf) {
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
kfree(ov->cbuf);
|
||||
ov->cbuf = NULL;
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
}
|
||||
|
||||
kfree(ov);
|
||||
@ -5881,10 +5878,10 @@ ov51x_disconnect(struct usb_interface *intf)
|
||||
|
||||
/* Free the memory */
|
||||
if (ov && !ov->user) {
|
||||
down(&ov->cbuf_lock);
|
||||
mutex_lock(&ov->cbuf_lock);
|
||||
kfree(ov->cbuf);
|
||||
ov->cbuf = NULL;
|
||||
up(&ov->cbuf_lock);
|
||||
mutex_unlock(&ov->cbuf_lock);
|
||||
|
||||
ov51x_dealloc(ov);
|
||||
kfree(ov);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define OV511_DEBUG /* Turn on debug messages */
|
||||
|
||||
@ -435,7 +436,7 @@ struct usb_ov511 {
|
||||
|
||||
int led_policy; /* LED: off|on|auto; OV511+ only */
|
||||
|
||||
struct semaphore lock; /* Serializes user-accessible operations */
|
||||
struct mutex lock; /* Serializes user-accessible operations */
|
||||
int user; /* user count for exclusive use */
|
||||
|
||||
int streaming; /* Are we streaming Isochronous? */
|
||||
@ -473,11 +474,9 @@ struct usb_ov511 {
|
||||
int packet_size; /* Frame size per isoc desc */
|
||||
int packet_numbering; /* Is ISO frame numbering enabled? */
|
||||
|
||||
struct semaphore param_lock; /* params lock for this camera */
|
||||
|
||||
/* Framebuffer/sbuf management */
|
||||
int buf_state;
|
||||
struct semaphore buf_lock;
|
||||
struct mutex buf_lock;
|
||||
|
||||
struct ov51x_decomp_ops *decomp_ops;
|
||||
|
||||
@ -494,12 +493,12 @@ struct usb_ov511 {
|
||||
int pal; /* Device is designed for PAL resolution */
|
||||
|
||||
/* I2C interface */
|
||||
struct semaphore i2c_lock; /* Protect I2C controller regs */
|
||||
struct mutex i2c_lock; /* Protect I2C controller regs */
|
||||
unsigned char primary_i2c_slave; /* I2C write id of sensor */
|
||||
|
||||
/* Control transaction stuff */
|
||||
unsigned char *cbuf; /* Buffer for payload */
|
||||
struct semaphore cbuf_lock;
|
||||
struct mutex cbuf_lock;
|
||||
};
|
||||
|
||||
/* Used to represent a list of values and their respective symbolic names */
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#endif
|
||||
#include <asm/errno.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "pwc.h"
|
||||
#include "pwc-ioctl.h"
|
||||
|
@ -62,7 +62,6 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "pwc.h"
|
||||
@ -827,13 +826,10 @@ static int pwc_isoc_init(struct pwc_device *pdev)
|
||||
/* Get the current alternate interface, adjust packet size */
|
||||
if (!udev->actconfig)
|
||||
return -EFAULT;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
|
||||
idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
|
||||
#else
|
||||
|
||||
intf = usb_ifnum_to_if(udev, 0);
|
||||
if (intf)
|
||||
idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
|
||||
#endif
|
||||
|
||||
if (!idesc)
|
||||
return -EFAULT;
|
||||
@ -1871,12 +1867,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
|
||||
Info("Warning: more than 1 configuration available.\n");
|
||||
|
||||
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
|
||||
pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL);
|
||||
pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
|
||||
if (pdev == NULL) {
|
||||
Err("Oops, could not allocate memory for pwc_device.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(pdev, 0, sizeof(struct pwc_device));
|
||||
pdev->type = type_id;
|
||||
pdev->vsize = default_size;
|
||||
pdev->vframes = default_fps;
|
||||
|
@ -1157,21 +1157,21 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
unsigned long size = vma->vm_end-vma->vm_start;
|
||||
unsigned long page, pos;
|
||||
|
||||
down(&se401->lock);
|
||||
mutex_lock(&se401->lock);
|
||||
|
||||
if (se401->dev == NULL) {
|
||||
up(&se401->lock);
|
||||
mutex_unlock(&se401->lock);
|
||||
return -EIO;
|
||||
}
|
||||
if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
|
||||
up(&se401->lock);
|
||||
mutex_unlock(&se401->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
pos = (unsigned long)se401->fbuf;
|
||||
while (size > 0) {
|
||||
page = vmalloc_to_pfn((void *)pos);
|
||||
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
|
||||
up(&se401->lock);
|
||||
mutex_unlock(&se401->lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
start += PAGE_SIZE;
|
||||
@ -1181,7 +1181,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
up(&se401->lock);
|
||||
mutex_unlock(&se401->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1345,13 +1345,11 @@ static int se401_probe(struct usb_interface *intf,
|
||||
/* We found one */
|
||||
info("SE401 camera found: %s", camera_name);
|
||||
|
||||
if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
|
||||
if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
|
||||
err("couldn't kmalloc se401 struct");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(se401, 0, sizeof(*se401));
|
||||
|
||||
se401->dev = dev;
|
||||
se401->iface = interface->bInterfaceNumber;
|
||||
se401->camera_name = camera_name;
|
||||
@ -1366,7 +1364,7 @@ static int se401_probe(struct usb_interface *intf,
|
||||
memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
|
||||
memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
|
||||
init_waitqueue_head(&se401->wq);
|
||||
init_MUTEX(&se401->lock);
|
||||
mutex_init(&se401->lock);
|
||||
wmb();
|
||||
|
||||
if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define se401_DEBUG /* Turn on debug messages */
|
||||
|
||||
@ -189,7 +190,7 @@ struct usb_se401 {
|
||||
int maxframesize;
|
||||
int cframesize; /* current framesize */
|
||||
|
||||
struct semaphore lock;
|
||||
struct mutex lock;
|
||||
int user; /* user count for exclusive use */
|
||||
int removed; /* device disconnected */
|
||||
|
||||
|
@ -33,7 +33,9 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include "sn9c102_sensor.h"
|
||||
|
||||
@ -50,6 +52,7 @@
|
||||
#define SN9C102_ALTERNATE_SETTING 8
|
||||
#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
|
||||
#define SN9C102_CTRL_TIMEOUT 300
|
||||
#define SN9C102_FRAME_TIMEOUT 2
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -107,16 +110,17 @@ struct sn9c102_sysfs_attr {
|
||||
|
||||
struct sn9c102_module_param {
|
||||
u8 force_munmap;
|
||||
u16 frame_timeout;
|
||||
};
|
||||
|
||||
static DECLARE_MUTEX(sn9c102_sysfs_lock);
|
||||
static DEFINE_MUTEX(sn9c102_sysfs_lock);
|
||||
static DECLARE_RWSEM(sn9c102_disconnect);
|
||||
|
||||
struct sn9c102_device {
|
||||
struct video_device* v4ldev;
|
||||
|
||||
enum sn9c102_bridge bridge;
|
||||
struct sn9c102_sensor* sensor;
|
||||
struct sn9c102_sensor sensor;
|
||||
|
||||
struct usb_device* usbdev;
|
||||
struct urb* urb[SN9C102_URBS];
|
||||
@ -141,19 +145,28 @@ struct sn9c102_device {
|
||||
enum sn9c102_dev_state state;
|
||||
u8 users;
|
||||
|
||||
struct semaphore dev_sem, fileop_sem;
|
||||
struct mutex dev_mutex, fileop_mutex;
|
||||
spinlock_t queue_lock;
|
||||
wait_queue_head_t open, wait_frame, wait_stream;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct sn9c102_device*
|
||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
|
||||
{
|
||||
if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
|
||||
return cam;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sn9c102_attach_sensor(struct sn9c102_device* cam,
|
||||
struct sn9c102_sensor* sensor)
|
||||
{
|
||||
cam->sensor = sensor;
|
||||
cam->sensor->usbdev = cam->usbdev;
|
||||
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -196,7 +209,8 @@ do { \
|
||||
|
||||
#undef PDBG
|
||||
#define PDBG(fmt, args...) \
|
||||
dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
|
||||
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
|
||||
__FUNCTION__, __LINE__ , ## args)
|
||||
|
||||
#undef PDBGG
|
||||
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
|
||||
|
@ -25,11 +25,9 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/poll.h>
|
||||
@ -49,8 +47,8 @@
|
||||
#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
|
||||
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
|
||||
#define SN9C102_MODULE_LICENSE "GPL"
|
||||
#define SN9C102_MODULE_VERSION "1:1.26"
|
||||
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 26)
|
||||
#define SN9C102_MODULE_VERSION "1:1.27"
|
||||
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -89,6 +87,15 @@ MODULE_PARM_DESC(force_munmap,
|
||||
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
|
||||
"\n");
|
||||
|
||||
static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
|
||||
SN9C102_FRAME_TIMEOUT};
|
||||
module_param_array(frame_timeout, uint, NULL, 0644);
|
||||
MODULE_PARM_DESC(frame_timeout,
|
||||
"\n<n[,...]> Timeout for a video frame in seconds."
|
||||
"\nThis parameter is specific for each detected camera."
|
||||
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
|
||||
"\n");
|
||||
|
||||
#ifdef SN9C102_DEBUG
|
||||
static unsigned short debug = SN9C102_DEBUG_LEVEL;
|
||||
module_param(debug, ushort, 0644);
|
||||
@ -128,8 +135,8 @@ static u32
|
||||
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
|
||||
enum sn9c102_io_method io)
|
||||
{
|
||||
struct v4l2_pix_format* p = &(cam->sensor->pix_format);
|
||||
struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
|
||||
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
|
||||
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
|
||||
const size_t imagesize = cam->module_param.force_munmap ||
|
||||
io == IO_READ ?
|
||||
(p->width * p->height * p->priv) / 8 :
|
||||
@ -449,19 +456,13 @@ sn9c102_i2c_try_write(struct sn9c102_device* cam,
|
||||
|
||||
int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
|
||||
{
|
||||
if (!cam->sensor)
|
||||
return -1;
|
||||
|
||||
return sn9c102_i2c_try_read(cam, cam->sensor, address);
|
||||
return sn9c102_i2c_try_read(cam, &cam->sensor, address);
|
||||
}
|
||||
|
||||
|
||||
int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
|
||||
{
|
||||
if (!cam->sensor)
|
||||
return -1;
|
||||
|
||||
return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
|
||||
return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -505,7 +506,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
|
||||
size_t eoflen = sizeof(sn9c102_eof_header_t), i;
|
||||
unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
|
||||
|
||||
if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
return NULL; /* EOF header does not exist in compressed data */
|
||||
|
||||
for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
|
||||
@ -535,7 +536,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
|
||||
if ((*f))
|
||||
(*f)->state = F_QUEUED;
|
||||
DBG(3, "Stream interrupted");
|
||||
wake_up_interruptible(&cam->wait_stream);
|
||||
wake_up(&cam->wait_stream);
|
||||
}
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
@ -553,9 +554,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
|
||||
(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
|
||||
frame);
|
||||
|
||||
imagesize = (cam->sensor->pix_format.width *
|
||||
cam->sensor->pix_format.height *
|
||||
cam->sensor->pix_format.priv) / 8;
|
||||
imagesize = (cam->sensor.pix_format.width *
|
||||
cam->sensor.pix_format.height *
|
||||
cam->sensor.pix_format.priv) / 8;
|
||||
|
||||
soflen = (cam->bridge) == BRIDGE_SN9C103 ?
|
||||
sizeof(sn9c103_sof_header_t) :
|
||||
@ -579,7 +580,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
|
||||
|
||||
redo:
|
||||
sof = sn9c102_find_sof_header(cam, pos, len);
|
||||
if (!sof) {
|
||||
if (likely(!sof)) {
|
||||
eof = sn9c102_find_eof_header(cam, pos, len);
|
||||
if ((*f)->state == F_GRABBING) {
|
||||
end_of_frame:
|
||||
@ -589,8 +590,9 @@ end_of_frame:
|
||||
img = (eof > pos) ? eof - pos - 1 : 0;
|
||||
|
||||
if ((*f)->buf.bytesused+img > imagesize) {
|
||||
u32 b = (*f)->buf.bytesused + img -
|
||||
imagesize;
|
||||
u32 b;
|
||||
b = (*f)->buf.bytesused + img -
|
||||
imagesize;
|
||||
img = imagesize - (*f)->buf.bytesused;
|
||||
DBG(3, "Expected EOF not found: "
|
||||
"video frame cut");
|
||||
@ -608,9 +610,10 @@ end_of_frame:
|
||||
(*f)->buf.bytesused += img;
|
||||
|
||||
if ((*f)->buf.bytesused == imagesize ||
|
||||
(cam->sensor->pix_format.pixelformat ==
|
||||
(cam->sensor.pix_format.pixelformat ==
|
||||
V4L2_PIX_FMT_SN9C10X && eof)) {
|
||||
u32 b = (*f)->buf.bytesused;
|
||||
u32 b;
|
||||
b = (*f)->buf.bytesused;
|
||||
(*f)->state = F_DONE;
|
||||
(*f)->buf.sequence= ++cam->frame_count;
|
||||
spin_lock(&cam->queue_lock);
|
||||
@ -667,7 +670,7 @@ start_of_frame:
|
||||
if (eof && eof < sof)
|
||||
goto end_of_frame; /* (1) */
|
||||
else {
|
||||
if (cam->sensor->pix_format.pixelformat ==
|
||||
if (cam->sensor.pix_format.pixelformat ==
|
||||
V4L2_PIX_FMT_SN9C10X) {
|
||||
eof = sof - soflen;
|
||||
goto end_of_frame;
|
||||
@ -808,20 +811,21 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
|
||||
|
||||
static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
long timeout;
|
||||
|
||||
cam->stream = STREAM_INTERRUPT;
|
||||
err = wait_event_timeout(cam->wait_stream,
|
||||
(cam->stream == STREAM_OFF) ||
|
||||
(cam->state & DEV_DISCONNECTED),
|
||||
SN9C102_URB_TIMEOUT);
|
||||
timeout = wait_event_timeout(cam->wait_stream,
|
||||
(cam->stream == STREAM_OFF) ||
|
||||
(cam->state & DEV_DISCONNECTED),
|
||||
SN9C102_URB_TIMEOUT);
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
return -ENODEV;
|
||||
else if (err) {
|
||||
else if (cam->stream != STREAM_OFF) {
|
||||
cam->state |= DEV_MISCONFIGURED;
|
||||
DBG(1, "The camera is misconfigured. To use it, close and "
|
||||
"open /dev/video%d again.", cam->v4ldev->minor);
|
||||
return err;
|
||||
DBG(1, "URB timeout reached. The camera is misconfigured. "
|
||||
"To use it, close and open /dev/video%d again.",
|
||||
cam->v4ldev->minor);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -866,18 +870,18 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
|
||||
struct sn9c102_device* cam;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
count = sprintf(buf, "%u\n", cam->sysfs.reg);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -890,18 +894,18 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
u8 index;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
index = sn9c102_strtou8(buf, len, &count);
|
||||
if (index > 0x1f || !count) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -910,7 +914,7 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -922,17 +926,17 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
|
||||
ssize_t count;
|
||||
int val;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -940,7 +944,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -954,24 +958,24 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
|
||||
ssize_t count;
|
||||
int err;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
value = sn9c102_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
|
||||
if (err) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -979,7 +983,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
|
||||
cam->sysfs.reg, value);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -990,12 +994,12 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
|
||||
struct sn9c102_device* cam;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1003,7 +1007,7 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1016,18 +1020,18 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
u8 index;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
index = sn9c102_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1036,7 +1040,7 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
|
||||
DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1048,22 +1052,22 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
|
||||
ssize_t count;
|
||||
int val;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1071,7 +1075,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1085,29 +1089,29 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
|
||||
ssize_t count;
|
||||
int err;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
value = sn9c102_strtou8(buf, len, &count);
|
||||
if (!count) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
|
||||
if (err) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1115,7 +1119,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
|
||||
cam->sysfs.i2c_reg, value);
|
||||
DBG(3, "Written bytes: %zd", count);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1130,18 +1134,18 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
|
||||
u8 value;
|
||||
ssize_t count;
|
||||
|
||||
if (down_interruptible(&sn9c102_sysfs_lock))
|
||||
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cam = video_get_drvdata(to_video_device(cd));
|
||||
if (!cam) {
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bridge = cam->bridge;
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
value = sn9c102_strtou8(buf, len, &count);
|
||||
if (!count)
|
||||
@ -1249,7 +1253,7 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
|
||||
video_device_create_file(v4ldev, &class_device_attr_blue);
|
||||
video_device_create_file(v4ldev, &class_device_attr_red);
|
||||
}
|
||||
if (cam->sensor && cam->sensor->sysfs_ops) {
|
||||
if (cam->sensor.sysfs_ops) {
|
||||
video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
|
||||
video_device_create_file(v4ldev, &class_device_attr_i2c_val);
|
||||
}
|
||||
@ -1312,7 +1316,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
|
||||
|
||||
static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top),
|
||||
h_size = (u8)(rect->width / 16),
|
||||
@ -1335,7 +1339,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
|
||||
|
||||
static int sn9c102_init(struct sn9c102_device* cam)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
struct v4l2_queryctrl *qctrl;
|
||||
struct v4l2_rect* rect;
|
||||
@ -1404,7 +1408,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
|
||||
}
|
||||
|
||||
if (!(cam->state & DEV_INITIALIZED)) {
|
||||
init_MUTEX(&cam->fileop_sem);
|
||||
mutex_init(&cam->fileop_mutex);
|
||||
spin_lock_init(&cam->queue_lock);
|
||||
init_waitqueue_head(&cam->wait_frame);
|
||||
init_waitqueue_head(&cam->wait_stream);
|
||||
@ -1422,13 +1426,15 @@ static int sn9c102_init(struct sn9c102_device* cam)
|
||||
|
||||
static void sn9c102_release_resources(struct sn9c102_device* cam)
|
||||
{
|
||||
down(&sn9c102_sysfs_lock);
|
||||
mutex_lock(&sn9c102_sysfs_lock);
|
||||
|
||||
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
|
||||
video_set_drvdata(cam->v4ldev, NULL);
|
||||
video_unregister_device(cam->v4ldev);
|
||||
|
||||
up(&sn9c102_sysfs_lock);
|
||||
usb_put_dev(cam->usbdev);
|
||||
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
kfree(cam->control_buffer);
|
||||
}
|
||||
@ -1449,7 +1455,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
|
||||
|
||||
cam = video_get_drvdata(video_devdata(filp));
|
||||
|
||||
if (down_interruptible(&cam->dev_sem)) {
|
||||
if (mutex_lock_interruptible(&cam->dev_mutex)) {
|
||||
up_read(&sn9c102_disconnect);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
@ -1461,7 +1467,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
|
||||
err = -EWOULDBLOCK;
|
||||
goto out;
|
||||
}
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
err = wait_event_interruptible_exclusive(cam->open,
|
||||
cam->state & DEV_DISCONNECTED
|
||||
|| !cam->users);
|
||||
@ -1473,7 +1479,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
|
||||
up_read(&sn9c102_disconnect);
|
||||
return -ENODEV;
|
||||
}
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -1501,7 +1507,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
|
||||
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
|
||||
|
||||
out:
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
up_read(&sn9c102_disconnect);
|
||||
return err;
|
||||
}
|
||||
@ -1511,7 +1517,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
|
||||
{
|
||||
struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
|
||||
down(&cam->dev_sem); /* prevent disconnect() to be called */
|
||||
mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
|
||||
|
||||
sn9c102_stop_transfer(cam);
|
||||
|
||||
@ -1519,7 +1525,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
sn9c102_release_resources(cam);
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
kfree(cam);
|
||||
return 0;
|
||||
}
|
||||
@ -1529,7 +1535,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
|
||||
|
||||
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1541,35 +1547,36 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
|
||||
struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
struct sn9c102_frame_t* f, * i;
|
||||
unsigned long lock_flags;
|
||||
long timeout;
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->io == IO_MMAP) {
|
||||
DBG(3, "Close and open the device again to choose "
|
||||
"the read method");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cam->io == IO_NONE) {
|
||||
if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
|
||||
DBG(1, "read() failed, not enough memory");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cam->io = IO_READ;
|
||||
@ -1583,30 +1590,32 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(&cam->outqueue)) {
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
err = wait_event_interruptible
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED) );
|
||||
if (err) {
|
||||
up(&cam->fileop_sem);
|
||||
return err;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return timeout;
|
||||
}
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
up(&cam->fileop_sem);
|
||||
if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -1634,7 +1643,7 @@ exit:
|
||||
PDBGG("Frame #%lu, bytes read: %zu",
|
||||
(unsigned long)f->buf.index, count);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1647,7 +1656,7 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
|
||||
unsigned long lock_flags;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return POLLERR;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
@ -1685,12 +1694,12 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
|
||||
if (!list_empty(&cam->outqueue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return mask;
|
||||
|
||||
error:
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return POLLERR;
|
||||
}
|
||||
|
||||
@ -1724,25 +1733,25 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
void *pos;
|
||||
u32 i;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
|
||||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1751,7 +1760,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
break;
|
||||
}
|
||||
if (i == cam->nbuffers) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1761,7 +1770,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
pos = cam->frame[i].bufmem;
|
||||
while (size > 0) { /* size is page-aligned */
|
||||
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
start += PAGE_SIZE;
|
||||
@ -1774,7 +1783,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
|
||||
|
||||
sn9c102_vm_open(vma);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1816,6 +1825,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
strcpy(i.name, "Camera");
|
||||
i.type = V4L2_INPUT_TYPE_CAMERA;
|
||||
|
||||
if (copy_to_user(arg, &i, sizeof(i)))
|
||||
return -EFAULT;
|
||||
@ -1825,7 +1835,19 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
|
||||
|
||||
|
||||
static int
|
||||
sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
|
||||
sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if (copy_to_user(arg, &index, sizeof(index)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
int index;
|
||||
|
||||
@ -1842,7 +1864,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
|
||||
static int
|
||||
sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_queryctrl qc;
|
||||
u8 i;
|
||||
|
||||
@ -1864,7 +1886,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
static int
|
||||
sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
int err = 0;
|
||||
u8 i;
|
||||
@ -1896,7 +1918,7 @@ exit:
|
||||
static int
|
||||
sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_control ctrl;
|
||||
u8 i;
|
||||
int err = 0;
|
||||
@ -1909,6 +1931,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
|
||||
if (ctrl.id == s->qctrl[i].id) {
|
||||
if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
|
||||
return -EINVAL;
|
||||
if (ctrl.value < s->qctrl[i].minimum ||
|
||||
ctrl.value > s->qctrl[i].maximum)
|
||||
return -ERANGE;
|
||||
@ -1931,7 +1955,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
|
||||
static int
|
||||
sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
|
||||
struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
|
||||
|
||||
cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
cc->pixelaspect.numerator = 1;
|
||||
@ -1947,7 +1971,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
|
||||
static int
|
||||
sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_crop crop = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
};
|
||||
@ -1964,7 +1988,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
|
||||
static int
|
||||
sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_crop crop;
|
||||
struct v4l2_rect* rect;
|
||||
struct v4l2_rect* bounds = &(s->cropcap.bounds);
|
||||
@ -2105,7 +2129,7 @@ static int
|
||||
sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
|
||||
{
|
||||
struct v4l2_format format;
|
||||
struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
|
||||
struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
|
||||
|
||||
if (copy_from_user(&format, arg, sizeof(format)))
|
||||
return -EFAULT;
|
||||
@ -2130,7 +2154,7 @@ static int
|
||||
sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
|
||||
void __user * arg)
|
||||
{
|
||||
struct sn9c102_sensor* s = cam->sensor;
|
||||
struct sn9c102_sensor* s = &cam->sensor;
|
||||
struct v4l2_format format;
|
||||
struct v4l2_pix_format* pix;
|
||||
struct v4l2_pix_format* pfmt = &(s->pix_format);
|
||||
@ -2417,7 +2441,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
|
||||
struct v4l2_buffer b;
|
||||
struct sn9c102_frame_t *f;
|
||||
unsigned long lock_flags;
|
||||
int err = 0;
|
||||
long timeout;
|
||||
|
||||
if (copy_from_user(&b, arg, sizeof(b)))
|
||||
return -EFAULT;
|
||||
@ -2430,16 +2454,18 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
|
||||
return -EINVAL;
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
err = wait_event_interruptible
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED) );
|
||||
if (err)
|
||||
return err;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0)
|
||||
return timeout;
|
||||
if (cam->state & DEV_DISCONNECTED)
|
||||
return -ENODEV;
|
||||
if (cam->state & DEV_MISCONFIGURED)
|
||||
if (!timeout || (cam->state & DEV_MISCONFIGURED))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -2571,8 +2597,10 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
|
||||
return sn9c102_vidioc_enuminput(cam, arg);
|
||||
|
||||
case VIDIOC_G_INPUT:
|
||||
return sn9c102_vidioc_g_input(cam, arg);
|
||||
|
||||
case VIDIOC_S_INPUT:
|
||||
return sn9c102_vidioc_gs_input(cam, arg);
|
||||
return sn9c102_vidioc_s_input(cam, arg);
|
||||
|
||||
case VIDIOC_QUERYCTRL:
|
||||
return sn9c102_vidioc_query_ctrl(cam, arg);
|
||||
@ -2655,19 +2683,19 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
|
||||
struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&cam->fileop_sem))
|
||||
if (mutex_lock_interruptible(&cam->fileop_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (cam->state & DEV_DISCONNECTED) {
|
||||
DBG(1, "Device not present");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cam->state & DEV_MISCONFIGURED) {
|
||||
DBG(1, "The camera is misconfigured. Close and open it "
|
||||
"again.");
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -2675,7 +2703,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
|
||||
|
||||
err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
|
||||
|
||||
up(&cam->fileop_sem);
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -2722,7 +2750,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_MUTEX(&cam->dev_sem);
|
||||
mutex_init(&cam->dev_mutex);
|
||||
|
||||
r = sn9c102_read_reg(cam, 0x00);
|
||||
if (r < 0 || r != 0x10) {
|
||||
@ -2752,10 +2780,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err && cam->sensor) {
|
||||
DBG(2, "%s image sensor detected", cam->sensor->name);
|
||||
if (!err) {
|
||||
DBG(2, "%s image sensor detected", cam->sensor.name);
|
||||
DBG(3, "Support for %s maintained by %s",
|
||||
cam->sensor->name, cam->sensor->maintainer);
|
||||
cam->sensor.name, cam->sensor.maintainer);
|
||||
} else {
|
||||
DBG(1, "No supported image sensor detected");
|
||||
err = -ENODEV;
|
||||
@ -2776,7 +2804,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
cam->v4ldev->release = video_device_release;
|
||||
video_set_drvdata(cam->v4ldev, cam);
|
||||
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
|
||||
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
|
||||
video_nr[dev_nr]);
|
||||
@ -2786,13 +2814,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
DBG(1, "Free /dev/videoX node not found");
|
||||
video_nr[dev_nr] = -1;
|
||||
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
|
||||
|
||||
cam->module_param.force_munmap = force_munmap[dev_nr];
|
||||
cam->module_param.frame_timeout = frame_timeout[dev_nr];
|
||||
|
||||
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
|
||||
|
||||
@ -2803,7 +2832,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
|
||||
usb_set_intfdata(intf, cam);
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2827,7 +2856,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
|
||||
|
||||
down_write(&sn9c102_disconnect);
|
||||
|
||||
down(&cam->dev_sem);
|
||||
mutex_lock(&cam->dev_mutex);
|
||||
|
||||
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
|
||||
|
||||
@ -2841,13 +2870,14 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
|
||||
sn9c102_stop_transfer(cam);
|
||||
cam->state |= DEV_DISCONNECTED;
|
||||
wake_up_interruptible(&cam->wait_frame);
|
||||
wake_up_interruptible(&cam->wait_stream);
|
||||
wake_up(&cam->wait_stream);
|
||||
usb_get_dev(cam->usbdev);
|
||||
} else {
|
||||
cam->state |= DEV_DISCONNECTED;
|
||||
sn9c102_release_resources(cam);
|
||||
}
|
||||
|
||||
up(&cam->dev_sem);
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
|
||||
if (!cam->users)
|
||||
kfree(cam);
|
||||
|
@ -34,8 +34,8 @@ static int ov7630_init(struct sn9c102_device* cam)
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x8d);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
||||
@ -43,12 +43,14 @@ static int ov7630_init(struct sn9c102_device* cam)
|
||||
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
||||
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x44);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x23, 0xee);
|
||||
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x29, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
|
||||
err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
|
||||
err += sn9c102_i2c_write(cam, 0x30, 0x24);
|
||||
err += sn9c102_i2c_write(cam, 0x32, 0x86);
|
||||
@ -80,7 +82,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
||||
err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
|
||||
err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
|
||||
@ -108,7 +110,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
||||
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
|
||||
err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
|
||||
@ -371,26 +373,29 @@ static struct sn9c102_sensor ov7630 = {
|
||||
|
||||
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id ov7630_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x602c), },
|
||||
{ USB_DEVICE(0x0c45, 0x602d), },
|
||||
{ USB_DEVICE(0x0c45, 0x608f), },
|
||||
{ USB_DEVICE(0x0c45, 0x60b0), },
|
||||
{ }
|
||||
};
|
||||
int err = 0;
|
||||
|
||||
sn9c102_attach_sensor(cam, &ov7630);
|
||||
|
||||
if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
|
||||
le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
|
||||
le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
|
||||
le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
|
||||
if (!sn9c102_match_id(cam, ov7630_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
|
||||
if (err)
|
||||
return -EIO;
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x0b, 0);
|
||||
err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
|
||||
if (err)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &ov7630);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
238
drivers/usb/media/sn9c102_pas202bca.c
Normal file
238
drivers/usb/media/sn9c102_pas202bca.c
Normal file
@ -0,0 +1,238 @@
|
||||
/***************************************************************************
|
||||
* Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (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., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas202bca;
|
||||
|
||||
|
||||
static int pas202bca_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x02, 0x14);
|
||||
err += sn9c102_i2c_write(cam, 0x03, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
|
||||
err += sn9c102_i2c_write(cam, 0x0e, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
|
||||
err += sn9c102_i2c_write(cam, 0x10, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x13, 0x63);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x70);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
|
||||
msleep(400);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
err += sn9c102_write_reg(cam, 0x24, 0x17);
|
||||
else
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
|
||||
err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_DAC_MAGNITUDE:
|
||||
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &pas202bca;
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas202bca = {
|
||||
.name = "PAS202BCA",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x40,
|
||||
.init = &pas202bca_init,
|
||||
.qctrl = {
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x01e5,
|
||||
.maximum = 0x3fff,
|
||||
.step = 0x0001,
|
||||
.default_value = 0x01e5,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "global gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x1f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x0c,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x01,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x05,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "DAC magnitude",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x04,
|
||||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.set_ctrl = &pas202bca_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
},
|
||||
.set_crop = &pas202bca_set_crop,
|
||||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &pas202bca_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id pas202bca_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x60af), },
|
||||
{ }
|
||||
};
|
||||
int err = 0;
|
||||
|
||||
if (!sn9c102_match_id(cam,pas202bca_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
if (err)
|
||||
return -EIO;
|
||||
|
||||
if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &pas202bca);
|
||||
|
||||
return 0;
|
||||
}
|
@ -263,7 +263,7 @@ static struct sn9c102_sensor pas202bcb = {
|
||||
|
||||
|
||||
int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
|
||||
{
|
||||
{
|
||||
int r0 = 0, r1 = 0, err = 0;
|
||||
unsigned int pid = 0;
|
||||
|
||||
|
@ -66,6 +66,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
|
||||
@ -81,12 +82,17 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
|
||||
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
|
||||
&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
|
||||
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
|
||||
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
|
||||
NULL, \
|
||||
};
|
||||
|
||||
/* Device identification */
|
||||
extern struct sn9c102_device*
|
||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
|
||||
|
||||
/* Attach a probed sensor to the camera. */
|
||||
extern void
|
||||
sn9c102_attach_sensor(struct sn9c102_device* cam,
|
||||
@ -108,6 +114,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
|
||||
static const struct usb_device_id sn9c102_id_table[] = { \
|
||||
{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6007), }, \
|
||||
{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6024), }, \
|
||||
@ -126,7 +133,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
|
||||
@ -359,12 +366,6 @@ struct sn9c102_sensor {
|
||||
error code without rolling back.
|
||||
*/
|
||||
|
||||
const struct usb_device* usbdev;
|
||||
/*
|
||||
Points to the usb_device struct after the sensor is attached.
|
||||
Do not touch unless you know what you are doing.
|
||||
*/
|
||||
|
||||
/*
|
||||
Do NOT write to the data below, it's READ ONLY. It is used by the
|
||||
core module to store successfully updated values of the above
|
||||
|
@ -142,14 +142,18 @@ static struct sn9c102_sensor tas5110c1b = {
|
||||
|
||||
int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
|
||||
{
|
||||
/* This sensor has no identifiers, so let's attach it anyway */
|
||||
sn9c102_attach_sensor(cam, &tas5110c1b);
|
||||
const struct usb_device_id tas5110c1b_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6001), },
|
||||
{ USB_DEVICE(0x0c45, 0x6005), },
|
||||
{ USB_DEVICE(0x0c45, 0x60ab), },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Sensor detection is based on USB pid/vid */
|
||||
if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
|
||||
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
|
||||
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
|
||||
if (!sn9c102_match_id(cam, tas5110c1b_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &tas5110c1b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = {
|
||||
|
||||
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
||||
{
|
||||
/* This sensor has no identifiers, so let's attach it anyway */
|
||||
sn9c102_attach_sensor(cam, &tas5130d1b);
|
||||
const struct usb_device_id tas5130d1b_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6025), },
|
||||
{ USB_DEVICE(0x0c45, 0x60aa), },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Sensor detection is based on USB pid/vid */
|
||||
if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
|
||||
le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
|
||||
if (!sn9c102_match_id(cam, tas5130d1b_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &tas5130d1b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "stv680.h"
|
||||
|
||||
@ -317,12 +318,11 @@ static int stv_init (struct usb_stv *stv680)
|
||||
unsigned char *buffer;
|
||||
unsigned long int bufsize;
|
||||
|
||||
buffer = kmalloc (40, GFP_KERNEL);
|
||||
buffer = kzalloc (40, GFP_KERNEL);
|
||||
if (buffer == NULL) {
|
||||
PDEBUG (0, "STV(e): Out of (small buf) memory");
|
||||
return -1;
|
||||
}
|
||||
memset (buffer, 0, 40);
|
||||
udelay (100);
|
||||
|
||||
/* set config 1, interface 0, alternate 0 */
|
||||
@ -1258,22 +1258,22 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
|
||||
unsigned long size = vma->vm_end-vma->vm_start;
|
||||
unsigned long page, pos;
|
||||
|
||||
down (&stv680->lock);
|
||||
mutex_lock(&stv680->lock);
|
||||
|
||||
if (stv680->udev == NULL) {
|
||||
up (&stv680->lock);
|
||||
mutex_unlock(&stv680->lock);
|
||||
return -EIO;
|
||||
}
|
||||
if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
|
||||
& ~(PAGE_SIZE - 1))) {
|
||||
up (&stv680->lock);
|
||||
mutex_unlock(&stv680->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
pos = (unsigned long) stv680->fbuf;
|
||||
while (size > 0) {
|
||||
page = vmalloc_to_pfn((void *)pos);
|
||||
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
|
||||
up (&stv680->lock);
|
||||
mutex_unlock(&stv680->lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
start += PAGE_SIZE;
|
||||
@ -1283,7 +1283,7 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
up (&stv680->lock);
|
||||
mutex_unlock(&stv680->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1387,14 +1387,12 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
|
||||
goto error;
|
||||
}
|
||||
/* We found one */
|
||||
if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
|
||||
if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
|
||||
PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset (stv680, 0, sizeof (*stv680));
|
||||
|
||||
stv680->udev = dev;
|
||||
stv680->camera_name = camera_name;
|
||||
|
||||
@ -1409,7 +1407,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
|
||||
|
||||
memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
|
||||
init_waitqueue_head (&stv680->wq);
|
||||
init_MUTEX (&stv680->lock);
|
||||
mutex_init (&stv680->lock);
|
||||
wmb ();
|
||||
|
||||
if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
|
||||
|
@ -118,7 +118,7 @@ struct usb_stv {
|
||||
int origGain;
|
||||
int origMode; /* original camera mode */
|
||||
|
||||
struct semaphore lock; /* to lock the structure */
|
||||
struct mutex lock; /* to lock the structure */
|
||||
int user; /* user count for exclusive use */
|
||||
int removed; /* device disconnected */
|
||||
int streaming; /* Are we streaming video? */
|
||||
|
@ -690,14 +690,13 @@ int usbvideo_register(
|
||||
}
|
||||
|
||||
base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
|
||||
cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
|
||||
cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
|
||||
if (cams == NULL) {
|
||||
err("Failed to allocate %d. bytes for usbvideo struct", base_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
|
||||
__FUNCTION__, cams, base_size, num_cams);
|
||||
memset(cams, 0, base_size);
|
||||
|
||||
/* Copy callbacks, apply defaults for those that are not set */
|
||||
memmove(&cams->cb, cbTbl, sizeof(cams->cb));
|
||||
@ -715,7 +714,7 @@ int usbvideo_register(
|
||||
cams->md_module = md;
|
||||
if (cams->md_module == NULL)
|
||||
warn("%s: module == NULL!", __FUNCTION__);
|
||||
init_MUTEX(&cams->lock); /* to 1 == available */
|
||||
mutex_init(&cams->lock); /* to 1 == available */
|
||||
|
||||
for (i = 0; i < num_cams; i++) {
|
||||
struct uvd *up = &cams->cam[i];
|
||||
@ -863,7 +862,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
|
||||
if (uvd->debug > 0)
|
||||
info("%s(%p.)", __FUNCTION__, intf);
|
||||
|
||||
down(&uvd->lock);
|
||||
mutex_lock(&uvd->lock);
|
||||
uvd->remove_pending = 1; /* Now all ISO data will be ignored */
|
||||
|
||||
/* At this time we ask to cancel outstanding URBs */
|
||||
@ -883,7 +882,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
|
||||
info("%s: In use, disconnect pending.", __FUNCTION__);
|
||||
else
|
||||
usbvideo_CameraRelease(uvd);
|
||||
up(&uvd->lock);
|
||||
mutex_unlock(&uvd->lock);
|
||||
info("USB camera disconnected.");
|
||||
|
||||
usbvideo_ClientDecModCount(uvd);
|
||||
@ -930,19 +929,19 @@ static int usbvideo_find_struct(struct usbvideo *cams)
|
||||
err("No usbvideo handle?");
|
||||
return -1;
|
||||
}
|
||||
down(&cams->lock);
|
||||
mutex_lock(&cams->lock);
|
||||
for (u = 0; u < cams->num_cameras; u++) {
|
||||
struct uvd *uvd = &cams->cam[u];
|
||||
if (!uvd->uvd_used) /* This one is free */
|
||||
{
|
||||
uvd->uvd_used = 1; /* In use now */
|
||||
init_MUTEX(&uvd->lock); /* to 1 == available */
|
||||
mutex_init(&uvd->lock); /* to 1 == available */
|
||||
uvd->dev = NULL;
|
||||
rv = u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up(&cams->lock);
|
||||
mutex_unlock(&cams->lock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -984,7 +983,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
|
||||
/* Not relying upon caller we increase module counter ourselves */
|
||||
usbvideo_ClientIncModCount(uvd);
|
||||
|
||||
down(&uvd->lock);
|
||||
mutex_lock(&uvd->lock);
|
||||
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
|
||||
uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
|
||||
if (uvd->sbuf[i].urb == NULL) {
|
||||
@ -1007,7 +1006,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
|
||||
* return control to the client's probe function right now.
|
||||
*/
|
||||
allocate_done:
|
||||
up (&uvd->lock);
|
||||
mutex_unlock(&uvd->lock);
|
||||
usbvideo_ClientDecModCount(uvd);
|
||||
return uvd;
|
||||
}
|
||||
@ -1121,7 +1120,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
|
||||
info("%s($%p)", __FUNCTION__, dev);
|
||||
|
||||
usbvideo_ClientIncModCount(uvd);
|
||||
down(&uvd->lock);
|
||||
mutex_lock(&uvd->lock);
|
||||
|
||||
if (uvd->user) {
|
||||
err("%s: Someone tried to open an already opened device!", __FUNCTION__);
|
||||
@ -1202,7 +1201,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
}
|
||||
}
|
||||
up(&uvd->lock);
|
||||
mutex_unlock(&uvd->lock);
|
||||
if (errCode != 0)
|
||||
usbvideo_ClientDecModCount(uvd);
|
||||
if (uvd->debug > 0)
|
||||
@ -1231,7 +1230,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
|
||||
if (uvd->debug > 1)
|
||||
info("%s($%p)", __FUNCTION__, dev);
|
||||
|
||||
down(&uvd->lock);
|
||||
mutex_lock(&uvd->lock);
|
||||
GET_CALLBACK(uvd, stopDataPump)(uvd);
|
||||
usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
|
||||
uvd->fbuf = NULL;
|
||||
@ -1252,7 +1251,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
|
||||
info("usbvideo_v4l_close: Final disconnect.");
|
||||
usbvideo_CameraRelease(uvd);
|
||||
}
|
||||
up(&uvd->lock);
|
||||
mutex_unlock(&uvd->lock);
|
||||
usbvideo_ClientDecModCount(uvd);
|
||||
|
||||
if (uvd->debug > 1)
|
||||
@ -1512,7 +1511,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
|
||||
if (uvd->debug >= 1)
|
||||
info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
|
||||
|
||||
down(&uvd->lock);
|
||||
mutex_lock(&uvd->lock);
|
||||
|
||||
/* See if a frame is completed, then use it. */
|
||||
for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
|
||||
@ -1644,7 +1643,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
|
||||
}
|
||||
}
|
||||
read_done:
|
||||
up(&uvd->lock);
|
||||
mutex_unlock(&uvd->lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user