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: (78 commits)
  USB: update MAINAINERS and CREDITS for Freescale USB driver
  USB: update gadget files for fsl_usb2_udc driver
  USB: add Freescale high-speed USB SOC device controller driver
  USB: quirk for broken suspend of IT8152F/G
  USB: iowarrior.c: timeouts too small in usb_control_msg calls
  USB: dell device id for option.c
  USB: Remove Huawei unusual_devs entry
  USB: CP2101 New Device IDs
  USB: add picdem device to ldusb
  usbfs micro optimitation
  USB: remove ancient/broken CRIS hcd
  usb ethernet gadget, workaround network stack API glitch
  USB: add "busnum" attribute for USB devices
  USB: cxacru: ADSL state management
  usbatm: Detect usb device shutdown and ignore failed urbs
  USB: Remove duplicate define of OHCI_QUIRK_ZFMICRO
  USB: BandRich BandLuxe HSDPA Data Card Driver
  USB gadget rndis: fix struct rndis_packet_msg_type unaligned bug
  USB Elan FTDI: check for driver registration status
  USB: sierra: add more checks on shutdown
  ...
This commit is contained in:
Linus Torvalds 2007-04-27 14:19:17 -07:00
commit 50f732ee63
80 changed files with 5358 additions and 5683 deletions

View File

@ -3301,6 +3301,14 @@ S: 12725 SW Millikan Way, Suite 400
S: Beaverton, Oregon 97005
S: USA
N: Li Yang
E: leoli@freescale.com
D: Freescale Highspeed USB device driver
D: Freescale QE SoC support and Ethernet driver
S: B-1206 Jingmao Guojigongyu
S: 16 Baliqiao Nanjie, Beijing 101100
S: People's Repulic of China
N: Marcelo Tosatti
E: marcelo@kvack.org
D: v2.4 kernel maintainer

View File

@ -0,0 +1,41 @@
What: /sys/bus/usb/devices/.../power/autosuspend
Date: March 2007
KernelVersion: 2.6.21
Contact: Alan Stern <stern@rowland.harvard.edu>
Description:
Each USB device directory will contain a file named
power/autosuspend. This file holds the time (in seconds)
the device must be idle before it will be autosuspended.
0 means the device will be autosuspended as soon as
possible. Negative values will prevent the device from
being autosuspended at all, and writing a negative value
will resume the device if it is already suspended.
The autosuspend delay for newly-created devices is set to
the value of the usbcore.autosuspend module parameter.
What: /sys/bus/usb/devices/.../power/level
Date: March 2007
KernelVersion: 2.6.21
Contact: Alan Stern <stern@rowland.harvard.edu>
Description:
Each USB device directory will contain a file named
power/level. This file holds a power-level setting for
the device, one of "on", "auto", or "suspend".
"on" means that the device is not allowed to autosuspend,
although normal suspends for system sleep will still
be honored. "auto" means the device will autosuspend
and autoresume in the usual manner, according to the
capabilities of its driver. "suspend" means the device
is forced into a suspended state and it will not autoresume
in response to I/O requests. However remote-wakeup requests
from the device may still be enabled (the remote-wakeup
setting is controlled separately by the power/wakeup
attribute).
During normal use, devices should be left in the "auto"
level. The other levels are meant for administrative uses.
If you want to suspend a device immediately but leave it
free to wake up in response to I/O requests, you should
write "0" to power/autosuspend.

View File

@ -1792,7 +1792,7 @@ and is between 256 and 4096 characters. It is defined in the file
for newly-detected USB devices (default 2). This
is the time required before an idle device will be
autosuspended. Devices for which the delay is set
to 0 won't be autosuspended at all.
to a negative value won't be autosuspended at all.
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.

View File

@ -16,7 +16,7 @@ situation as with tcpdump.
Unlike the packet socket, usbmon has an interface which provides traces
in a text format. This is used for two purposes. First, it serves as a
common trace exchange format for tools while most sophisticated formats
common trace exchange format for tools while more sophisticated formats
are finalized. Second, humans can read it in case tools are not available.
To collect a raw text trace, execute following steps.
@ -34,7 +34,7 @@ if usbmon is built into the kernel.
Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon
1s 1t 2s 2t 3s 3t 4s 4t
1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
#
2. Find which bus connects to the desired device
@ -54,7 +54,7 @@ Bus=03 means it's bus 3.
3. Start 'cat'
# cat /sys/kernel/debug/usbmon/3t > /tmp/1.mon.out
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going
@ -75,46 +75,80 @@ that the file size is not excessive for your favourite editor.
* Raw text data format
The '1t' type data consists of a stream of events, such as URB submission,
Two formats are supported currently: the original, or '1t' format, and
the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u'
format adds a few fields, such as ISO frame descriptors, interval, etc.
It produces slightly longer lines, but otherwise is a perfect superset
of '1t' format.
If it is desired to recognize one from the other in a program, look at the
"address" word (see below), where '1u' format adds a bus number. If 2 colons
are present, it's the '1t' format, otherwise '1u'.
Any text format data consists of a stream of events, such as URB submission,
URB callback, submission error. Every event is a text line, which consists
of whitespace separated words. The number or position of words may depend
on the event type, but there is a set of words, common for all types.
Here is the list of words, from left to right:
- URB Tag. This is used to identify URBs is normally a kernel mode address
of the URB structure in hexadecimal.
- Timestamp in microseconds, a decimal number. The timestamp's resolution
depends on available clock, and so it can be much worse than a microsecond
(if the implementation uses jiffies, for example).
- Event Type. This type refers to the format of the event, not URB type.
Available types are: S - submission, C - callback, E - submission error.
- "Pipe". The pipe concept is deprecated. This is a composite word, used to
be derived from information in pipes. It consists of three fields, separated
by colons: URB type and direction, Device address, Endpoint number.
- "Address" word (formerly a "pipe"). It consists of four fields, separated by
colons: URB type and direction, Bus number, Device address, Endpoint number.
Type and direction are encoded with two bytes in the following manner:
Ci Co Control input and output
Zi Zo Isochronous input and output
Ii Io Interrupt input and output
Bi Bo Bulk input and output
Device address and Endpoint number are 3-digit and 2-digit (respectively)
decimal numbers, with leading zeroes.
- URB Status. In most cases, this field contains a number, sometimes negative,
which represents a "status" field of the URB. This field makes no sense for
submissions, but is present anyway to help scripts with parsing. When an
error occurs, the field contains the error code. In case of a submission of
a Control packet, this field contains a Setup Tag instead of an error code.
It is easy to tell whether the Setup Tag is present because it is never a
number. Thus if scripts find a number in this field, they proceed to read
Data Length. If they find something else, like a letter, they read the setup
packet before reading the Data Length.
Bus number, Device address, and Endpoint are decimal numbers, but they may
have leading zeros, for the sake of human readers.
- URB Status word. This is either a letter, or several numbers separated
by colons: URB status, interval, start frame, and error count. Unlike the
"address" word, all fields save the status are optional. Interval is printed
only for interrupt and isochronous URBs. Start frame is printed only for
isochronous URBs. Error count is printed only for isochronous callback
events.
The status field is a decimal number, sometimes negative, which represents
a "status" field of the URB. This field makes no sense for submissions, but
is present anyway to help scripts with parsing. When an error occurs, the
field contains the error code.
In case of a submission of a Control packet, this field contains a Setup Tag
instead of an group of numbers. It is easy to tell whether the Setup Tag is
present because it is never a number. Thus if scripts find a set of numbers
in this word, they proceed to read Data Length (except for isochronous URBs).
If they find something else, like a letter, they read the setup packet before
reading the Data Length or isochronous descriptors.
- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
packet was present, but not captured, and the fields contain filler.
- Number of isochronous frame descriptors and descriptors themselves.
If an Isochronous transfer event has a set of descriptors, a total number
of them in an URB is printed first, then a word per descriptor, up to a
total of 5. The word consists of 3 colon-separated decimal numbers for
status, offset, and length respectively. For submissions, initial length
is reported. For callbacks, actual length is reported.
- Data Length. For submissions, this is the requested length. For callbacks,
this is the actual length.
- Data tag. The usbmon may not always capture data, even if length is nonzero.
The data words are present only if this tag is '='.
- Data words follow, in big endian hexadecimal format. Notice that they are
not machine words, but really just a byte stream split into words to make
it easier to read. Thus, the last word may contain from one to four bytes.
@ -153,20 +187,18 @@ class ParsedLine {
}
}
This format may be changed in the future.
Examples:
An input control transfer to get a port status.
d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 <
d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000
d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
to a storage device at address 5:
dd65f0e8 4128379752 S Bo:005:02 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
dd65f0e8 4128379808 C Bo:005:02 0 31 >
dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
* Raw binary format and API

View File

@ -981,6 +981,11 @@ M: mhw@wittsend.com
W: http://www.wittsend.com/computone.html
S: Maintained
CONEXANT ACCESSRUNNER USB DRIVER
P: Simon Arlott
M: cxacru@fire.lp0.eu
S: Maintained
COSA/SRP SYNC SERIAL DRIVER
P: Jan "Yenya" Kasprzak
M: kas@fi.muni.cz
@ -1389,6 +1394,13 @@ L: linuxppc-embedded@ozlabs.org
L: netdev@vger.kernel.org
S: Maintained
FREESCALE HIGHSPEED USB DEVICE DRIVER
P: Li Yang
M: leoli@freescale.com
L: linux-usb-devel@lists.sourceforge.net
L: linuxppc-embedded@ozlabs.org
S: Maintained
FILE LOCKING (flock() and fcntl()/lockf())
P: Matthew Wilcox
M: matthew@wil.cx

View File

@ -2132,10 +2132,13 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* BULK in or out? */
if (ep->bEndpointAddress & USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
if (ep->bEndpointAddress & USB_DIR_IN) {
if (ep_in == NULL)
ep_in = ep;
} else {
if (ep_out == NULL)
ep_out = ep;
}
}
}

View File

@ -15,7 +15,6 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
obj-$(CONFIG_USB_ACM) += class/

View File

@ -4,6 +4,7 @@
*
* Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
* Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
* Copyright (C) 2007 Simon Arlott
*
* 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
@ -34,14 +35,14 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h> /* FIXME: linux/firmware.h should include it itself */
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
#include "usbatm.h"
#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands"
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
#define DRIVER_VERSION "0.3"
#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
static const char cxacru_driver_name[] = "cxacru";
@ -64,7 +65,7 @@ static const char cxacru_driver_name[] = "cxacru";
#define SDRAM_ENA 0x1
#define CMD_TIMEOUT 2000 /* msecs */
#define POLL_INTERVAL 5000 /* msecs */
#define POLL_INTERVAL 1 /* secs */
/* commands for interaction with the modem through the control channel before
* firmware is loaded */
@ -146,6 +147,13 @@ enum cxacru_info_idx {
CXINF_MAX = 0x1c,
};
enum cxacru_poll_state {
CXPOLL_STOPPING,
CXPOLL_STOPPED,
CXPOLL_POLLING,
CXPOLL_SHUTDOWN
};
struct cxacru_modem_type {
u32 pll_f_clk;
u32 pll_b_clk;
@ -158,7 +166,12 @@ struct cxacru_data {
const struct cxacru_modem_type *modem_type;
int line_status;
struct mutex adsl_state_serialize;
int adsl_status;
struct delayed_work poll_work;
u32 card_info[CXINF_MAX];
struct mutex poll_state_serialize;
int poll_state;
/* contol handles */
struct mutex cm_serialize;
@ -170,6 +183,275 @@ struct cxacru_data {
struct completion snd_done;
};
static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
u8 *wdata, int wsize, u8 *rdata, int rsize);
static void cxacru_poll_status(struct work_struct *work);
/* Card info exported through sysfs */
#define CXACRU__ATTR_INIT(_name) \
static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
#define CXACRU_CMD_INIT(_name) \
static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
#define CXACRU_ATTR_INIT(_value, _type, _name) \
static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
struct cxacru_data *instance = usbatm_instance->driver_data; \
return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
} \
CXACRU__ATTR_INIT(_name)
#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", value);
}
static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", value);
}
static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
{
if (unlikely(value < 0)) {
return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
value / 100, -value % 100);
} else {
return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
value / 100, value % 100);
}
}
static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
{
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "no\n");
case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
default: return 0;
}
}
static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
{
switch (value) {
case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
}
static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
{
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "down\n");
case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
case 2: return snprintf(buf, PAGE_SIZE, "training\n");
case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
case 5: return snprintf(buf, PAGE_SIZE, "up\n");
case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
}
static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
{
switch (value) {
case 0: return 0;
case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
}
/*
* This could use MAC_ADDRESS_HIGH and MAC_ADDRESS_LOW, but since
* this data is already in atm_dev there's no point.
*
* MAC_ADDRESS_HIGH = 0x????5544
* MAC_ADDRESS_LOW = 0x33221100
* Where 00-55 are bytes 0-5 of the MAC.
*/
static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct atm_dev *atm_dev = usbatm_instance->atm_dev;
return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
}
static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct cxacru_data *instance = usbatm_instance->driver_data;
u32 value = instance->card_info[CXINF_LINE_STARTABLE];
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "running\n");
case 1: return snprintf(buf, PAGE_SIZE, "stopped\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
}
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct cxacru_data *instance = usbatm_instance->driver_data;
int ret;
int poll = -1;
char str_cmd[8];
int len = strlen(buf);
if (!capable(CAP_NET_ADMIN))
return -EACCES;
ret = sscanf(buf, "%7s", str_cmd);
if (ret != 1)
return -EINVAL;
ret = 0;
if (mutex_lock_interruptible(&instance->adsl_state_serialize))
return -ERESTARTSYS;
if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
if (ret < 0) {
atm_err(usbatm_instance, "change adsl state:"
" CHIP_ADSL_LINE_STOP returned %d\n", ret);
ret = -EIO;
} else {
ret = len;
poll = CXPOLL_STOPPED;
}
}
/* Line status is only updated every second
* and the device appears to only react to
* START/STOP every second too. Wait 1.5s to
* be sure that restart will have an effect. */
if (!strcmp(str_cmd, "restart"))
msleep(1500);
if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
if (ret < 0) {
atm_err(usbatm_instance, "change adsl state:"
" CHIP_ADSL_LINE_START returned %d\n", ret);
ret = -EIO;
} else {
ret = len;
poll = CXPOLL_POLLING;
}
}
if (!strcmp(str_cmd, "poll")) {
ret = len;
poll = CXPOLL_POLLING;
}
if (ret == 0) {
ret = -EINVAL;
poll = -1;
}
if (poll == CXPOLL_POLLING) {
mutex_lock(&instance->poll_state_serialize);
switch (instance->poll_state) {
case CXPOLL_STOPPED:
/* start polling */
instance->poll_state = CXPOLL_POLLING;
break;
case CXPOLL_STOPPING:
/* abort stop request */
instance->poll_state = CXPOLL_POLLING;
case CXPOLL_POLLING:
case CXPOLL_SHUTDOWN:
/* don't start polling */
poll = -1;
}
mutex_unlock(&instance->poll_state_serialize);
} else if (poll == CXPOLL_STOPPED) {
mutex_lock(&instance->poll_state_serialize);
/* request stop */
if (instance->poll_state == CXPOLL_POLLING)
instance->poll_state = CXPOLL_STOPPING;
mutex_unlock(&instance->poll_state_serialize);
}
mutex_unlock(&instance->adsl_state_serialize);
if (poll == CXPOLL_POLLING)
cxacru_poll_status(&instance->poll_work.work);
return ret;
}
/*
* All device attributes are included in CXACRU_ALL_FILES
* so that the same list can be used multiple times:
* INIT (define the device attributes)
* CREATE (create all the device files)
* REMOVE (remove all the device files)
*
* With the last two being defined as needed in the functions
* they are used in before calling CXACRU_ALL_FILES()
*/
#define CXACRU_ALL_FILES(_action) \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_RATE, u32, downstream_rate); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_RATE, u32, upstream_rate); \
CXACRU_ATTR_##_action(CXINF_LINK_STATUS, LINK, link_status); \
CXACRU_ATTR_##_action(CXINF_LINE_STATUS, LINE, line_status); \
CXACRU__ATTR_##_action( mac_address); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_SNR_MARGIN, dB, upstream_snr_margin); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_SNR_MARGIN, dB, downstream_snr_margin); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_ATTENUATION, dB, upstream_attenuation); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_ATTENUATION, dB, downstream_attenuation); \
CXACRU_ATTR_##_action(CXINF_TRANSMITTER_POWER, s8, transmitter_power); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_BITS_PER_FRAME, u32, upstream_bits_per_frame); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_BITS_PER_FRAME, u32, downstream_bits_per_frame); \
CXACRU_ATTR_##_action(CXINF_STARTUP_ATTEMPTS, u32, startup_attempts); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_CRC_ERRORS, u32, upstream_crc_errors); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_CRC_ERRORS, u32, downstream_crc_errors); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC_ERRORS, u32, upstream_fec_errors); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS, u32, downstream_fec_errors); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS, u32, upstream_hec_errors); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS, u32, downstream_hec_errors); \
CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE, bool, line_startable); \
CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \
CXACRU_CMD_##_action( adsl_state);
CXACRU_ALL_FILES(INIT);
/* the following three functions are stolen from drivers/usb/core/message.c */
static void cxacru_blocking_completion(struct urb *urb)
{
@ -347,8 +629,6 @@ static int cxacru_card_status(struct cxacru_data *instance)
return 0;
}
static void cxacru_poll_status(struct work_struct *work);
static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
struct atm_dev *atm_dev)
{
@ -357,6 +637,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
struct atm_dev *atm_dev = usbatm_instance->atm_dev;
*/
int ret;
int start_polling = 1;
dbg("cxacru_atm_start");
@ -369,14 +650,35 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
}
/* start ADSL */
mutex_lock(&instance->adsl_state_serialize);
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
if (ret < 0) {
atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
mutex_unlock(&instance->adsl_state_serialize);
return ret;
}
/* Start status polling */
cxacru_poll_status(&instance->poll_work.work);
mutex_lock(&instance->poll_state_serialize);
switch (instance->poll_state) {
case CXPOLL_STOPPED:
/* start polling */
instance->poll_state = CXPOLL_POLLING;
break;
case CXPOLL_STOPPING:
/* abort stop request */
instance->poll_state = CXPOLL_POLLING;
case CXPOLL_POLLING:
case CXPOLL_SHUTDOWN:
/* don't start polling */
start_polling = 0;
}
mutex_unlock(&instance->poll_state_serialize);
mutex_unlock(&instance->adsl_state_serialize);
if (start_polling)
cxacru_poll_status(&instance->poll_work.work);
return 0;
}
@ -387,14 +689,46 @@ static void cxacru_poll_status(struct work_struct *work)
u32 buf[CXINF_MAX] = {};
struct usbatm_data *usbatm = instance->usbatm;
struct atm_dev *atm_dev = usbatm->atm_dev;
int keep_polling = 1;
int ret;
ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
if (ret < 0) {
atm_warn(usbatm, "poll status: error %d\n", ret);
if (ret != -ESHUTDOWN)
atm_warn(usbatm, "poll status: error %d\n", ret);
mutex_lock(&instance->poll_state_serialize);
if (instance->poll_state != CXPOLL_SHUTDOWN) {
instance->poll_state = CXPOLL_STOPPED;
if (ret != -ESHUTDOWN)
atm_warn(usbatm, "polling disabled, set adsl_state"
" to 'start' or 'poll' to resume\n");
}
mutex_unlock(&instance->poll_state_serialize);
goto reschedule;
}
memcpy(instance->card_info, buf, sizeof(instance->card_info));
if (instance->adsl_status != buf[CXINF_LINE_STARTABLE]) {
instance->adsl_status = buf[CXINF_LINE_STARTABLE];
switch (instance->adsl_status) {
case 0:
atm_printk(KERN_INFO, usbatm, "ADSL state: running\n");
break;
case 1:
atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n");
break;
default:
atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status);
break;
}
}
if (instance->line_status == buf[CXINF_LINE_STATUS])
goto reschedule;
@ -449,7 +783,20 @@ static void cxacru_poll_status(struct work_struct *work)
break;
}
reschedule:
schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
mutex_lock(&instance->poll_state_serialize);
if (instance->poll_state == CXPOLL_STOPPING &&
instance->adsl_status == 1 && /* stopped */
instance->line_status == 0) /* down */
instance->poll_state = CXPOLL_STOPPED;
if (instance->poll_state == CXPOLL_STOPPED)
keep_polling = 0;
mutex_unlock(&instance->poll_state_serialize);
if (keep_polling)
schedule_delayed_work(&instance->poll_work,
round_jiffies_relative(POLL_INTERVAL*HZ));
}
static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
@ -684,6 +1031,14 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
instance->usbatm = usbatm_instance;
instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
memset(instance->card_info, 0, sizeof(instance->card_info));
mutex_init(&instance->poll_state_serialize);
instance->poll_state = CXPOLL_STOPPED;
instance->line_status = -1;
instance->adsl_status = -1;
mutex_init(&instance->adsl_state_serialize);
instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->rcv_buf) {
@ -710,6 +1065,13 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
goto fail;
}
#define CXACRU_DEVICE_CREATE_FILE(_name) \
ret = device_create_file(&intf->dev, &dev_attr_##_name); \
if (unlikely(ret)) \
goto fail_sysfs;
CXACRU_ALL_FILES(CREATE);
#undef CXACRU_DEVICE_CREATE_FILE
usb_fill_int_urb(instance->rcv_urb,
usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
instance->rcv_buf, PAGE_SIZE,
@ -730,6 +1092,14 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
return 0;
fail_sysfs:
dbg("cxacru_bind: device_create_file failed (%d)\n", ret);
#define CXACRU_DEVICE_REMOVE_FILE(_name) \
device_remove_file(&intf->dev, &dev_attr_##_name);
CXACRU_ALL_FILES(REMOVE);
#undef CXACRU_DEVICE_REVOVE_FILE
fail:
free_page((unsigned long) instance->snd_buf);
free_page((unsigned long) instance->rcv_buf);
@ -744,6 +1114,7 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
struct usb_interface *intf)
{
struct cxacru_data *instance = usbatm_instance->driver_data;
int is_polling = 1;
dbg("cxacru_unbind entered");
@ -752,8 +1123,20 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
return;
}
while (!cancel_delayed_work(&instance->poll_work))
flush_scheduled_work();
mutex_lock(&instance->poll_state_serialize);
BUG_ON(instance->poll_state == CXPOLL_SHUTDOWN);
/* ensure that status polling continues unless
* it has already stopped */
if (instance->poll_state == CXPOLL_STOPPED)
is_polling = 0;
/* stop polling from being stopped or started */
instance->poll_state = CXPOLL_SHUTDOWN;
mutex_unlock(&instance->poll_state_serialize);
if (is_polling)
cancel_rearming_delayed_work(&instance->poll_work);
usb_kill_urb(instance->snd_urb);
usb_kill_urb(instance->rcv_urb);
@ -762,6 +1145,12 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
free_page((unsigned long) instance->snd_buf);
free_page((unsigned long) instance->rcv_buf);
#define CXACRU_DEVICE_REMOVE_FILE(_name) \
device_remove_file(&intf->dev, &dev_attr_##_name);
CXACRU_ALL_FILES(REMOVE);
#undef CXACRU_DEVICE_REVOVE_FILE
kfree(instance);
usbatm_instance->driver_data = NULL;

View File

@ -274,6 +274,9 @@ static void usbatm_complete(struct urb *urb)
(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
urb->status != -EILSEQ ))
{
if (urb->status == -ESHUTDOWN)
return;
if (printk_ratelimit())
atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
__func__, urb, urb->status);
@ -968,6 +971,14 @@ static int usbatm_atm_init(struct usbatm_data *instance)
/* temp init ATM device, set to 128kbit */
atm_dev->link_rate = 128 * 1000 / 424;
ret = sysfs_create_link(&atm_dev->class_dev.kobj,
&instance->usb_intf->dev.kobj, "device");
if (ret) {
atm_err(instance, "%s: sysfs_create_link failed: %d\n",
__func__, ret);
goto fail_sysfs;
}
if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
goto fail;
@ -986,6 +997,8 @@ static int usbatm_atm_init(struct usbatm_data *instance)
return 0;
fail:
sysfs_remove_link(&atm_dev->class_dev.kobj, "device");
fail_sysfs:
instance->atm_dev = NULL;
atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
return ret;
@ -1318,8 +1331,10 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
kfree(instance->cell_buf);
/* ATM finalize */
if (instance->atm_dev)
if (instance->atm_dev) {
sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
}
usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
}

View File

@ -212,7 +212,41 @@ static int acm_write_start(struct acm *acm)
}
return rc;
}
/*
* attributes exported through sysfs
*/
static ssize_t show_caps
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
return sprintf(buf, "%d", acm->ctrl_caps);
}
static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
static ssize_t show_country_codes
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
memcpy(buf, acm->country_codes, acm->country_code_size);
return acm->country_code_size;
}
static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
static ssize_t show_country_rel_date
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
return sprintf(buf, "%d", acm->country_rel_date);
}
static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
/*
* Interrupt handlers for various ACM device responses
*/
@ -514,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm)
usb_free_urb(acm->writeurb);
for (i = 0; i < nr; i++)
usb_free_urb(acm->ru[i].urb);
kfree(acm->country_codes);
kfree(acm);
}
@ -761,6 +796,7 @@ static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_cdc_union_desc *union_header = NULL;
struct usb_cdc_country_functional_desc *cfd = NULL;
char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
@ -824,8 +860,9 @@ static int acm_probe (struct usb_interface *intf,
union_header = (struct usb_cdc_union_desc *)
buffer;
break;
case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
break; /* for now we ignore it */
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case USB_CDC_ACM_TYPE:
@ -983,6 +1020,34 @@ static int acm_probe (struct usb_interface *intf,
goto alloc_fail7;
}
usb_set_intfdata (intf, acm);
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
if (i < 0)
goto alloc_fail8;
if (cfd) { /* export the country data */
acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
if (!acm->country_codes)
goto skip_countries;
acm->country_code_size = cfd->bLength - 4;
memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
acm->country_rel_date = cfd->iCountryCodeRelDate;
i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
if (i < 0) {
kfree(acm->country_codes);
goto skip_countries;
}
i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
if (i < 0) {
kfree(acm->country_codes);
goto skip_countries;
}
}
skip_countries:
usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@ -1006,9 +1071,10 @@ static int acm_probe (struct usb_interface *intf,
tty_register_device(acm_tty_driver, minor, &control_interface->dev);
acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
return 0;
return 0;
alloc_fail8:
usb_free_urb(acm->writeurb);
alloc_fail7:
for (i = 0; i < num_rx_buf; i++)
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
@ -1027,7 +1093,7 @@ static int acm_probe (struct usb_interface *intf,
static void acm_disconnect(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata (intf);
struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
int i;
@ -1041,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf)
mutex_unlock(&open_mutex);
return;
}
if (acm->country_codes){
device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
}
device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
acm->dev = NULL;
usb_set_intfdata(acm->control, NULL);
usb_set_intfdata(acm->data, NULL);

View File

@ -91,6 +91,9 @@ struct acm {
struct urb *ctrlurb, *writeurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */
unsigned int country_code_size; /* size of this buffer */
unsigned int country_rel_date; /* release date of version */
struct acm_wb wb[ACM_NW];
struct acm_ru ru[ACM_NR];
struct acm_rb rb[ACM_NR];

View File

@ -31,7 +31,30 @@ config USB_DEVICEFS
For the format of the various /proc/bus/usb/ files, please read
<file:Documentation/usb/proc_usb_info.txt>.
Most users want to say Y here.
Usbfs files can't handle Access Control Lists (ACL), which are the
default way to grant access to USB devices for untrusted users of a
desktop system. The usbfs functionality is replaced by real
device-nodes managed by udev. These nodes live in /dev/bus/usb and
are used by libusb.
config USB_DEVICE_CLASS
bool "USB device class-devices (DEPRECATED)"
depends on USB
default n
---help---
Userspace access to USB devices is granted by device-nodes exported
directly from the usbdev in sysfs. Old versions of the driver
core and udev needed additional class devices to export device nodes.
These additional devices are difficult to handle in userspace, if
information about USB interfaces must be available. One device contains
the device node, the other device contains the interface data. Both
devices are at the same level in sysfs (siblings) and one can't access
the other. The device node created directly by the usbdev is the parent
device of the interface and therefore easily accessible from the interface
event.
This option provides backward compatibility if needed.
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"

View File

@ -57,7 +57,6 @@
#define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
/* Mutual exclusion for removal, open, and release */
DEFINE_MUTEX(usbfs_mutex);
@ -514,22 +513,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
return ret;
}
static struct usb_device *usbdev_lookup_minor(int minor)
static int __match_minor(struct device *dev, void *data)
{
struct device *device;
struct usb_device *udev = NULL;
int minor = *((int *)data);
down(&usb_device_class->sem);
list_for_each_entry(device, &usb_device_class->devices, node) {
if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
udev = device->platform_data;
break;
}
}
up(&usb_device_class->sem);
if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
return 1;
return 0;
}
return udev;
};
static struct usb_device *usbdev_lookup_by_minor(int minor)
{
struct device *dev;
dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor);
if (!dev)
return NULL;
put_device(dev);
return container_of(dev, struct usb_device, dev);
}
/*
* file operations
@ -548,11 +550,14 @@ static int usbdev_open(struct inode *inode, struct file *file)
goto out;
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
dev = usbdev_lookup_by_minor(iminor(inode));
#ifdef CONFIG_USB_DEVICEFS
/* procfs file */
if (!dev)
dev = inode->i_private;
#endif
if (!dev)
goto out;
ret = usb_autoresume_device(dev);
@ -575,7 +580,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->disccontext = NULL;
ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
wmb();
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
@ -1570,7 +1575,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
return mask;
}
const struct file_operations usbfs_device_file_operations = {
const struct file_operations usbdev_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@ -1579,50 +1584,53 @@ const struct file_operations usbfs_device_file_operations = {
.release = usbdev_release,
};
static int usbdev_add(struct usb_device *dev)
#ifdef CONFIG_USB_DEVICE_CLASS
static struct class *usb_classdev_class;
static int usb_classdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
dev->usb_classdev = device_create(usb_classdev_class, &dev->dev,
MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
if (IS_ERR(dev->usbfs_dev))
return PTR_ERR(dev->usbfs_dev);
if (IS_ERR(dev->usb_classdev))
return PTR_ERR(dev->usb_classdev);
dev->usbfs_dev->platform_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
static void usb_classdev_remove(struct usb_device *dev)
{
device_unregister(dev->usbfs_dev);
device_unregister(dev->usb_classdev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
void *dev)
static int usb_classdev_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
if (usbdev_add(dev))
if (usb_classdev_add(dev))
return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
usb_classdev_remove(dev);
break;
}
return NOTIFY_OK;
}
static struct notifier_block usbdev_nb = {
.notifier_call = usbdev_notify,
.notifier_call = usb_classdev_notify,
};
#endif
static struct cdev usb_device_cdev = {
.kobj = {.name = "usb_device", },
.owner = THIS_MODULE,
};
int __init usbdev_init(void)
int __init usb_devio_init(void)
{
int retval;
@ -1632,38 +1640,38 @@ int __init usbdev_init(void)
err("unable to register minors for usb_device");
goto out;
}
cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
goto error_cdev;
}
usb_device_class = class_create(THIS_MODULE, "usb_device");
if (IS_ERR(usb_device_class)) {
#ifdef CONFIG_USB_DEVICE_CLASS
usb_classdev_class = class_create(THIS_MODULE, "usb_device");
if (IS_ERR(usb_classdev_class)) {
err("unable to register usb_device class");
retval = PTR_ERR(usb_device_class);
goto error_class;
retval = PTR_ERR(usb_classdev_class);
cdev_del(&usb_device_cdev);
usb_classdev_class = NULL;
goto out;
}
usb_register_notify(&usbdev_nb);
#endif
out:
return retval;
error_class:
usb_device_class = NULL;
cdev_del(&usb_device_cdev);
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
}
void usbdev_cleanup(void)
void usb_devio_cleanup(void)
{
#ifdef CONFIG_USB_DEVICE_CLASS
usb_unregister_notify(&usbdev_nb);
class_destroy(usb_device_class);
class_destroy(usb_classdev_class);
#endif
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}

View File

@ -574,23 +574,10 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
/*
* This sends an uevent to userspace, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
struct usb_host_interface *alt;
int i = 0;
int length = 0;
@ -600,13 +587,11 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
/* driver is often null here; dev_dbg() would oops */
pr_debug ("usb %s: uevent\n", dev->bus_id);
if (is_usb_device(dev)) {
if (is_usb_device(dev))
usb_dev = to_usb_device(dev);
alt = NULL;
} else {
intf = to_usb_interface(dev);
else {
struct usb_interface *intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
alt = intf->cur_altsetting;
}
if (usb_dev->devnum < 0) {
@ -621,9 +606,7 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
* act as usermode drivers.
*/
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
@ -650,44 +633,29 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
if (!is_usb_device(dev)) {
if (add_uevent_var(envp, num_envp, &i,
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
"BUSNUM=%03d",
usb_dev->bus->busnum))
return -ENOMEM;
if (add_uevent_var(envp, num_envp, &i,
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
}
"DEVNUM=%03d",
usb_dev->devnum))
return -ENOMEM;
envp[i] = NULL;
return 0;
}
#else
static int usb_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */
/**
@ -872,8 +840,10 @@ static int usb_resume_device(struct usb_device *udev)
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
if (status == 0) {
udev->autoresume_disabled = 0;
udev->dev.power.power_state.event = PM_EVENT_ON;
}
return status;
}
@ -962,6 +932,7 @@ static int autosuspend_check(struct usb_device *udev)
{
int i;
struct usb_interface *intf;
unsigned long suspend_time;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@ -970,9 +941,10 @@ static int autosuspend_check(struct usb_device *udev)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->pm_usage_cnt > 0)
return -EBUSY;
if (!udev->autosuspend_delay)
if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
return -EPERM;
suspend_time = udev->last_busy + udev->autosuspend_delay;
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
@ -988,6 +960,24 @@ static int autosuspend_check(struct usb_device *udev)
}
}
}
/* If everything is okay but the device hasn't been idle for long
* enough, queue a delayed autosuspend request.
*/
if (time_after(suspend_time, jiffies)) {
if (!timer_pending(&udev->autosuspend.timer)) {
/* The value of jiffies may change between the
* time_after() comparison above and the subtraction
* below. That's okay; the system behaves sanely
* when a timer is registered for the present moment
* or for the past.
*/
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
suspend_time - jiffies);
}
return -EAGAIN;
}
return 0;
}
@ -1033,26 +1023,25 @@ static int autosuspend_check(struct usb_device *udev)
*
* This routine can run only in process context.
*/
int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
int i = 0;
struct usb_interface *intf;
struct usb_device *parent = udev->parent;
cancel_delayed_work(&udev->autosuspend);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
if (udev->state == USB_STATE_SUSPENDED)
return 0;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
status = autosuspend_check(udev);
if (status < 0)
return status;
goto done;
}
cancel_delayed_work(&udev->autosuspend);
/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {
@ -1077,6 +1066,7 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
} else if (parent)
usb_autosuspend_device(parent);
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
@ -1109,7 +1099,7 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
*
* This routine can run only in process context.
*/
int usb_resume_both(struct usb_device *udev)
static int usb_resume_both(struct usb_device *udev)
{
int status = 0;
int i;
@ -1117,11 +1107,17 @@ int usb_resume_both(struct usb_device *udev)
struct usb_device *parent = udev->parent;
cancel_delayed_work(&udev->autosuspend);
if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
if (udev->state == USB_STATE_NOTATTACHED) {
status = -ENODEV;
goto done;
}
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
if (udev->auto_pm && udev->autoresume_disabled) {
status = -EPERM;
goto done;
}
if (parent) {
status = usb_autoresume_device(parent);
if (status == 0) {
@ -1167,6 +1163,7 @@ int usb_resume_both(struct usb_device *udev)
}
}
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
@ -1181,20 +1178,34 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
int status = 0;
usb_pm_lock(udev);
udev->auto_pm = 1;
udev->pm_usage_cnt += inc_usage_cnt;
WARN_ON(udev->pm_usage_cnt < 0);
if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
udev->auto_pm = 1;
status = usb_resume_both(udev);
if (udev->state == USB_STATE_SUSPENDED)
status = usb_resume_both(udev);
if (status != 0)
udev->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
udev->autosuspend_delay);
else if (inc_usage_cnt)
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
if (inc_usage_cnt)
udev->last_busy = jiffies;
status = usb_suspend_both(udev, PMSG_SUSPEND);
}
usb_pm_unlock(udev);
return status;
}
/* usb_autosuspend_work - callback routine to autosuspend a USB device */
void usb_autosuspend_work(struct work_struct *work)
{
struct usb_device *udev =
container_of(work, struct usb_device, autosuspend.work);
usb_autopm_do_device(udev, 0);
}
/**
* usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
* @udev: the usb_device to autosuspend
@ -1286,15 +1297,20 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
if (intf->condition == USB_INTERFACE_UNBOUND)
status = -ENODEV;
else {
udev->auto_pm = 1;
intf->pm_usage_cnt += inc_usage_cnt;
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
udev->auto_pm = 1;
status = usb_resume_both(udev);
if (udev->state == USB_STATE_SUSPENDED)
status = usb_resume_both(udev);
if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
udev->autosuspend_delay);
else if (inc_usage_cnt)
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
if (inc_usage_cnt)
udev->last_busy = jiffies;
status = usb_suspend_both(udev, PMSG_SUSPEND);
}
}
usb_pm_unlock(udev);
return status;
@ -1353,11 +1369,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
* or @intf is unbound. A typical example would be a character-device
* driver when its device file is opened.
*
* The routine increments @intf's usage counter. So long as the counter
* is greater than 0, autosuspend will not be allowed for @intf or its
* usb_device. When the driver is finished using @intf it should call
* usb_autopm_put_interface() to decrement the usage counter and queue
* a delayed autosuspend request (if the counter is <= 0).
*
* The routine increments @intf's usage counter. (However if the
* autoresume fails then the counter is re-decremented.) So long as the
* counter is greater than 0, autosuspend will not be allowed for @intf
* or its usb_device. When the driver is finished using @intf it should
* call usb_autopm_put_interface() to decrement the usage counter and
* queue a delayed autosuspend request (if the counter is <= 0).
*
*
* Note that @intf->pm_usage_cnt is owned by the interface driver. The
* core will not change its value other than the increment and decrement
@ -1405,50 +1424,96 @@ int usb_autopm_set_interface(struct usb_interface *intf)
}
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
#else
void usb_autosuspend_work(struct work_struct *work)
{}
#endif /* CONFIG_USB_SUSPEND */
static int usb_suspend(struct device *dev, pm_message_t message)
/**
* usb_external_suspend_device - external suspend of a USB device and its interfaces
* @udev: the usb_device to suspend
* @msg: Power Management message describing this state transition
*
* This routine handles external suspend requests: ones not generated
* internally by a USB driver (autosuspend) but rather coming from the user
* (via sysfs) or the PM core (system sleep). The suspend will be carried
* out regardless of @udev's usage counter or those of its interfaces,
* and regardless of whether or not remote wakeup is enabled. Of course,
* interface drivers still have the option of failing the suspend (if
* there are unsuspended children, for example).
*
* The caller must hold @udev's device lock.
*/
int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
{
int status;
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
usb_pm_lock(udev);
udev->auto_pm = 0;
status = usb_suspend_both(udev, message);
usb_pm_unlock(udev);
} else
status = 0;
usb_pm_lock(udev);
udev->auto_pm = 0;
status = usb_suspend_both(udev, msg);
usb_pm_unlock(udev);
return status;
}
/**
* usb_external_resume_device - external resume of a USB device and its interfaces
* @udev: the usb_device to resume
*
* This routine handles external resume requests: ones not generated
* internally by a USB driver (autoresume) but rather coming from the user
* (via sysfs), the PM core (system resume), or the device itself (remote
* wakeup). @udev's usage counter is unaffected.
*
* The caller must hold @udev's device lock.
*/
int usb_external_resume_device(struct usb_device *udev)
{
int status;
usb_pm_lock(udev);
udev->auto_pm = 0;
status = usb_resume_both(udev);
usb_pm_unlock(udev);
/* Now that the device is awake, we can start trying to autosuspend
* it again. */
if (status == 0)
usb_try_autosuspend_device(udev);
return status;
}
static int usb_suspend(struct device *dev, pm_message_t message)
{
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
return usb_external_suspend_device(to_usb_device(dev), message);
}
static int usb_resume(struct device *dev)
{
int status;
struct usb_device *udev;
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
usb_pm_lock(udev);
udev->auto_pm = 0;
status = usb_resume_both(udev);
usb_pm_unlock(udev);
/* Rebind drivers that had no suspend method? */
} else
status = 0;
return status;
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
udev = to_usb_device(dev);
if (udev->autoresume_disabled)
return -EPERM;
return usb_external_resume_device(udev);
}
#else
#define usb_suspend NULL
#define usb_resume NULL
#endif /* CONFIG_PM */
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
#ifdef CONFIG_PM
.suspend = usb_suspend,
.resume = usb_resume,
#endif
};

View File

@ -37,6 +37,7 @@
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/usb.h>
@ -544,6 +545,8 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
unsigned long flags;
char buffer[4]; /* Any root hubs with > 31 ports? */
if (unlikely(!hcd->rh_registered))
return;
if (!hcd->uses_new_polling && !hcd->status_urb)
return;
@ -1296,14 +1299,26 @@ int hcd_bus_resume (struct usb_bus *bus)
return status;
}
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
{
struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
struct usb_device *udev = hcd->self.root_hub;
usb_lock_device(udev);
usb_mark_last_busy(udev);
usb_external_resume_device(udev);
usb_unlock_device(udev);
}
/**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub
*
* The USB host controller calls this function when its root hub is
* suspended (with the remote wakeup feature enabled) and a remote
* wakeup request is received. It queues a request for khubd to
* resume the root hub (that is, manage its downstream ports again).
* wakeup request is received. The routine submits a workqueue request
* to resume the root hub (that is, manage its downstream ports again).
*/
void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
{
@ -1311,7 +1326,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered)
usb_resume_root_hub (hcd->self.root_hub);
queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
@ -1500,6 +1515,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_PM
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@ -1666,16 +1684,20 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
#ifdef CONFIG_PM
flush_workqueue(ksuspend_usb_wq);
#endif
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
hcd->poll_rh = 0;
del_timer_sync(&hcd->rh_timer);
hcd->driver->stop(hcd);
hcd->state = HC_STATE_HALT;
hcd->poll_rh = 0;
del_timer_sync(&hcd->rh_timer);
if (hcd->irq >= 0)
free_irq(hcd->irq, hcd);
usb_deregister_bus(&hcd->self);

View File

@ -68,6 +68,9 @@ struct usb_hcd {
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
#ifdef CONFIG_PM
struct work_struct wakeup_work; /* for remote wakeup */
#endif
/*
* hardware info/state

View File

@ -1367,11 +1367,15 @@ int usb_new_device(struct usb_device *udev)
}
#endif
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Register the device. The device driver is responsible
* for adding the device files to usbfs and sysfs and for
* configuring the device.
* for adding the device files to sysfs and for configuring
* the device.
*/
err = device_add (&udev->dev);
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
@ -1855,12 +1859,8 @@ static int remote_wakeup(struct usb_device *udev)
usb_lock_device(udev);
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
status = usb_autoresume_device(udev);
/* Give the interface drivers a chance to do something,
* then autosuspend the device again. */
if (status == 0)
usb_autosuspend_device(udev);
usb_mark_last_busy(udev);
status = usb_external_resume_device(udev);
}
usb_unlock_device(udev);
return status;
@ -1984,13 +1984,6 @@ static inline int remote_wakeup(struct usb_device *udev)
#define hub_resume NULL
#endif
void usb_resume_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
kick_khubd(hub);
}
/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
*

View File

@ -662,7 +662,7 @@ static void usbfs_add_device(struct usb_device *dev)
sprintf (name, "%03d", dev->devnum);
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbfs_dentry, dev,
&usbfs_device_file_operations,
&usbdev_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
err ("error creating usbfs device entry");

View File

@ -412,10 +412,24 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0;
/*
* Some systems need to revert to PIO when DMA is temporarily
* unavailable. For their sakes, both transfer_buffer and
* transfer_dma are set when possible. However this can only
* work on systems without HIGHMEM, since DMA buffers located
* in high memory are not directly addressable by the CPU for
* PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
* to prevent stale pointers and to help spot bugs.
*/
if (dma) {
/* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
#ifdef CONFIG_HIGHMEM
io->urbs[i]->transfer_buffer = NULL;
#else
io->urbs[i]->transfer_buffer =
page_address(sg[i].page) + sg[i].offset;
#endif
} else {
/* hc may use _only_ transfer_buffer */
io->urbs [i]->transfer_buffer =
@ -1305,7 +1319,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
static void release_interface(struct device *dev)
void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@ -1315,6 +1329,67 @@ static void release_interface(struct device *dev)
kfree(intf);
}
#ifdef CONFIG_HOTPLUG
static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_device *usb_dev;
struct usb_interface *intf;
struct usb_host_interface *alt;
int i = 0;
int length = 0;
if (!dev)
return -ENODEV;
/* driver is often null here; dev_dbg() would oops */
pr_debug ("usb %s: uevent\n", dev->bus_id);
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
alt = intf->cur_altsetting;
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
envp[i] = NULL;
return 0;
}
#else
static int usb_if_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */
struct device_type usb_if_device_type = {
.name = "usb_interface",
.release = usb_release_interface,
.uevent = usb_if_uevent,
};
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@ -1478,8 +1553,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.dma_mask = dev->dev.dma_mask;
intf->dev.release = release_interface;
device_initialize (&intf->dev);
mark_quiesced(intf);
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",

View File

@ -42,7 +42,7 @@ static void usb_autosuspend_quirk(struct usb_device *udev)
{
#ifdef CONFIG_USB_SUSPEND
/* disable autosuspend, but allow the user to re-enable it via sysfs */
udev->autosuspend_delay = 0;
udev->autosuspend_disabled = 1;
#endif
}

View File

@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/usb.h>
#include "usb.h"
@ -116,6 +117,16 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
static ssize_t
show_busnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->bus->busnum);
}
static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL);
static ssize_t
show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
{
@ -165,7 +176,7 @@ show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ);
return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ);
}
static ssize_t
@ -173,38 +184,114 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
unsigned value, old;
int value;
if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ)
if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
value <= - INT_MAX/HZ)
return -EINVAL;
value *= HZ;
old = udev->autosuspend_delay;
udev->autosuspend_delay = value;
if (value > 0 && old == 0)
if (value >= 0)
usb_try_autosuspend_device(udev);
else {
if (usb_autoresume_device(udev) == 0)
usb_autosuspend_device(udev);
}
return count;
}
static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
show_autosuspend, set_autosuspend);
static const char on_string[] = "on";
static const char auto_string[] = "auto";
static const char suspend_string[] = "suspend";
static ssize_t
show_level(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
const char *p = auto_string;
if (udev->state == USB_STATE_SUSPENDED) {
if (udev->autoresume_disabled)
p = suspend_string;
} else {
if (udev->autosuspend_disabled)
p = on_string;
}
return sprintf(buf, "%s\n", p);
}
static ssize_t
set_level(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int len = count;
char *cp;
int rc = 0;
cp = memchr(buf, '\n', count);
if (cp)
len = cp - buf;
usb_lock_device(udev);
/* Setting the flags without calling usb_pm_lock is a subject to
* races, but who cares...
*/
if (len == sizeof on_string - 1 &&
strncmp(buf, on_string, len) == 0) {
udev->autosuspend_disabled = 1;
udev->autoresume_disabled = 0;
rc = usb_external_resume_device(udev);
} else if (len == sizeof auto_string - 1 &&
strncmp(buf, auto_string, len) == 0) {
udev->autosuspend_disabled = 0;
udev->autoresume_disabled = 0;
rc = usb_external_resume_device(udev);
} else if (len == sizeof suspend_string - 1 &&
strncmp(buf, suspend_string, len) == 0) {
udev->autosuspend_disabled = 0;
udev->autoresume_disabled = 1;
rc = usb_external_suspend_device(udev, PMSG_SUSPEND);
} else
rc = -EINVAL;
usb_unlock_device(udev);
return (rc < 0 ? rc : count);
}
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
static char power_group[] = "power";
static int add_power_attributes(struct device *dev)
{
int rc = 0;
if (is_usb_device(dev))
if (is_usb_device(dev)) {
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_autosuspend.attr,
power_group);
if (rc == 0)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
}
return rc;
}
static void remove_power_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_autosuspend.attr,
power_group);
@ -270,6 +357,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bNumConfigurations.attr,
&dev_attr_bMaxPacketSize0.attr,
&dev_attr_speed.attr,
&dev_attr_busnum.attr,
&dev_attr_devnum.attr,
&dev_attr_version.attr,
&dev_attr_maxchild.attr,

View File

@ -49,12 +49,13 @@ const char *usbcore_name = "usbcore";
static int nousb; /* Disable USB when built into kernel image */
struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
/* Workqueue for autosuspend and for remote wakeup of root hubs */
struct workqueue_struct *ksuspend_usb_wq;
#ifdef CONFIG_USB_SUSPEND
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644);
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
#else
@ -196,6 +197,11 @@ static void usb_release_dev(struct device *dev)
kfree(udev);
}
struct device_type usb_device_type = {
.name = "usb_device",
.release = usb_release_dev,
};
#ifdef CONFIG_PM
static int ksuspend_usb_init(void)
@ -211,27 +217,6 @@ static void ksuspend_usb_cleanup(void)
destroy_workqueue(ksuspend_usb_wq);
}
#ifdef CONFIG_USB_SUSPEND
/* usb_autosuspend_work - callback routine to autosuspend a USB device */
static void usb_autosuspend_work(struct work_struct *work)
{
struct usb_device *udev =
container_of(work, struct usb_device, autosuspend.work);
usb_pm_lock(udev);
udev->auto_pm = 1;
usb_suspend_both(udev, PMSG_SUSPEND);
usb_pm_unlock(udev);
}
#else
static void usb_autosuspend_work(struct work_struct *work)
{}
#endif /* CONFIG_USB_SUSPEND */
#else
#define ksuspend_usb_init() 0
@ -267,13 +252,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.dma_mask = bus->controller->dma_mask;
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
/* This magic assignment distinguishes devices from interfaces */
dev->dev.platform_data = &usb_generic_driver;
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@ -902,9 +884,9 @@ static int __init usb_init(void)
retval = usb_register(&usbfs_driver);
if (retval)
goto driver_register_failed;
retval = usbdev_init();
retval = usb_devio_init();
if (retval)
goto usbdevice_init_failed;
goto usb_devio_init_failed;
retval = usbfs_init();
if (retval)
goto fs_init_failed;
@ -919,8 +901,8 @@ static int __init usb_init(void)
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usbdev_cleanup();
usbdevice_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
@ -947,7 +929,7 @@ static void __exit usb_exit(void)
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
usbdev_cleanup();
usb_devio_cleanup();
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);

View File

@ -21,7 +21,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_resume_root_hub(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
const struct usb_device_id *id);
@ -34,10 +33,12 @@ extern void usb_host_cleanup(void);
#ifdef CONFIG_PM
extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
extern int usb_resume_both(struct usb_device *udev);
extern void usb_autosuspend_work(struct work_struct *work);
extern int usb_port_suspend(struct usb_device *dev);
extern int usb_port_resume(struct usb_device *dev);
extern int usb_external_suspend_device(struct usb_device *udev,
pm_message_t msg);
extern int usb_external_resume_device(struct usb_device *udev);
static inline void usb_pm_lock(struct usb_device *udev)
{
@ -51,11 +52,6 @@ static inline void usb_pm_unlock(struct usb_device *udev)
#else
#define usb_suspend_both(udev, msg) 0
static inline int usb_resume_both(struct usb_device *udev)
{
return 0;
}
#define usb_port_suspend(dev) 0
#define usb_port_resume(dev) 0
static inline void usb_pm_lock(struct usb_device *udev) {}
@ -82,15 +78,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
extern struct device_type usb_device_type;
extern struct device_type usb_if_device_type;
extern struct usb_device_driver usb_generic_driver;
/* Here's how we tell apart devices and interfaces. Luckily there's
* no such thing as a platform USB device, so we can steal the use
* of the platform_data field. */
static inline int is_usb_device(const struct device *dev)
{
return dev->platform_data == &usb_generic_driver;
return dev->type == &usb_device_type;
}
/* Do the same for device drivers and interface drivers. */
@ -126,11 +120,11 @@ extern const char *usbcore_name;
extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
extern const struct file_operations usbfs_devices_fops;
extern const struct file_operations usbfs_device_file_operations;
extern const struct file_operations usbdev_file_operations;
extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void);
extern void usbdev_cleanup(void);
extern int usb_devio_init(void);
extern void usb_devio_cleanup(void);
struct dev_state {
struct list_head list; /* state list */

View File

@ -68,6 +68,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
select USB_GADGET_DUALSPEED
help
Some of Freescale PowerPC processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
The number of programmable endpoints is different through
SOC revisions.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "fsl_usb2_udc" and force
all gadget drivers to also be dynamically linked.
config USB_FSL_USB2
tristate
depends on USB_GADGET_FSL_USB2
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_NET2280
boolean "NetChip 228x"
depends on PCI
@ -370,6 +391,7 @@ config USB_GADGETFS
config USB_FILE_STORAGE
tristate "File-backed Storage Gadget"
depends on BLOCK
help
The File-backed Storage Gadget acts as a USB Mass Storage
disk drive. As its storage repository it can use a regular

View File

@ -8,6 +8,7 @@ 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
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
#
# USB gadget drivers

View File

@ -282,6 +282,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_FSL_USB2
#define DEV_CONFIG_CDC
#endif
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@ -1735,7 +1738,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
defer_kevent (dev, WORK_RX_MEMORY);
if (retval) {
DEBUG (dev, "rx submit --> %d\n", retval);
dev_kfree_skb_any (skb);
if (skb)
dev_kfree_skb_any(skb);
spin_lock(&dev->req_lock);
list_add (&req->list, &dev->rx_reqs);
spin_unlock(&dev->req_lock);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,579 @@
/*
* Freescale USB device/endpoint management registers
*/
#ifndef __FSL_USB2_UDC_H
#define __FSL_USB2_UDC_H
/* ### define USB registers here
*/
#define USB_MAX_CTRL_PAYLOAD 64
#define USB_DR_SYS_OFFSET 0x400
/* USB DR device mode registers (Little Endian) */
struct usb_dr_device {
/* Capability register */
u8 res1[256];
u16 caplength; /* Capability Register Length */
u16 hciversion; /* Host Controller Interface Version */
u32 hcsparams; /* Host Controller Structual Parameters */
u32 hccparams; /* Host Controller Capability Parameters */
u8 res2[20];
u32 dciversion; /* Device Controller Interface Version */
u32 dccparams; /* Device Controller Capability Parameters */
u8 res3[24];
/* Operation register */
u32 usbcmd; /* USB Command Register */
u32 usbsts; /* USB Status Register */
u32 usbintr; /* USB Interrupt Enable Register */
u32 frindex; /* Frame Index Register */
u8 res4[4];
u32 deviceaddr; /* Device Address */
u32 endpointlistaddr; /* Endpoint List Address Register */
u8 res5[4];
u32 burstsize; /* Master Interface Data Burst Size Register */
u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
u8 res6[24];
u32 configflag; /* Configure Flag Register */
u32 portsc1; /* Port 1 Status and Control Register */
u8 res7[28];
u32 otgsc; /* On-The-Go Status and Control */
u32 usbmode; /* USB Mode Register */
u32 endptsetupstat; /* Endpoint Setup Status Register */
u32 endpointprime; /* Endpoint Initialization Register */
u32 endptflush; /* Endpoint Flush Register */
u32 endptstatus; /* Endpoint Status Register */
u32 endptcomplete; /* Endpoint Complete Register */
u32 endptctrl[6]; /* Endpoint Control Registers */
};
/* USB DR host mode registers (Little Endian) */
struct usb_dr_host {
/* Capability register */
u8 res1[256];
u16 caplength; /* Capability Register Length */
u16 hciversion; /* Host Controller Interface Version */
u32 hcsparams; /* Host Controller Structual Parameters */
u32 hccparams; /* Host Controller Capability Parameters */
u8 res2[20];
u32 dciversion; /* Device Controller Interface Version */
u32 dccparams; /* Device Controller Capability Parameters */
u8 res3[24];
/* Operation register */
u32 usbcmd; /* USB Command Register */
u32 usbsts; /* USB Status Register */
u32 usbintr; /* USB Interrupt Enable Register */
u32 frindex; /* Frame Index Register */
u8 res4[4];
u32 periodiclistbase; /* Periodic Frame List Base Address Register */
u32 asynclistaddr; /* Current Asynchronous List Address Register */
u8 res5[4];
u32 burstsize; /* Master Interface Data Burst Size Register */
u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
u8 res6[24];
u32 configflag; /* Configure Flag Register */
u32 portsc1; /* Port 1 Status and Control Register */
u8 res7[28];
u32 otgsc; /* On-The-Go Status and Control */
u32 usbmode; /* USB Mode Register */
u32 endptsetupstat; /* Endpoint Setup Status Register */
u32 endpointprime; /* Endpoint Initialization Register */
u32 endptflush; /* Endpoint Flush Register */
u32 endptstatus; /* Endpoint Status Register */
u32 endptcomplete; /* Endpoint Complete Register */
u32 endptctrl[6]; /* Endpoint Control Registers */
};
/* non-EHCI USB system interface registers (Big Endian) */
struct usb_sys_interface {
u32 snoop1;
u32 snoop2;
u32 age_cnt_thresh; /* Age Count Threshold Register */
u32 pri_ctrl; /* Priority Control Register */
u32 si_ctrl; /* System Interface Control Register */
u8 res[236];
u32 control; /* General Purpose Control Register */
};
/* ep0 transfer state */
#define WAIT_FOR_SETUP 0
#define DATA_STATE_XMIT 1
#define DATA_STATE_NEED_ZLP 2
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
/* Frame Index Register Bit Masks */
#define USB_FRINDEX_MASKS 0x3fff
/* USB CMD Register Bit Masks */
#define USB_CMD_RUN_STOP 0x00000001
#define USB_CMD_CTRL_RESET 0x00000002
#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010
#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020
#define USB_CMD_INT_AA_DOORBELL 0x00000040
#define USB_CMD_ASP 0x00000300
#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800
#define USB_CMD_SUTW 0x00002000
#define USB_CMD_ATDTW 0x00004000
#define USB_CMD_ITC 0x00FF0000
/* bit 15,3,2 are frame list size */
#define USB_CMD_FRAME_SIZE_1024 0x00000000
#define USB_CMD_FRAME_SIZE_512 0x00000004
#define USB_CMD_FRAME_SIZE_256 0x00000008
#define USB_CMD_FRAME_SIZE_128 0x0000000C
#define USB_CMD_FRAME_SIZE_64 0x00008000
#define USB_CMD_FRAME_SIZE_32 0x00008004
#define USB_CMD_FRAME_SIZE_16 0x00008008
#define USB_CMD_FRAME_SIZE_8 0x0000800C
/* bit 9-8 are async schedule park mode count */
#define USB_CMD_ASP_00 0x00000000
#define USB_CMD_ASP_01 0x00000100
#define USB_CMD_ASP_10 0x00000200
#define USB_CMD_ASP_11 0x00000300
#define USB_CMD_ASP_BIT_POS 8
/* bit 23-16 are interrupt threshold control */
#define USB_CMD_ITC_NO_THRESHOLD 0x00000000
#define USB_CMD_ITC_1_MICRO_FRM 0x00010000
#define USB_CMD_ITC_2_MICRO_FRM 0x00020000
#define USB_CMD_ITC_4_MICRO_FRM 0x00040000
#define USB_CMD_ITC_8_MICRO_FRM 0x00080000
#define USB_CMD_ITC_16_MICRO_FRM 0x00100000
#define USB_CMD_ITC_32_MICRO_FRM 0x00200000
#define USB_CMD_ITC_64_MICRO_FRM 0x00400000
#define USB_CMD_ITC_BIT_POS 16
/* USB STS Register Bit Masks */
#define USB_STS_INT 0x00000001
#define USB_STS_ERR 0x00000002
#define USB_STS_PORT_CHANGE 0x00000004
#define USB_STS_FRM_LST_ROLL 0x00000008
#define USB_STS_SYS_ERR 0x00000010
#define USB_STS_IAA 0x00000020
#define USB_STS_RESET 0x00000040
#define USB_STS_SOF 0x00000080
#define USB_STS_SUSPEND 0x00000100
#define USB_STS_HC_HALTED 0x00001000
#define USB_STS_RCL 0x00002000
#define USB_STS_PERIODIC_SCHEDULE 0x00004000
#define USB_STS_ASYNC_SCHEDULE 0x00008000
/* USB INTR Register Bit Masks */
#define USB_INTR_INT_EN 0x00000001
#define USB_INTR_ERR_INT_EN 0x00000002
#define USB_INTR_PTC_DETECT_EN 0x00000004
#define USB_INTR_FRM_LST_ROLL_EN 0x00000008
#define USB_INTR_SYS_ERR_EN 0x00000010
#define USB_INTR_ASYN_ADV_EN 0x00000020
#define USB_INTR_RESET_EN 0x00000040
#define USB_INTR_SOF_EN 0x00000080
#define USB_INTR_DEVICE_SUSPEND 0x00000100
/* Device Address bit masks */
#define USB_DEVICE_ADDRESS_MASK 0xFE000000
#define USB_DEVICE_ADDRESS_BIT_POS 25
/* endpoint list address bit masks */
#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
/* PORTSCX Register Bit Masks */
#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001
#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002
#define PORTSCX_PORT_ENABLE 0x00000004
#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008
#define PORTSCX_OVER_CURRENT_ACT 0x00000010
#define PORTSCX_OVER_CURRENT_CHG 0x00000020
#define PORTSCX_PORT_FORCE_RESUME 0x00000040
#define PORTSCX_PORT_SUSPEND 0x00000080
#define PORTSCX_PORT_RESET 0x00000100
#define PORTSCX_LINE_STATUS_BITS 0x00000C00
#define PORTSCX_PORT_POWER 0x00001000
#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000
#define PORTSCX_PORT_TEST_CTRL 0x000F0000
#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000
#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000
#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000
#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000
#define PORTSCX_PORT_FORCE_FULL_SPEED 0x01000000
#define PORTSCX_PORT_SPEED_MASK 0x0C000000
#define PORTSCX_PORT_WIDTH 0x10000000
#define PORTSCX_PHY_TYPE_SEL 0xC0000000
/* bit 11-10 are line status */
#define PORTSCX_LINE_STATUS_SE0 0x00000000
#define PORTSCX_LINE_STATUS_JSTATE 0x00000400
#define PORTSCX_LINE_STATUS_KSTATE 0x00000800
#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00
#define PORTSCX_LINE_STATUS_BIT_POS 10
/* bit 15-14 are port indicator control */
#define PORTSCX_PIC_OFF 0x00000000
#define PORTSCX_PIC_AMBER 0x00004000
#define PORTSCX_PIC_GREEN 0x00008000
#define PORTSCX_PIC_UNDEF 0x0000C000
#define PORTSCX_PIC_BIT_POS 14
/* bit 19-16 are port test control */
#define PORTSCX_PTC_DISABLE 0x00000000
#define PORTSCX_PTC_JSTATE 0x00010000
#define PORTSCX_PTC_KSTATE 0x00020000
#define PORTSCX_PTC_SEQNAK 0x00030000
#define PORTSCX_PTC_PACKET 0x00040000
#define PORTSCX_PTC_FORCE_EN 0x00050000
#define PORTSCX_PTC_BIT_POS 16
/* bit 27-26 are port speed */
#define PORTSCX_PORT_SPEED_FULL 0x00000000
#define PORTSCX_PORT_SPEED_LOW 0x04000000
#define PORTSCX_PORT_SPEED_HIGH 0x08000000
#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000
#define PORTSCX_SPEED_BIT_POS 26
/* bit 28 is parallel transceiver width for UTMI interface */
#define PORTSCX_PTW 0x10000000
#define PORTSCX_PTW_8BIT 0x00000000
#define PORTSCX_PTW_16BIT 0x10000000
/* bit 31-30 are port transceiver select */
#define PORTSCX_PTS_UTMI 0x00000000
#define PORTSCX_PTS_ULPI 0x80000000
#define PORTSCX_PTS_FSLS 0xC0000000
#define PORTSCX_PTS_BIT_POS 30
/* otgsc Register Bit Masks */
#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001
#define OTGSC_CTRL_VUSB_CHARGE 0x00000002
#define OTGSC_CTRL_OTG_TERM 0x00000008
#define OTGSC_CTRL_DATA_PULSING 0x00000010
#define OTGSC_STS_USB_ID 0x00000100
#define OTGSC_STS_A_VBUS_VALID 0x00000200
#define OTGSC_STS_A_SESSION_VALID 0x00000400
#define OTGSC_STS_B_SESSION_VALID 0x00000800
#define OTGSC_STS_B_SESSION_END 0x00001000
#define OTGSC_STS_1MS_TOGGLE 0x00002000
#define OTGSC_STS_DATA_PULSING 0x00004000
#define OTGSC_INTSTS_USB_ID 0x00010000
#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000
#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000
#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000
#define OTGSC_INTSTS_B_SESSION_END 0x00100000
#define OTGSC_INTSTS_1MS 0x00200000
#define OTGSC_INTSTS_DATA_PULSING 0x00400000
#define OTGSC_INTR_USB_ID 0x01000000
#define OTGSC_INTR_A_VBUS_VALID 0x02000000
#define OTGSC_INTR_A_SESSION_VALID 0x04000000
#define OTGSC_INTR_B_SESSION_VALID 0x08000000
#define OTGSC_INTR_B_SESSION_END 0x10000000
#define OTGSC_INTR_1MS_TIMER 0x20000000
#define OTGSC_INTR_DATA_PULSING 0x40000000
/* USB MODE Register Bit Masks */
#define USB_MODE_CTRL_MODE_IDLE 0x00000000
#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
#define USB_MODE_CTRL_MODE_HOST 0x00000003
#define USB_MODE_CTRL_MODE_RSV 0x00000001
#define USB_MODE_SETUP_LOCK_OFF 0x00000008
#define USB_MODE_STREAM_DISABLE 0x00000010
/* Endpoint Flush Register */
#define EPFLUSH_TX_OFFSET 0x00010000
#define EPFLUSH_RX_OFFSET 0x00000000
/* Endpoint Setup Status bit masks */
#define EP_SETUP_STATUS_MASK 0x0000003F
#define EP_SETUP_STATUS_EP0 0x00000001
/* ENDPOINTCTRLx Register Bit Masks */
#define EPCTRL_TX_ENABLE 0x00800000
#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */
#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */
#define EPCTRL_TX_TYPE 0x000C0000
#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */
#define EPCTRL_TX_EP_STALL 0x00010000
#define EPCTRL_RX_ENABLE 0x00000080
#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */
#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */
#define EPCTRL_RX_TYPE 0x0000000C
#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */
#define EPCTRL_RX_EP_STALL 0x00000001
/* bit 19-18 and 3-2 are endpoint type */
#define EPCTRL_EP_TYPE_CONTROL 0
#define EPCTRL_EP_TYPE_ISO 1
#define EPCTRL_EP_TYPE_BULK 2
#define EPCTRL_EP_TYPE_INTERRUPT 3
#define EPCTRL_TX_EP_TYPE_SHIFT 18
#define EPCTRL_RX_EP_TYPE_SHIFT 2
/* SNOOPn Register Bit Masks */
#define SNOOP_ADDRESS_MASK 0xFFFFF000
#define SNOOP_SIZE_ZERO 0x00 /* snooping disable */
#define SNOOP_SIZE_4KB 0x0B /* 4KB snoop size */
#define SNOOP_SIZE_8KB 0x0C
#define SNOOP_SIZE_16KB 0x0D
#define SNOOP_SIZE_32KB 0x0E
#define SNOOP_SIZE_64KB 0x0F
#define SNOOP_SIZE_128KB 0x10
#define SNOOP_SIZE_256KB 0x11
#define SNOOP_SIZE_512KB 0x12
#define SNOOP_SIZE_1MB 0x13
#define SNOOP_SIZE_2MB 0x14
#define SNOOP_SIZE_4MB 0x15
#define SNOOP_SIZE_8MB 0x16
#define SNOOP_SIZE_16MB 0x17
#define SNOOP_SIZE_32MB 0x18
#define SNOOP_SIZE_64MB 0x19
#define SNOOP_SIZE_128MB 0x1A
#define SNOOP_SIZE_256MB 0x1B
#define SNOOP_SIZE_512MB 0x1C
#define SNOOP_SIZE_1GB 0x1D
#define SNOOP_SIZE_2GB 0x1E /* 2GB snoop size */
/* pri_ctrl Register Bit Masks */
#define PRI_CTRL_PRI_LVL1 0x0000000C
#define PRI_CTRL_PRI_LVL0 0x00000003
/* si_ctrl Register Bit Masks */
#define SI_CTRL_ERR_DISABLE 0x00000010
#define SI_CTRL_IDRC_DISABLE 0x00000008
#define SI_CTRL_RD_SAFE_EN 0x00000004
#define SI_CTRL_RD_PREFETCH_DISABLE 0x00000002
#define SI_CTRL_RD_PREFEFETCH_VAL 0x00000001
/* control Register Bit Masks */
#define USB_CTRL_IOENB 0x00000004
#define USB_CTRL_ULPI_INT0EN 0x00000001
/* Endpoint Queue Head data struct
* Rem: all the variables of qh are LittleEndian Mode
* and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
*/
struct ep_queue_head {
u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
and IOS(15) */
u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
MultO(11-10), STS (7-0) */
u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
u32 res1;
u8 setup_buffer[8]; /* Setup data 8 bytes */
u32 res2[4];
};
/* Endpoint Queue Head Bit Masks */
#define EP_QUEUE_HEAD_MULT_POS 30
#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
#define EP_QUEUE_HEAD_IOS 0x00008000
#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
#define EP_QUEUE_HEAD_IOC 0x00008000
#define EP_QUEUE_HEAD_MULTO 0x00000C00
#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
#define EP_QUEUE_FRINDEX_MASK 0x000007FF
#define EP_MAX_LENGTH_TRANSFER 0x4000
/* Endpoint Transfer Descriptor data struct */
/* Rem: all the variables of td are LittleEndian Mode */
struct ep_td_struct {
u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
indicate invalid */
u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
MultO(11-10), STS (7-0) */
u32 buff_ptr0; /* Buffer pointer Page 0 */
u32 buff_ptr1; /* Buffer pointer Page 1 */
u32 buff_ptr2; /* Buffer pointer Page 2 */
u32 buff_ptr3; /* Buffer pointer Page 3 */
u32 buff_ptr4; /* Buffer pointer Page 4 */
u32 res;
/* 32 bytes */
dma_addr_t td_dma; /* dma address for this td */
/* virtual address of next td specified in next_td_ptr */
struct ep_td_struct *next_td_virt;
};
/* Endpoint Transfer Descriptor bit Masks */
#define DTD_NEXT_TERMINATE 0x00000001
#define DTD_IOC 0x00008000
#define DTD_STATUS_ACTIVE 0x00000080
#define DTD_STATUS_HALTED 0x00000040
#define DTD_STATUS_DATA_BUFF_ERR 0x00000020
#define DTD_STATUS_TRANSACTION_ERR 0x00000008
#define DTD_RESERVED_FIELDS 0x80007300
#define DTD_ADDR_MASK 0xFFFFFFE0
#define DTD_PACKET_SIZE 0x7FFF0000
#define DTD_LENGTH_BIT_POS 16
#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
DTD_STATUS_DATA_BUFF_ERR | \
DTD_STATUS_TRANSACTION_ERR)
/* Alignment requirements; must be a power of two */
#define DTD_ALIGNMENT 0x20
#define QH_ALIGNMENT 2048
/* Controller dma boundary */
#define UDC_DMA_BOUNDARY 0x1000
/* -----------------------------------------------------------------------*/
/* ##### enum data
*/
typedef enum {
e_ULPI,
e_UTMI_8BIT,
e_UTMI_16BIT,
e_SERIAL
} e_PhyInterface;
/*-------------------------------------------------------------------------*/
/* ### driver private data
*/
struct fsl_req {
struct usb_request req;
struct list_head queue;
/* ep_queue() func will add
a request->queue into a udc_ep->queue 'd tail */
struct fsl_ep *ep;
unsigned mapped:1;
struct ep_td_struct *head, *tail; /* For dTD List
cpu endian Virtual addr */
unsigned int dtd_count;
};
#define REQ_UNCOMPLETE 1
struct fsl_ep {
struct usb_ep ep;
struct list_head queue;
struct fsl_udc *udc;
struct ep_queue_head *qh;
const struct usb_endpoint_descriptor *desc;
struct usb_gadget *gadget;
char name[14];
unsigned stopped:1;
};
#define EP_DIR_IN 1
#define EP_DIR_OUT 0
struct fsl_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct fsl_ep *eps;
unsigned int max_ep;
unsigned int irq;
struct usb_ctrlrequest local_setup_buff;
spinlock_t lock;
struct otg_transceiver *transceiver;
unsigned softconnect:1;
unsigned vbus_active:1;
unsigned stopped:1;
unsigned remote_wakeup:1;
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
struct fsl_req *status_req; /* ep0 status request */
struct dma_pool *td_pool; /* dma pool for DTD */
enum fsl_usb2_phy_modes phy_mode;
size_t ep_qh_size; /* size after alignment adjustment*/
dma_addr_t ep_qh_dma; /* dma address of QH */
u32 max_pipes; /* Device max pipes */
u32 max_use_endpts; /* Max endpointes to be used */
u32 bus_reset; /* Device is bus reseting */
u32 resume_state; /* USB state to resume */
u32 usb_state; /* USB current state */
u32 usb_next_state; /* USB next state */
u32 ep0_state; /* Endpoint zero state */
u32 ep0_dir; /* Endpoint zero direction: can be
USB_DIR_IN or USB_DIR_OUT */
u32 usb_sof_count; /* SOF count */
u32 errors; /* USB ERRORs count */
u8 device_address; /* Device USB address */
struct completion *done; /* to make sure release() is done */
};
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
__FUNCTION__, ## args)
#else
#define DBG(fmt, args...) do{}while(0)
#endif
#if 0
static void dump_msg(const char *label, const u8 * buf, unsigned int length)
{
unsigned int start, num, i;
char line[52], *p;
if (length >= 512)
return;
DBG("%s, length %u:\n", label, length);
start = 0;
while (length > 0) {
num = min(length, 16u);
p = line;
for (i = 0; i < num; ++i) {
if (i == 8)
*p++ = ' ';
sprintf(p, " %02x", buf[i]);
p += 3;
}
*p = 0;
printk(KERN_DEBUG "%6x: %s\n", start, line);
buf += num;
start += num;
length -= num;
}
}
#endif
#ifdef VERBOSE
#define VDBG DBG
#else
#define VDBG(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)
/*-------------------------------------------------------------------------*/
/* ### Add board specific defines here
*/
/*
* ### pipe direction macro from device view
*/
#define USB_RECV 0 /* OUT EP */
#define USB_SEND 1 /* IN EP */
/*
* ### internal used help routines.
*/
#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF)
#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
USB_DIR_IN ):((EP)->desc->bEndpointAddress \
& USB_DIR_IN)==USB_DIR_IN)
#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \
&udc->eps[pipe])
#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \
* 2 + ((windex & USB_DIR_IN) ? 1 : 0))
#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
#endif

View File

@ -99,6 +99,12 @@
#define gadget_is_imx(g) 0
#endif
#ifdef CONFIG_USB_GADGET_FSL_USB2
#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name)
#else
#define gadget_is_fsl_usb2(g) 0
#endif
/* Mentor high speed function controller */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
@ -177,5 +183,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x17;
else if (gadget_is_husb2dev(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
return -ENOENT;
}

View File

@ -71,7 +71,7 @@
* by the host to interact with this device, and allocates endpoints to
* the different protocol interfaces. The controller driver virtualizes
* usb hardware so that the gadget drivers will be more portable.
*
*
* This UDC hardware wants to implement a bit too much USB protocol, so
* it constrains the sorts of USB configuration change events that work.
* The errata for these chips are misleading; some "fixed" bugs from
@ -141,7 +141,7 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
#endif
/* ---------------------------------------------------------------------------
* endpoint related parts of the api to the usb controller hardware,
* endpoint related parts of the api to the usb controller hardware,
* used by gadget driver; and the inner talker-to-hardware core.
* ---------------------------------------------------------------------------
*/
@ -293,7 +293,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
#ifdef USE_DMA
/* for (some) bulk and ISO endpoints, try to get a DMA channel and
* bind it to the endpoint. otherwise use PIO.
* bind it to the endpoint. otherwise use PIO.
*/
switch (ep->bmAttributes) {
case USB_ENDPOINT_XFER_ISOC:
@ -304,7 +304,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
if (!use_dma || !ep->reg_drcmr)
break;
ep->dma = pxa_request_dma ((char *)_ep->name,
(le16_to_cpu (desc->wMaxPacketSize) > 64)
(le16_to_cpu (desc->wMaxPacketSize) > 64)
? DMA_PRIO_MEDIUM /* some iso */
: DMA_PRIO_LOW,
dma_nodesc_handler, ep);
@ -361,7 +361,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
*/
/*
* pxa2xx_ep_alloc_request - allocate a request data structure
* pxa2xx_ep_alloc_request - allocate a request data structure
*/
static struct usb_request *
pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
@ -378,7 +378,7 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
/*
* pxa2xx_ep_free_request - deallocate a request data structure
* pxa2xx_ep_free_request - deallocate a request data structure
*/
static void
pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
@ -1031,7 +1031,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/*
* nuke - dequeue ALL requests
* nuke - dequeue ALL requests
*/
static void nuke(struct pxa2xx_ep *ep, int status)
{
@ -1136,16 +1136,16 @@ static int pxa2xx_ep_set_halt(struct usb_ep *_ep, int value)
ep->dev->req_pending = 0;
ep->dev->ep0state = EP0_STALL;
/* and bulk/intr endpoints like dropping stalls too */
} else {
unsigned i;
for (i = 0; i < 1000; i += 20) {
if (*ep->reg_udccs & UDCCS_BI_SST)
break;
udelay(20);
}
}
local_irq_restore(flags);
/* and bulk/intr endpoints like dropping stalls too */
} else {
unsigned i;
for (i = 0; i < 1000; i += 20) {
if (*ep->reg_udccs & UDCCS_BI_SST)
break;
udelay(20);
}
}
local_irq_restore(flags);
DBG(DBG_VERBOSE, "%s halt\n", _ep->name);
return 0;
@ -1216,7 +1216,7 @@ static struct usb_ep_ops pxa2xx_ep_ops = {
/* ---------------------------------------------------------------------------
* device-scoped parts of the api to the usb controller hardware
* device-scoped parts of the api to the usb controller hardware
* ---------------------------------------------------------------------------
*/
@ -1239,7 +1239,7 @@ static void udc_enable (struct pxa2xx_udc *);
static void udc_disable(struct pxa2xx_udc *);
/* We disable the UDC -- and its 48 MHz clock -- whenever it's not
* in active use.
* in active use.
*/
static int pullup(struct pxa2xx_udc *udc, int is_active)
{
@ -1464,24 +1464,10 @@ udc_proc_read(char *page, char **start, off_t off, int count,
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
/* "function" sysfs attribute */
static ssize_t
show_function (struct device *_dev, struct device_attribute *attr, char *buf)
{
struct pxa2xx_udc *dev = dev_get_drvdata (_dev);
if (!dev->driver
|| !dev->driver->function
|| strlen (dev->driver->function) > PAGE_SIZE)
return 0;
return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
}
static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
/*-------------------------------------------------------------------------*/
/*
* udc_disable - disable USB device controller
* udc_disable - disable USB device controller
*/
static void udc_disable(struct pxa2xx_udc *dev)
{
@ -1507,7 +1493,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
/*
* udc_reinit - initialize software state
* udc_reinit - initialize software state
*/
static void udc_reinit(struct pxa2xx_udc *dev)
{
@ -1635,18 +1621,20 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1;
device_add (&dev->gadget.dev);
retval = device_add (&dev->gadget.dev);
if (retval) {
fail:
dev->driver = NULL;
dev->gadget.dev.driver = NULL;
return retval;
}
retval = driver->bind(&dev->gadget);
if (retval) {
DMSG("bind to driver %s --> error %d\n",
driver->driver.name, retval);
device_del (&dev->gadget.dev);
dev->driver = NULL;
dev->gadget.dev.driver = NULL;
return retval;
goto fail;
}
device_create_file(dev->dev, &dev_attr_function);
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@ -1704,7 +1692,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
dev->driver = NULL;
device_del (&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_function);
DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
dump_state(dev);
@ -2474,12 +2461,12 @@ static struct pxa2xx_udc memory = {
#define IXP465_AD 0x00000200
/*
* probe - binds to the platform device
* probe - binds to the platform device
*/
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
int retval, out_dma = 1, vbus_irq;
int retval, out_dma = 1, vbus_irq, irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@ -2522,7 +2509,11 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
pr_debug("%s: IRQ %d%s%s%s\n", driver_name, IRQ_USB,
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return -ENODEV;
pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)",
out_dma ? "" : " (broken dma-out)",
SIZE_STR DMASTR
@ -2570,11 +2561,11 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
dev->vbus = is_vbus_present();
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
retval = request_irq(irq, pxa2xx_udc_irq,
IRQF_DISABLED, driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, IRQ_USB, retval);
printk(KERN_ERR "%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
return -EBUSY;
}
dev->got_irq = 1;
@ -2589,7 +2580,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
free_irq(IRQ_USB, dev);
free_irq(irq, dev);
return -EBUSY;
}
retval = request_irq(LUBBOCK_USB_IRQ,
@ -2616,7 +2607,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
free_irq(IRQ_USB, dev);
free_irq(irq, dev);
return -EBUSY;
}
}
@ -2641,7 +2632,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
remove_proc_files();
if (dev->got_irq) {
free_irq(IRQ_USB, dev);
free_irq(platform_get_irq(pdev, 0), dev);
dev->got_irq = 0;
}
#ifdef CONFIG_ARCH_LUBBOCK
@ -2668,7 +2659,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
*
* For now, we punt and forcibly disconnect from the USB host when PXA
* enters any suspend state. While we're disconnected, we always disable
* the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states.
* the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states.
* Boards without software pullup control shouldn't use those states.
* VBUS IRQs should probably be ignored so that the PXA device just acts
* "dead" to USB hosts until system resume.
@ -2701,7 +2692,6 @@ static int pxa2xx_udc_resume(struct platform_device *dev)
/*-------------------------------------------------------------------------*/
static struct platform_driver udc_driver = {
.probe = pxa2xx_udc_probe,
.shutdown = pxa2xx_udc_shutdown,
.remove = __exit_p(pxa2xx_udc_remove),
.suspend = pxa2xx_udc_suspend,
@ -2715,7 +2705,7 @@ static struct platform_driver udc_driver = {
static int __init udc_init(void)
{
printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
return platform_driver_register(&udc_driver);
return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
}
module_init(udc_init);

View File

@ -195,7 +195,7 @@ struct rndis_packet_msg_type
__le32 PerPacketInfoLength;
__le32 VcHandle;
__le32 Reserved;
};
} __attribute__ ((packed));
struct rndis_config_parameter
{

View File

@ -15,4 +15,3 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o

View File

@ -31,7 +31,7 @@
#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_PRICTRL 0x40c /* NOTE: big-endian */
#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
#endif /* _EHCI_FSL_H */

View File

@ -136,6 +136,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* restore CMD_RUN, framelist size, and irq threshold */
ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* Some controller/firmware combinations need a delay during which
* they set up the port statuses. See Bugzilla #8190. */
mdelay(8);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {

File diff suppressed because it is too large Load Diff

View File

@ -1,289 +0,0 @@
#ifndef __LINUX_ETRAX_USB_H
#define __LINUX_ETRAX_USB_H
#include <linux/types.h>
#include <linux/list.h>
typedef struct USB_IN_Desc {
volatile __u16 sw_len;
volatile __u16 command;
volatile unsigned long next;
volatile unsigned long buf;
volatile __u16 hw_len;
volatile __u16 status;
} USB_IN_Desc_t;
typedef struct USB_SB_Desc {
volatile __u16 sw_len;
volatile __u16 command;
volatile unsigned long next;
volatile unsigned long buf;
__u32 dummy;
} USB_SB_Desc_t;
typedef struct USB_EP_Desc {
volatile __u16 hw_len;
volatile __u16 command;
volatile unsigned long sub;
volatile unsigned long next;
__u32 dummy;
} USB_EP_Desc_t;
struct virt_root_hub {
int devnum;
void *urb;
void *int_addr;
int send;
int interval;
int numports;
struct timer_list rh_int_timer;
volatile __u16 wPortChange_1;
volatile __u16 wPortChange_2;
volatile __u16 prev_wPortStatus_1;
volatile __u16 prev_wPortStatus_2;
};
struct etrax_usb_intr_traffic {
int sleeping;
int error;
struct wait_queue *wq;
};
typedef struct etrax_usb_hc {
struct usb_bus *bus;
struct virt_root_hub rh;
struct etrax_usb_intr_traffic intr;
} etrax_hc_t;
typedef enum {
STARTED,
NOT_STARTED,
UNLINK,
TRANSFER_DONE,
WAITING_FOR_DESCR_INTR
} etrax_usb_urb_state_t;
typedef struct etrax_usb_urb_priv {
/* The first_sb field is used for freeing all SB descriptors belonging
to an urb. The corresponding ep descriptor's sub pointer cannot be
used for this since the DMA advances the sub pointer as it processes
the sb list. */
USB_SB_Desc_t *first_sb;
/* The last_sb field referes to the last SB descriptor that belongs to
this urb. This is important to know so we can free the SB descriptors
that ranges between first_sb and last_sb. */
USB_SB_Desc_t *last_sb;
/* The rx_offset field is used in ctrl and bulk traffic to keep track
of the offset in the urb's transfer_buffer where incoming data should be
copied to. */
__u32 rx_offset;
/* Counter used in isochronous transfers to keep track of the
number of packets received/transmitted. */
__u32 isoc_packet_counter;
/* This field is used to pass information about the urb's current state between
the various interrupt handlers (thus marked volatile). */
volatile etrax_usb_urb_state_t urb_state;
/* Connection between the submitted urb and ETRAX epid number */
__u8 epid;
/* The rx_data_list field is used for periodic traffic, to hold
received data for later processing in the the complete_urb functions,
where the data us copied to the urb's transfer_buffer. Basically, we
use this intermediate storage because we don't know when it's safe to
reuse the transfer_buffer (FIXME?). */
struct list_head rx_data_list;
} etrax_urb_priv_t;
/* This struct is for passing data from the top half to the bottom half. */
typedef struct usb_interrupt_registers
{
etrax_hc_t *hc;
__u32 r_usb_epid_attn;
__u8 r_usb_status;
__u16 r_usb_rh_port_status_1;
__u16 r_usb_rh_port_status_2;
__u32 r_usb_irq_mask_read;
__u32 r_usb_fm_number;
struct work_struct usb_bh;
} usb_interrupt_registers_t;
/* This struct is for passing data from the isoc top half to the isoc bottom half. */
typedef struct usb_isoc_complete_data
{
struct urb *urb;
struct work_struct usb_bh;
} usb_isoc_complete_data_t;
/* This struct holds data we get from the rx descriptors for DMA channel 9
for periodic traffic (intr and isoc). */
typedef struct rx_data
{
void *data;
int length;
struct list_head list;
} rx_data_t;
typedef struct urb_entry
{
struct urb *urb;
struct list_head list;
} urb_entry_t;
/* ---------------------------------------------------------------------------
Virtual Root HUB
------------------------------------------------------------------------- */
/* destination of request */
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
#define RH_CLASS 0x20
#define RH_VENDOR 0x40
/* Requests: bRequest << 8 | bmRequestType */
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
#define RH_SET_ADDRESS 0x0500
#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
#define RH_GET_STATE 0x0280
#define RH_GET_INTERFACE 0x0A80
#define RH_SET_INTERFACE 0x0B00
#define RH_SYNC_FRAME 0x0C80
/* Our Vendor Specific Request */
#define RH_SET_EP 0x2000
/* Hub port features */
#define RH_PORT_CONNECTION 0x00
#define RH_PORT_ENABLE 0x01
#define RH_PORT_SUSPEND 0x02
#define RH_PORT_OVER_CURRENT 0x03
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
#define RH_C_PORT_OVER_CURRENT 0x13
#define RH_C_PORT_RESET 0x14
/* Hub features */
#define RH_C_HUB_LOCAL_POWER 0x00
#define RH_C_HUB_OVER_CURRENT 0x01
#define RH_DEVICE_REMOTE_WAKEUP 0x00
#define RH_ENDPOINT_STALL 0x01
/* Our Vendor Specific feature */
#define RH_REMOVE_EP 0x00
#define RH_ACK 0x01
#define RH_REQ_ERR -1
#define RH_NACK 0x00
/* Field definitions for */
#define USB_IN_command__eol__BITNR 0 /* command macros */
#define USB_IN_command__eol__WIDTH 1
#define USB_IN_command__eol__no 0
#define USB_IN_command__eol__yes 1
#define USB_IN_command__intr__BITNR 3
#define USB_IN_command__intr__WIDTH 1
#define USB_IN_command__intr__no 0
#define USB_IN_command__intr__yes 1
#define USB_IN_status__eop__BITNR 1 /* status macros. */
#define USB_IN_status__eop__WIDTH 1
#define USB_IN_status__eop__no 0
#define USB_IN_status__eop__yes 1
#define USB_IN_status__eot__BITNR 5
#define USB_IN_status__eot__WIDTH 1
#define USB_IN_status__eot__no 0
#define USB_IN_status__eot__yes 1
#define USB_IN_status__error__BITNR 6
#define USB_IN_status__error__WIDTH 1
#define USB_IN_status__error__no 0
#define USB_IN_status__error__yes 1
#define USB_IN_status__nodata__BITNR 7
#define USB_IN_status__nodata__WIDTH 1
#define USB_IN_status__nodata__no 0
#define USB_IN_status__nodata__yes 1
#define USB_IN_status__epid__BITNR 8
#define USB_IN_status__epid__WIDTH 5
#define USB_EP_command__eol__BITNR 0
#define USB_EP_command__eol__WIDTH 1
#define USB_EP_command__eol__no 0
#define USB_EP_command__eol__yes 1
#define USB_EP_command__eof__BITNR 1
#define USB_EP_command__eof__WIDTH 1
#define USB_EP_command__eof__no 0
#define USB_EP_command__eof__yes 1
#define USB_EP_command__intr__BITNR 3
#define USB_EP_command__intr__WIDTH 1
#define USB_EP_command__intr__no 0
#define USB_EP_command__intr__yes 1
#define USB_EP_command__enable__BITNR 4
#define USB_EP_command__enable__WIDTH 1
#define USB_EP_command__enable__no 0
#define USB_EP_command__enable__yes 1
#define USB_EP_command__hw_valid__BITNR 5
#define USB_EP_command__hw_valid__WIDTH 1
#define USB_EP_command__hw_valid__no 0
#define USB_EP_command__hw_valid__yes 1
#define USB_EP_command__epid__BITNR 8
#define USB_EP_command__epid__WIDTH 5
#define USB_SB_command__eol__BITNR 0 /* command macros. */
#define USB_SB_command__eol__WIDTH 1
#define USB_SB_command__eol__no 0
#define USB_SB_command__eol__yes 1
#define USB_SB_command__eot__BITNR 1
#define USB_SB_command__eot__WIDTH 1
#define USB_SB_command__eot__no 0
#define USB_SB_command__eot__yes 1
#define USB_SB_command__intr__BITNR 3
#define USB_SB_command__intr__WIDTH 1
#define USB_SB_command__intr__no 0
#define USB_SB_command__intr__yes 1
#define USB_SB_command__tt__BITNR 4
#define USB_SB_command__tt__WIDTH 2
#define USB_SB_command__tt__zout 0
#define USB_SB_command__tt__in 1
#define USB_SB_command__tt__out 2
#define USB_SB_command__tt__setup 3
#define USB_SB_command__rem__BITNR 8
#define USB_SB_command__rem__WIDTH 6
#define USB_SB_command__full__BITNR 6
#define USB_SB_command__full__WIDTH 1
#define USB_SB_command__full__no 0
#define USB_SB_command__full__yes 1
#endif

View File

@ -20,10 +20,16 @@
/*-------------------------------------------------------------------------*/
static int broken_suspend(struct usb_hcd *hcd)
{
device_init_wakeup(&hcd->self.root_hub->dev, 0);
return 0;
}
/* AMD 756, for most chips (early revs), corrupts register
* values on read ... so enable the vendor workaround.
*/
static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
static int ohci_quirk_amd756(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@ -31,16 +37,14 @@ static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
/* also erratum 10 (suspend/resume issues) */
device_init_wakeup(&hcd->self.root_hub->dev, 0);
return 0;
return broken_suspend(hcd);
}
/* Apple's OHCI driver has a lot of bizarre workarounds
* for this chip. Evidently control and bulk lists
* can get confused. (B&W G3 models, and ...)
*/
static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
static int ohci_quirk_opti(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@ -53,7 +57,7 @@ static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
* identify the USB (fn2). This quirk might apply to more or
* even all NSC stuff.
*/
static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
static int ohci_quirk_ns(struct usb_hcd *hcd)
{
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
struct pci_dev *b;
@ -75,7 +79,7 @@ static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
* delays before control or bulk queues get re-activated
* in finish_unlinks()
*/
static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@ -88,7 +92,7 @@ static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
/* Check for Toshiba SCC OHCI which has big endian registers
* and little endian in memory data structures
*/
static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@ -129,6 +133,18 @@ static const struct pci_device_id ohci_pci_quirks[] = {
PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
},
{
/* Toshiba portege 4000 */
.vendor = PCI_VENDOR_ID_AL,
.device = 0x5237,
.subvendor = PCI_VENDOR_ID_TOSHIBA_2,
.subdevice = 0x0004,
.driver_data = (unsigned long) broken_suspend,
},
{
PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152),
.driver_data = (unsigned long) broken_suspend,
},
/* FIXME for some of the early AMD 760 southbridges, OHCI
* won't work at all. blacklist them.
*/

View File

@ -123,10 +123,14 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{
if (!list_empty(&td->list))
if (!list_empty(&td->list)) {
dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
if (!list_empty(&td->fl_list))
WARN_ON(1);
}
if (!list_empty(&td->fl_list)) {
dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
WARN_ON(1);
}
dma_pool_free(uhci->td_pool, td, td->dma_handle);
}
@ -291,8 +295,10 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
if (!list_empty(&qh->queue))
if (!list_empty(&qh->queue)) {
dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
WARN_ON(1);
}
list_del(&qh->node);
if (qh->udev) {
@ -740,9 +746,11 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
{
struct uhci_td *td, *tmp;
if (!list_empty(&urbp->node))
if (!list_empty(&urbp->node)) {
dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
urbp->urb);
WARN_ON(1);
}
list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
uhci_remove_td_from_urbp(td);

View File

@ -2,6 +2,7 @@
* ati_remote2 - ATI/Philips USB RF remote driver
*
* Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@ -11,13 +12,29 @@
#include <linux/usb/input.h>
#define DRIVER_DESC "ATI/Philips USB RF remote driver"
#define DRIVER_VERSION "0.1"
#define DRIVER_VERSION "0.2"
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
MODULE_LICENSE("GPL");
/*
* ATI Remote Wonder II Channel Configuration
*
* The remote control can by assigned one of sixteen "channels" in order to facilitate
* the use of multiple remote controls within range of each other.
* A remote's "channel" may be altered by pressing and holding the "PC" button for
* approximately 3 seconds, after which the button will slowly flash the count of the
* currently configured "channel", using the numeric keypad enter a number between 1 and
* 16 and then the "PC" button again, the button will slowly flash the count of the
* newly configured "channel".
*/
static unsigned int channel_mask = 0xFFFF;
module_param(channel_mask, uint, 0644);
MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
static unsigned int mode_mask = 0x1F;
module_param(mode_mask, uint, 0644);
MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
@ -146,15 +163,23 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[0];
int channel, mode;
if (data[0] > 4) {
channel = data[0] >> 4;
if (!((1 << channel) & channel_mask))
return;
mode = data[0] & 0x0F;
if (mode > 4) {
dev_err(&ar2->intf[0]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]);
return;
}
if (!((1 << data[0]) & mode_mask))
if (!((1 << mode) & mode_mask))
return;
input_event(idev, EV_REL, REL_X, (s8) data[1]);
@ -177,9 +202,16 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[1];
int hw_code, index;
int channel, mode, hw_code, index;
if (data[0] > 4) {
channel = data[0] >> 4;
if (!((1 << channel) & channel_mask))
return;
mode = data[0] & 0x0F;
if (mode > 4) {
dev_err(&ar2->intf[1]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]);
@ -199,16 +231,16 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
* events for the mouse pad so we filter out any subsequent
* events from the same mode key.
*/
if (ar2->mode == data[0])
if (ar2->mode == mode)
return;
if (data[1] == 0)
ar2->mode = data[0];
ar2->mode = mode;
hw_code |= data[0] << 8;
hw_code |= mode << 8;
}
if (!((1 << data[0]) & mode_mask))
if (!((1 << mode) & mode_mask))
return;
index = ati_remote2_lookup(hw_code);
@ -379,6 +411,41 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
}
}
static int ati_remote2_setup(struct ati_remote2 *ar2)
{
int r, i, channel;
/*
* Configure receiver to only accept input from remote "channel"
* channel == 0 -> Accept input from any remote channel
* channel == 1 -> Only accept input from remote channel 1
* channel == 2 -> Only accept input from remote channel 2
* ...
* channel == 16 -> Only accept input from remote channel 16
*/
channel = 0;
for (i = 0; i < 16; i++) {
if ((1 << i) & channel_mask) {
if (!(~(1 << i) & 0xFFFF & channel_mask))
channel = i + 1;
break;
}
}
r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
0x20,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
if (r) {
dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
__FUNCTION__, r);
return r;
}
return 0;
}
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
@ -409,6 +476,10 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
if (r)
goto fail2;
r = ati_remote2_setup(ar2);
if (r)
goto fail2;
usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
strlcat(ar2->phys, "/input0", sizeof(ar2->phys));

View File

@ -1047,13 +1047,10 @@ static void gtco_disconnect(struct usb_interface *interface)
/* Grab private device ptr */
struct gtco *device = usb_get_intfdata (interface);
struct input_dev *inputdev;
inputdev = device->inputdevice;
/* Now reverse all the registration stuff */
if (device) {
input_unregister_device(inputdev);
input_unregister_device(device->inputdevice);
usb_kill_urb(device->urbinfo);
usb_free_urb(device->urbinfo);
usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,

View File

@ -285,23 +285,24 @@ static int adu_open(struct inode *inode, struct file *file)
/* save device in the file's private structure */
file->private_data = dev;
/* initialize in direction */
dev->read_buffer_length = 0;
/* fixup first read by having urb waiting for it */
usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
adu_interrupt_in_callback, dev,
dev->interrupt_in_endpoint->bInterval);
/* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
dev->read_urb_finished = 0;
usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
/* we ignore failure */
/* end of fixup for first read */
if (dev->open_count == 1) {
/* initialize in direction */
dev->read_buffer_length = 0;
/* fixup first read by having urb waiting for it */
usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
adu_interrupt_in_callback, dev,
dev->interrupt_in_endpoint->bInterval);
/* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
dev->read_urb_finished = 0;
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
if (retval)
--dev->open_count;
}
up(&dev->sem);
exit_no_device:
@ -469,7 +470,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
adu_interrupt_in_callback,
dev,
dev->interrupt_in_endpoint->bInterval);
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
if (!retval) {
spin_unlock_irqrestore(&dev->buflock, flags);
dbg(2," %s : submitted OK", __FUNCTION__);
@ -539,7 +540,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
size_t bytes_written = 0;
size_t bytes_to_write;
size_t buffer_size;
int retval = 0;
int retval;
int timeout = 0;
dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
@ -547,7 +548,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
dev = file->private_data;
/* lock this object */
down_interruptible(&dev->sem);
retval = down_interruptible(&dev->sem);
if (retval)
goto exit_nolock;
/* verify that the device wasn't unplugged */
if (dev->udev == NULL || dev->minor == 0) {
@ -575,7 +578,11 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
}
up(&dev->sem);
timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
down_interruptible(&dev->sem);
retval = down_interruptible(&dev->sem);
if (retval) {
retval = bytes_written ? bytes_written : retval;
goto exit_nolock;
}
if (timeout > 0) {
break;
}
@ -637,6 +644,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
/* unlock the device */
up(&dev->sem);
exit_nolock:
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);

View File

@ -246,11 +246,13 @@ static void cypress_disconnect(struct usb_interface *interface)
struct cypress *dev;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* remove device attribute files */
device_remove_file(&interface->dev, &dev_attr_port0);
device_remove_file(&interface->dev, &dev_attr_port1);
/* the intfdata can be set to NULL only after the
* device files have been removed */
usb_set_intfdata(interface, NULL);
usb_put_dev(dev->udev);

View File

@ -2304,7 +2304,6 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
#define OHCI_QUIRK_SUPERIO 0x02
#define OHCI_QUIRK_INITRESET 0x04
#define OHCI_BIG_ENDIAN 0x08
#define OHCI_QUIRK_ZFMICRO 0x10
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
OHCI_INTR_WDH)
@ -2910,24 +2909,28 @@ static int __init ftdi_elan_init(void)
INIT_LIST_HEAD(&ftdi_static_list);
status_queue = create_singlethread_workqueue("ftdi-status-control");
if (!status_queue)
goto err1;
goto err_status_queue;
command_queue = create_singlethread_workqueue("ftdi-command-engine");
if (!command_queue)
goto err2;
goto err_command_queue;
respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
if (!respond_queue)
goto err3;
goto err_respond_queue;
result = usb_register(&ftdi_elan_driver);
if (result)
if (result) {
destroy_workqueue(status_queue);
destroy_workqueue(command_queue);
destroy_workqueue(respond_queue);
printk(KERN_ERR "usb_register failed. Error number %d\n",
result);
}
return result;
err3:
err_respond_queue:
destroy_workqueue(command_queue);
err2:
err_command_queue:
destroy_workqueue(status_queue);
err1:
err_status_queue:
printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name);
return -ENOMEM;
}

View File

@ -118,7 +118,7 @@ static int usb_get_report(struct usb_device *dev,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE, (type << 8) + id,
inter->desc.bInterfaceNumber, buf, size,
GET_TIMEOUT);
GET_TIMEOUT*HZ);
}
//#endif
@ -133,7 +133,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->cur_altsetting->desc.bInterfaceNumber, buf,
size, 1);
size, HZ);
}
/*---------------------*/
@ -417,14 +417,14 @@ static ssize_t iowarrior_write(struct file *file,
if (!int_out_urb) {
retval = -ENOMEM;
dbg("%s Unable to allocate urb ", __func__);
goto error;
goto error_no_urb;
}
buf = usb_buffer_alloc(dev->udev, dev->report_size,
GFP_KERNEL, &int_out_urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
dbg("%s Unable to allocate buffer ", __func__);
goto error;
goto error_no_buffer;
}
usb_fill_int_urb(int_out_urb, dev->udev,
usb_sndintpipe(dev->udev,
@ -459,7 +459,9 @@ static ssize_t iowarrior_write(struct file *file,
error:
usb_buffer_free(dev->udev, dev->report_size, buf,
int_out_urb->transfer_dma);
error_no_buffer:
usb_free_urb(int_out_urb);
error_no_urb:
atomic_dec(&dev->write_busy);
wake_up_interruptible(&dev->write_wait);
exit:
@ -748,7 +750,6 @@ static int iowarrior_probe(struct usb_interface *interface,
struct usb_endpoint_descriptor *endpoint;
int i;
int retval = -ENOMEM;
int idele = 0;
/* allocate memory for our device state and intialize it */
dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
@ -824,11 +825,10 @@ static int iowarrior_probe(struct usb_interface *interface,
/* Set the idle timeout to 0, if this is interface 0 */
if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) {
idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x0A,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
0, NULL, 0, USB_CTRL_SET_TIMEOUT);
dbg("idele = %d", idele);
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x0A,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
0, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
/* allow device read and ioctl */
dev->present = 1;

View File

@ -62,6 +62,8 @@
#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
#define USB_VENDOR_ID_MICROCHIP 0x04d8
#define USB_DEVICE_ID_PICDEM 0x000c
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define USB_LD_MINOR_BASE 0
@ -89,6 +91,7 @@ static struct usb_device_id ld_usb_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
{ USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ld_usb_table);

View File

@ -47,6 +47,7 @@ struct usb_lcd {
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
static struct usb_driver lcd_driver;
static DEFINE_MUTEX(usb_lcd_open_mutex);
static void lcd_delete(struct kref *kref)
@ -68,6 +69,7 @@ static int lcd_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
mutex_lock(&usb_lcd_open_mutex);
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
err ("USBLCD: %s - error, can't find device for minor %d",
@ -89,6 +91,7 @@ static int lcd_open(struct inode *inode, struct file *file)
file->private_data = dev;
exit:
mutex_unlock(&usb_lcd_open_mutex);
return retval;
}
@ -347,7 +350,7 @@ static void lcd_disconnect(struct usb_interface *interface)
int minor = interface->minor;
/* prevent skel_open() from racing skel_disconnect() */
lock_kernel();
mutex_lock(&usb_lcd_open_mutex);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
@ -355,7 +358,7 @@ static void lcd_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev(interface, &lcd_class);
unlock_kernel();
mutex_unlock(&usb_lcd_open_mutex);
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);

View File

@ -356,8 +356,10 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
return '-';
if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
}
if (urb->setup_packet == NULL)
return 'Z';
@ -369,7 +371,8 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
unsigned int offset, struct urb *urb, unsigned int length)
{
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
return 0;
}
@ -440,7 +443,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
ep->busnum = rp->r.m_bus->u_bus->busnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
@ -500,7 +503,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
ep->busnum = rp->r.m_bus->u_bus->busnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;
@ -515,7 +518,6 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
static int mon_bin_open(struct inode *inode, struct file *file)
{
struct mon_bus *mbus;
struct usb_bus *ubus;
struct mon_reader_bin *rp;
size_t size;
int rc;
@ -525,7 +527,7 @@ static int mon_bin_open(struct inode *inode, struct file *file)
mutex_unlock(&mon_lock);
return -ENODEV;
}
if ((ubus = mbus->u_bus) == NULL) {
if (mbus != &mon_bus0 && mbus->u_bus == NULL) {
printk(KERN_ERR TAG ": consistency error on open\n");
mutex_unlock(&mon_lock);
return -ENODEV;

View File

@ -16,8 +16,6 @@
#include "usb_mon.h"
#include "../core/hcd.h"
static void mon_submit(struct usb_bus *ubus, struct urb *urb);
static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
@ -25,6 +23,7 @@ static void mon_bus_init(struct usb_bus *ubus);
DEFINE_MUTEX(mon_lock);
struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@ -35,22 +34,19 @@ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
{
unsigned long flags;
struct usb_bus *ubus;
struct list_head *p;
spin_lock_irqsave(&mbus->lock, flags);
if (mbus->nreaders == 0) {
ubus = mbus->u_bus;
if (ubus->monitored) {
/*
* Something is really broken, refuse to go on and
* possibly corrupt ops pointers or worse.
*/
printk(KERN_ERR TAG ": bus %d is already monitored\n",
ubus->busnum);
spin_unlock_irqrestore(&mbus->lock, flags);
return;
if (mbus == &mon_bus0) {
list_for_each (p, &mon_buses) {
struct mon_bus *m1;
m1 = list_entry(p, struct mon_bus, bus_link);
m1->u_bus->monitored = 1;
}
} else {
mbus->u_bus->monitored = 1;
}
ubus->monitored = 1;
}
mbus->nreaders++;
list_add_tail(&r->r_link, &mbus->r_list);
@ -80,77 +76,79 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
/*
*/
static void mon_submit(struct usb_bus *ubus, struct urb *urb)
static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb)
{
struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
mbus = ubus->mon_bus;
if (mbus == NULL)
goto out_unlocked;
spin_lock_irqsave(&mbus->lock, flags);
if (mbus->nreaders == 0)
goto out_locked;
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
r->rnf_submit(r->r_data, urb);
}
spin_unlock_irqrestore(&mbus->lock, flags);
return;
}
out_locked:
spin_unlock_irqrestore(&mbus->lock, flags);
out_unlocked:
return;
static void mon_submit(struct usb_bus *ubus, struct urb *urb)
{
struct mon_bus *mbus;
if ((mbus = ubus->mon_bus) != NULL)
mon_bus_submit(mbus, urb);
mon_bus_submit(&mon_bus0, urb);
}
/*
*/
static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error)
{
struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
mbus = ubus->mon_bus;
if (mbus == NULL)
goto out_unlocked;
spin_lock_irqsave(&mbus->lock, flags);
if (mbus->nreaders == 0)
goto out_locked;
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
r->rnf_error(r->r_data, urb, error);
}
spin_unlock_irqrestore(&mbus->lock, flags);
return;
}
out_locked:
spin_unlock_irqrestore(&mbus->lock, flags);
out_unlocked:
return;
static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
{
struct mon_bus *mbus;
if ((mbus = ubus->mon_bus) != NULL)
mon_bus_submit_error(mbus, urb, error);
mon_bus_submit_error(&mon_bus0, urb, error);
}
/*
*/
static void mon_complete(struct usb_bus *ubus, struct urb *urb)
static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
{
struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
spin_lock_irqsave(&mbus->lock, flags);
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
r->rnf_complete(r->r_data, urb);
}
spin_unlock_irqrestore(&mbus->lock, flags);
}
static void mon_complete(struct usb_bus *ubus, struct urb *urb)
{
struct mon_bus *mbus;
mbus = ubus->mon_bus;
if (mbus == NULL) {
/*
@ -162,13 +160,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
return;
}
spin_lock_irqsave(&mbus->lock, flags);
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
r->rnf_complete(r->r_data, urb);
}
spin_unlock_irqrestore(&mbus->lock, flags);
mon_bus_complete(mbus, urb);
mon_bus_complete(&mon_bus0, urb);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@ -179,14 +172,26 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
static void mon_stop(struct mon_bus *mbus)
{
struct usb_bus *ubus = mbus->u_bus;
struct list_head *p;
/*
* A stop can be called for a dissolved mon_bus in case of
* a reader staying across an rmmod foo_hcd.
*/
if (ubus != NULL) {
ubus->monitored = 0;
mb();
if (mbus == &mon_bus0) {
list_for_each (p, &mon_buses) {
mbus = list_entry(p, struct mon_bus, bus_link);
/*
* We do not change nreaders here, so rely on mon_lock.
*/
if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL)
ubus->monitored = 0;
}
} else {
/*
* A stop can be called for a dissolved mon_bus in case of
* a reader staying across an rmmod foo_hcd, so test ->u_bus.
*/
if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) {
ubus->monitored = 0;
mb();
}
}
}
@ -199,6 +204,10 @@ static void mon_stop(struct mon_bus *mbus)
static void mon_bus_add(struct usb_bus *ubus)
{
mon_bus_init(ubus);
mutex_lock(&mon_lock);
if (mon_bus0.nreaders != 0)
ubus->monitored = 1;
mutex_unlock(&mon_lock);
}
/*
@ -250,12 +259,7 @@ static struct usb_mon_operations mon_ops_0 = {
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
{
/*
* Never happens, but...
*/
if (ubus->monitored) {
printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
ubus->busnum);
ubus->monitored = 0;
mb();
}
@ -263,6 +267,8 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
ubus->mon_bus = NULL;
mbus->u_bus = NULL;
mb();
/* We want synchronize_irq() here, but that needs an argument. */
}
/*
@ -295,9 +301,8 @@ static void mon_bus_init(struct usb_bus *ubus)
*/
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
mbus->uses_dma = ubus->uses_dma;
mbus->text_inited = mon_text_add(mbus, ubus);
mbus->text_inited = mon_text_add(mbus, ubus->busnum);
// mon_bin_add(...)
mutex_lock(&mon_lock);
@ -309,6 +314,18 @@ static void mon_bus_init(struct usb_bus *ubus)
return;
}
static void mon_bus0_init(void)
{
struct mon_bus *mbus = &mon_bus0;
kref_init(&mbus->ref);
spin_lock_init(&mbus->lock);
INIT_LIST_HEAD(&mbus->r_list);
mbus->text_inited = mon_text_add(mbus, 0);
// mbus->bin_inited = mon_bin_add(mbus, 0);
}
/*
* Search a USB bus by number. Notice that USB bus numbers start from one,
* which we may later use to identify "all" with zero.
@ -322,6 +339,9 @@ struct mon_bus *mon_bus_lookup(unsigned int num)
struct list_head *p;
struct mon_bus *mbus;
if (num == 0) {
return &mon_bus0;
}
list_for_each (p, &mon_buses) {
mbus = list_entry(p, struct mon_bus, bus_link);
if (mbus->u_bus->busnum == num) {
@ -341,6 +361,8 @@ static int __init mon_init(void)
if ((rc = mon_bin_init()) != 0)
goto err_bin;
mon_bus0_init();
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
rc = -ENODEV;
@ -374,6 +396,7 @@ static void __exit mon_exit(void)
usb_mon_deregister();
mutex_lock(&mon_lock);
while (!list_empty(&mon_buses)) {
p = mon_buses.next;
mbus = list_entry(p, struct mon_bus, bus_link);
@ -397,6 +420,11 @@ static void __exit mon_exit(void)
mon_dissolve(mbus, mbus->u_bus);
kref_put(&mbus->ref, mon_bus_drop);
}
mbus = &mon_bus0;
if (mbus->text_inited)
mon_text_del(mbus);
mutex_unlock(&mon_lock);
mon_text_exit();

View File

@ -31,9 +31,21 @@
* to a local DoS. But we have to keep to root in order to prevent
* password sniffing from HID devices.
*/
#define EVENT_MAX (2*PAGE_SIZE / sizeof(struct mon_event_text))
#define EVENT_MAX (4*PAGE_SIZE / sizeof(struct mon_event_text))
#define PRINTF_DFL 160
/*
* Potentially unlimited number; we limit it for similar allocations.
* The usbfs limits this to 128, but we're not quite as generous.
*/
#define ISODESC_MAX 5
#define PRINTF_DFL 250 /* with 5 ISOs segs */
struct mon_iso_desc {
int status;
unsigned int offset;
unsigned int length; /* Unsigned here, signed in URB. Historic. */
};
struct mon_event_text {
struct list_head e_link;
@ -41,10 +53,16 @@ struct mon_event_text {
unsigned int pipe; /* Pipe */
unsigned long id; /* From pointer, most of the time */
unsigned int tstamp;
int busnum;
int length; /* Depends on type: xfer length or act length */
int status;
int interval;
int start_frame;
int error_count;
char setup_flag;
char data_flag;
int numdesc; /* Full number */
struct mon_iso_desc isodesc[ISODESC_MAX];
unsigned char setup[SETUP_MAX];
unsigned char data[DATA_MAX];
};
@ -68,6 +86,28 @@ static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
struct mon_text_ptr {
int cnt, limit;
char *pbuf;
};
static struct mon_event_text *
mon_text_read_wait(struct mon_reader_text *rp, struct file *file);
static void mon_text_read_head_t(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_head_u(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_statset(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_intstat(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_isostat(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_isodesc(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
static void mon_text_read_data(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep);
/*
* mon_text_submit
* mon_text_complete
@ -84,8 +124,10 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
return '-';
if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
}
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@ -104,10 +146,10 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
len = DATA_MAX;
if (usb_pipein(pipe)) {
if (ev_type == 'S')
if (ev_type != 'C')
return '<';
} else {
if (ev_type == 'C')
if (ev_type != 'S')
return '>';
}
@ -120,8 +162,10 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
return mon_dmapeek(ep->data, urb->transfer_dma, len);
}
if (urb->transfer_buffer == NULL)
return 'Z'; /* '0' would be not as pretty. */
@ -146,6 +190,9 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
{
struct mon_event_text *ep;
unsigned int stamp;
struct usb_iso_packet_descriptor *fp;
struct mon_iso_desc *dp;
int i, ndesc;
stamp = mon_get_timestamp();
@ -158,12 +205,36 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
ep->type = ev_type;
ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = urb->dev->bus->busnum;
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
if (usb_pipeint(urb->pipe)) {
ep->interval = urb->interval;
} else if (usb_pipeisoc(urb->pipe)) {
ep->interval = urb->interval;
ep->start_frame = urb->start_frame;
ep->error_count = urb->error_count;
}
ep->numdesc = urb->number_of_packets;
if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
ndesc = ISODESC_MAX;
fp = urb->iso_frame_desc;
dp = ep->isodesc;
for (i = 0; i < ndesc; i++) {
dp->status = fp->status;
dp->offset = fp->offset;
dp->length = (ev_type == 'S') ?
fp->length : fp->actual_length;
fp++;
dp++;
}
}
ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus);
ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type,
rp->r.m_bus);
@ -199,6 +270,7 @@ static void mon_text_error(void *data, struct urb *urb, int error)
ep->type = 'E';
ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = 0;
ep->tstamp = 0;
ep->length = 0;
ep->status = error;
@ -237,13 +309,11 @@ static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp,
static int mon_text_open(struct inode *inode, struct file *file)
{
struct mon_bus *mbus;
struct usb_bus *ubus;
struct mon_reader_text *rp;
int rc;
mutex_lock(&mon_lock);
mbus = inode->i_private;
ubus = mbus->u_bus;
rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
if (rp == NULL) {
@ -267,8 +337,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
rp->r.rnf_error = mon_text_error;
rp->r.rnf_complete = mon_text_complete;
snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
(long)rp);
snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
mon_text_ctor, NULL);
@ -300,17 +369,75 @@ static int mon_text_open(struct inode *inode, struct file *file)
* dd if=/dbg/usbmon/0t bs=10
* Also, we do not allow seeks and do not bother advancing the offset.
*/
static ssize_t mon_text_read(struct file *file, char __user *buf,
static ssize_t mon_text_read_t(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
struct mon_reader_text *rp = file->private_data;
struct mon_event_text *ep;
struct mon_text_ptr ptr;
if (IS_ERR(ep = mon_text_read_wait(rp, file)))
return PTR_ERR(ep);
mutex_lock(&rp->printf_lock);
ptr.cnt = 0;
ptr.pbuf = rp->printf_buf;
ptr.limit = rp->printf_size;
mon_text_read_head_t(rp, &ptr, ep);
mon_text_read_statset(rp, &ptr, ep);
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
" %d", ep->length);
mon_text_read_data(rp, &ptr, ep);
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
ptr.cnt = -EFAULT;
mutex_unlock(&rp->printf_lock);
kmem_cache_free(rp->e_slab, ep);
return ptr.cnt;
}
static ssize_t mon_text_read_u(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
struct mon_reader_text *rp = file->private_data;
struct mon_event_text *ep;
struct mon_text_ptr ptr;
if (IS_ERR(ep = mon_text_read_wait(rp, file)))
return PTR_ERR(ep);
mutex_lock(&rp->printf_lock);
ptr.cnt = 0;
ptr.pbuf = rp->printf_buf;
ptr.limit = rp->printf_size;
mon_text_read_head_u(rp, &ptr, ep);
if (ep->type == 'E') {
mon_text_read_statset(rp, &ptr, ep);
} else if (usb_pipeisoc(ep->pipe)) {
mon_text_read_isostat(rp, &ptr, ep);
mon_text_read_isodesc(rp, &ptr, ep);
} else if (usb_pipeint(ep->pipe)) {
mon_text_read_intstat(rp, &ptr, ep);
} else {
mon_text_read_statset(rp, &ptr, ep);
}
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
" %d", ep->length);
mon_text_read_data(rp, &ptr, ep);
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
ptr.cnt = -EFAULT;
mutex_unlock(&rp->printf_lock);
kmem_cache_free(rp->e_slab, ep);
return ptr.cnt;
}
static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
struct file *file)
{
struct mon_bus *mbus = rp->r.m_bus;
DECLARE_WAITQUEUE(waita, current);
struct mon_event_text *ep;
int cnt, limit;
char *pbuf;
char udir, utype;
int data_len, i;
add_wait_queue(&rp->wait, &waita);
set_current_state(TASK_INTERRUPTIBLE);
@ -318,7 +445,7 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
if (file->f_flags & O_NONBLOCK) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&rp->wait, &waita);
return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
return ERR_PTR(-EWOULDBLOCK);
}
/*
* We do not count nwaiters, because ->release is supposed
@ -327,17 +454,19 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
schedule();
if (signal_pending(current)) {
remove_wait_queue(&rp->wait, &waita);
return -EINTR;
return ERR_PTR(-EINTR);
}
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&rp->wait, &waita);
return ep;
}
mutex_lock(&rp->printf_lock);
cnt = 0;
pbuf = rp->printf_buf;
limit = rp->printf_size;
static void mon_text_read_head_t(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
char udir, utype;
udir = usb_pipein(ep->pipe) ? 'i' : 'o';
switch (usb_pipetype(ep->pipe)) {
@ -346,13 +475,38 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
case PIPE_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
utype, udir,
usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
}
static void mon_text_read_head_u(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
char udir, utype;
udir = usb_pipein(ep->pipe) ? 'i' : 'o';
switch (usb_pipetype(ep->pipe)) {
case PIPE_ISOCHRONOUS: utype = 'Z'; break;
case PIPE_INTERRUPT: utype = 'I'; break;
case PIPE_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%d:%03u:%u",
ep->id, ep->tstamp, ep->type,
utype, udir,
ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
}
static void mon_text_read_statset(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
if (ep->setup_flag == 0) { /* Setup packet is present and captured */
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" s %02x %02x %04x %04x %04x",
ep->setup[0],
ep->setup[1],
@ -360,40 +514,86 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
(ep->setup[5] << 8) | ep->setup[4],
(ep->setup[7] << 8) | ep->setup[6]);
} else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %c __ __ ____ ____ ____", ep->setup_flag);
} else { /* No setup for this kind of URB */
cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d", ep->status);
}
cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);
}
static void mon_text_read_intstat(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d:%d", ep->status, ep->interval);
}
static void mon_text_read_isostat(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
if (ep->type == 'S') {
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d:%d:%d", ep->status, ep->interval, ep->start_frame);
} else {
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d:%d:%d:%d",
ep->status, ep->interval, ep->start_frame, ep->error_count);
}
}
static void mon_text_read_isodesc(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
int ndesc; /* Display this many */
int i;
const struct mon_iso_desc *dp;
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d", ep->numdesc);
ndesc = ep->numdesc;
if (ndesc > ISODESC_MAX)
ndesc = ISODESC_MAX;
if (ndesc < 0)
ndesc = 0;
dp = ep->isodesc;
for (i = 0; i < ndesc; i++) {
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %d:%u:%u", dp->status, dp->offset, dp->length);
dp++;
}
}
static void mon_text_read_data(struct mon_reader_text *rp,
struct mon_text_ptr *p, const struct mon_event_text *ep)
{
int data_len, i;
if ((data_len = ep->length) > 0) {
if (ep->data_flag == 0) {
cnt += snprintf(pbuf + cnt, limit - cnt, " =");
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" =");
if (data_len >= DATA_MAX)
data_len = DATA_MAX;
for (i = 0; i < data_len; i++) {
if (i % 4 == 0) {
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt,
p->limit - p->cnt,
" ");
}
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt,
p->limit - p->cnt,
"%02x", ep->data[i]);
}
cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"\n");
} else {
cnt += snprintf(pbuf + cnt, limit - cnt,
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
" %c\n", ep->data_flag);
}
} else {
cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n");
}
if (copy_to_user(buf, rp->printf_buf, cnt))
cnt = -EFAULT;
mutex_unlock(&rp->printf_lock);
kmem_cache_free(rp->e_slab, ep);
return cnt;
}
static int mon_text_release(struct inode *inode, struct file *file)
@ -439,34 +639,46 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
static const struct file_operations mon_fops_text = {
static const struct file_operations mon_fops_text_t = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
.read = mon_text_read,
/* .write = mon_text_write, */
/* .poll = mon_text_poll, */
/* .ioctl = mon_text_ioctl, */
.read = mon_text_read_t,
.release = mon_text_release,
};
int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
static const struct file_operations mon_fops_text_u = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
.read = mon_text_read_u,
.release = mon_text_release,
};
int mon_text_add(struct mon_bus *mbus, int busnum)
{
struct dentry *d;
enum { NAMESZ = 10 };
char name[NAMESZ];
int rc;
rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
rc = snprintf(name, NAMESZ, "%dt", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_t;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
if (d == NULL)
goto err_create_t;
mbus->dent_t = d;
/* XXX The stats do not belong to here (text API), but oh well... */
rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
rc = snprintf(name, NAMESZ, "%du", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_u;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u);
if (d == NULL)
goto err_create_u;
mbus->dent_u = d;
rc = snprintf(name, NAMESZ, "%ds", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_s;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
@ -478,6 +690,10 @@ int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
err_create_s:
err_print_s:
debugfs_remove(mbus->dent_u);
mbus->dent_u = NULL;
err_create_u:
err_print_u:
debugfs_remove(mbus->dent_t);
mbus->dent_t = NULL;
err_create_t:
@ -487,6 +703,7 @@ int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
void mon_text_del(struct mon_bus *mbus)
{
debugfs_remove(mbus->dent_u);
debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
}

View File

@ -22,7 +22,7 @@ struct mon_bus {
int text_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
int uses_dma;
struct dentry *dent_u; /* Second text interface file */
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@ -52,7 +52,7 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
struct mon_bus *mon_bus_lookup(unsigned int num);
int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
void mon_text_del(struct mon_bus *mbus);
// void mon_bin_add(struct mon_bus *);
@ -81,4 +81,6 @@ extern struct mutex mon_lock;
extern const struct file_operations mon_fops_stat;
extern struct mon_bus mon_bus0; /* Only for redundant checks */
#endif /* __USB_MON_H */

View File

@ -355,7 +355,7 @@ static void catc_irq_done(struct urb *urb)
* Transmit routines.
*/
static void catc_tx_run(struct catc *catc)
static int catc_tx_run(struct catc *catc)
{
int status;
@ -373,12 +373,14 @@ static void catc_tx_run(struct catc *catc)
catc->tx_ptr = 0;
catc->netdev->trans_start = jiffies;
return status;
}
static void catc_tx_done(struct urb *urb)
{
struct catc *catc = urb->context;
unsigned long flags;
int r;
if (urb->status == -ECONNRESET) {
dbg("Tx Reset.");
@ -397,10 +399,13 @@ static void catc_tx_done(struct urb *urb)
spin_lock_irqsave(&catc->tx_lock, flags);
if (catc->tx_ptr)
catc_tx_run(catc);
else
if (catc->tx_ptr) {
r = catc_tx_run(catc);
if (unlikely(r < 0))
clear_bit(TX_RUNNING, &catc->flags);
} else {
clear_bit(TX_RUNNING, &catc->flags);
}
netif_wake_queue(catc->netdev);
@ -411,6 +416,7 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
unsigned long flags;
int r = 0;
char *tx_buf;
spin_lock_irqsave(&catc->tx_lock, flags);
@ -421,8 +427,11 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
skb_copy_from_linear_data(skb, tx_buf + 2, skb->len);
catc->tx_ptr += skb->len + 2;
if (!test_and_set_bit(TX_RUNNING, &catc->flags))
catc_tx_run(catc);
if (!test_and_set_bit(TX_RUNNING, &catc->flags)) {
r = catc_tx_run(catc);
if (r < 0)
clear_bit(TX_RUNNING, &catc->flags);
}
if ((catc->is_f5u011 && catc->tx_ptr)
|| (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))))
@ -430,8 +439,10 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
spin_unlock_irqrestore(&catc->tx_lock, flags);
catc->stats.tx_bytes += skb->len;
catc->stats.tx_packets++;
if (r >= 0) {
catc->stats.tx_bytes += skb->len;
catc->stats.tx_packets++;
}
dev_kfree_skb(skb);

View File

@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@ -85,7 +86,7 @@ static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
usb_sndctrlpipe(dev->udev, 0),
DM_WRITE_REG,
USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
value, reg, 0, 0, USB_CTRL_SET_TIMEOUT);
value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static void dm_write_async_callback(struct urb *urb)
@ -171,7 +172,7 @@ static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, 0, 0, dm_write_async_callback, req);
(void *)req, NULL, 0, dm_write_async_callback, req);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {

View File

@ -253,6 +253,7 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */
* of that mess as possible.
*/
#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
/*
@ -349,7 +350,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
case RNDIS_MSG_INDICATE: { /* fault */
// struct rndis_indicate *msg = (void *)buf;
dev_info(&info->control->dev,
"rndis fault indication\n");
"rndis fault indication\n");
}
break;
case RNDIS_MSG_KEEPALIVE: { /* ping */
@ -387,6 +388,71 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
return -ETIMEDOUT;
}
/*
* rndis_query:
*
* Performs a query for @oid along with 0 or more bytes of payload as
* specified by @in_len. If @reply_len is not set to -1 then the reply
* length is checked against this value, resulting in an error if it
* doesn't match.
*
* NOTE: Adding a payload exactly or greater than the size of the expected
* response payload is an evident requirement MSFT added for ActiveSync.
*
* The only exception is for OIDs that return a variably sized response,
* in which case no payload should be added. This undocumented (and
* nonsensical!) issue was found by sniffing protocol requests from the
* ActiveSync 4.1 Windows driver.
*/
static int rndis_query(struct usbnet *dev, struct usb_interface *intf,
void *buf, u32 oid, u32 in_len,
void **reply, int *reply_len)
{
int retval;
union {
void *buf;
struct rndis_msg_hdr *header;
struct rndis_query *get;
struct rndis_query_c *get_c;
} u;
u32 off, len;
u.buf = buf;
memset(u.get, 0, sizeof *u.get + in_len);
u.get->msg_type = RNDIS_MSG_QUERY;
u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len);
u.get->oid = oid;
u.get->len = cpu_to_le32(in_len);
u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n",
oid, retval);
return retval;
}
off = le32_to_cpu(u.get_c->offset);
len = le32_to_cpu(u.get_c->len);
if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
goto response_error;
if (*reply_len != -1 && len != *reply_len)
goto response_error;
*reply = (unsigned char *) &u.get_c->request_id + off;
*reply_len = len;
return retval;
response_error:
dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) "
"invalid response - off %d len %d\n",
oid, off, len);
return -EDOM;
}
static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
int retval;
@ -403,6 +469,8 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
struct rndis_set_c *set_c;
} u;
u32 tmp;
int reply_len;
unsigned char *bp;
/* we can't rely on i/o from stack working, or stack allocation */
u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
@ -421,6 +489,12 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
* TX we'll stick to one Ethernet packet plus RNDIS framing.
* For RX we handle drivers that zero-pad to end-of-packet.
* Don't let userspace change these settings.
*
* NOTE: there still seems to be wierdness here, as if we need
* to do some more things to make sure WinCE targets accept this.
* They default to jumbograms of 8KB or 16KB, which is absurd
* for such low data rates and which is also more than Linux
* can usually expect to allocate for SKB data...
*/
net->hard_header_len += sizeof (struct rndis_data_hdr);
dev->hard_mtu = net->mtu + net->hard_header_len;
@ -434,7 +508,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
goto fail_and_release;
goto fail_and_release;
}
tmp = le32_to_cpu(u.init_c->max_transfer_size);
if (tmp < dev->hard_mtu) {
@ -450,34 +524,15 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
/* Get designated host ethernet address.
*
* Adding a payload exactly the same size as the expected response
* payload is an evident requirement MSFT added for ActiveSync.
* This undocumented (and nonsensical) issue was found by sniffing
* protocol requests from the ActiveSync 4.1 Windows driver.
*/
memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
u.get->len = ccpu2(48);
u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* Get designated host ethernet address */
reply_len = ETH_ALEN;
retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
48, (void **) &bp, &reply_len);
if (unlikely(retval< 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
goto fail_and_release;
}
tmp = le32_to_cpu(u.get_c->offset);
if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
retval = -EDOM;
goto fail_and_release;
}
memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
memcpy(net->dev_addr, bp, ETH_ALEN);
/* set a nonzero filter to enable data transfers */
memset(u.set, 0, sizeof *u.set);
@ -502,6 +557,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
fail_and_release:
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
info->data = NULL;
fail:
kfree(u.buf);
return retval;
@ -618,7 +674,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
static const struct driver_info rndis_info = {
.description = "RNDIS device",
.flags = FLAG_ETHER | FLAG_FRAMING_RN,
.flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT,
.bind = rndis_bind,
.unbind = rndis_unbind,
.status = rndis_status,

View File

@ -734,8 +734,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
{
struct usbnet *dev = netdev_priv(net);
/* REVISIT don't always return "usbnet" */
strncpy (info->driver, driver_name, sizeof info->driver);
strncpy (info->driver, dev->driver_name, sizeof info->driver);
strncpy (info->version, DRIVER_VERSION, sizeof info->version);
strncpy (info->fw_version, dev->driver_info->description,
sizeof info->fw_version);
@ -1115,10 +1114,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct driver_info *info;
struct usb_device *xdev;
int status;
const char *name;
name = udev->dev.driver->name;
info = (struct driver_info *) prod->driver_info;
if (!info) {
dev_dbg (&udev->dev, "blacklisted by %s\n", driver_name);
dev_dbg (&udev->dev, "blacklisted by %s\n", name);
return -ENODEV;
}
xdev = interface_to_usbdev (udev);
@ -1138,6 +1139,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev = netdev_priv(net);
dev->udev = xdev;
dev->driver_info = info;
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
skb_queue_head_init (&dev->rxq);

View File

@ -29,6 +29,7 @@ struct usbnet {
/* housekeeping */
struct usb_device *udev;
struct driver_info *driver_info;
const char *driver_name;
wait_queue_head_t *wait;
struct mutex phy_mutex;

View File

@ -423,11 +423,11 @@ config USB_SERIAL_MCT_U232
module will be called mct_u232.
config USB_SERIAL_MOS7720
tristate "USB Moschip 7720 Single Port Serial Driver"
tristate "USB Moschip 7720 Serial Driver"
depends on USB_SERIAL
---help---
Say Y here if you want to use a USB Serial single port adapter from
Moschip Semiconductor Tech.
Say Y here if you want to use USB Serial single and double
port adapters from Moschip Semiconductor Tech.
To compile this driver as a module, choose M here: the
module will be called mos7720.

View File

@ -209,6 +209,7 @@ static void aircable_send(struct usb_serial_port *port)
int count, result;
struct aircable_private *priv = usb_get_serial_port_data(port);
unsigned char* buf;
u16 *dbuf;
dbg("%s - port %d", __FUNCTION__, port->number);
if (port->write_urb_busy)
return;
@ -226,8 +227,8 @@ static void aircable_send(struct usb_serial_port *port)
buf[0] = TX_HEADER_0;
buf[1] = TX_HEADER_1;
buf[2] = (unsigned char)count;
buf[3] = (unsigned char)(count >> 8);
dbuf = (u16 *)&buf[2];
*dbuf = cpu_to_le16((u16)count);
serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
memcpy(port->write_urb->transfer_buffer, buf,
@ -434,7 +435,7 @@ static void aircable_write_bulk_callback(struct urb *urb)
__FUNCTION__, urb->status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_KERNEL);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev,
"%s - failed resubmitting write urb, error %d\n",

View File

@ -341,7 +341,7 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
result = usb_serial_generic_open(port, filp);
if (result)
return result;
goto err_out;
/* open */
ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
@ -372,6 +372,7 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
if (port->tty)
ark3116_set_termios(port, &tmp_termios);
err_out:
kfree(buf);
return result;

View File

@ -58,9 +58,11 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */

View File

@ -342,6 +342,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
@ -1433,6 +1434,7 @@ static int ftdi_write (struct usb_serial_port *port,
dbg("%s - write limit hit\n", __FUNCTION__);
return 0;
}
priv->tx_outstanding_urbs++;
spin_unlock_irqrestore(&priv->tx_lock, flags);
data_offset = priv->write_offset;
@ -1450,14 +1452,15 @@ static int ftdi_write (struct usb_serial_port *port,
buffer = kmalloc (transfer_size, GFP_ATOMIC);
if (!buffer) {
err("%s ran out of kernel memory for urb ...", __FUNCTION__);
return -ENOMEM;
count = -ENOMEM;
goto error_no_buffer;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("%s - no more free urbs", __FUNCTION__);
kfree (buffer);
return -ENOMEM;
count = -ENOMEM;
goto error_no_urb;
}
/* Copy data */
@ -1499,10 +1502,9 @@ static int ftdi_write (struct usb_serial_port *port,
if (status) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status;
kfree (buffer);
goto error;
} else {
spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_outstanding_urbs;
priv->tx_outstanding_bytes += count;
priv->tx_bytes += count;
spin_unlock_irqrestore(&priv->tx_lock, flags);
@ -1510,10 +1512,19 @@ static int ftdi_write (struct usb_serial_port *port,
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
usb_free_urb (urb);
usb_free_urb(urb);
dbg("%s write returning: %d", __FUNCTION__, count);
return count;
error:
usb_free_urb(urb);
error_no_urb:
kfree (buffer);
error_no_buffer:
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_outstanding_urbs--;
spin_unlock_irqrestore(&priv->tx_lock, flags);
return count;
} /* ftdi_write */

View File

@ -31,6 +31,7 @@
#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 */
/* www.canusb.com Lawicel CANUSB device */

View File

@ -111,7 +111,7 @@ struct edgeport_port {
struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */
struct urb *write_urb; /* write URB for this port */
char write_in_progress; /* TRUE while a write URB is outstanding */
bool write_in_progress; /* 'true' while a write URB is outstanding */
spinlock_t ep_lock;
__u8 shadowLCR; /* last LCR value received */
@ -123,11 +123,11 @@ struct edgeport_port {
__u8 validDataMask;
__u32 baudRate;
char open;
char openPending;
char commandPending;
char closePending;
char chaseResponsePending;
bool open;
bool openPending;
bool commandPending;
bool closePending;
bool chaseResponsePending;
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
@ -156,7 +156,7 @@ struct edgeport_serial {
__u8 bulk_in_endpoint; /* the bulk in endpoint handle */
unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
struct urb * read_urb; /* our bulk read urb */
int read_in_progress;
bool read_in_progress;
spinlock_t es_lock;
__u8 bulk_out_endpoint; /* the bulk out endpoint handle */
@ -212,7 +212,7 @@ static int debug;
static int low_latency = 1; /* tty low latency flag, on by default */
static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */
static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */
/* local function prototypes */
@ -631,14 +631,14 @@ static void edge_interrupt_callback (struct urb *urb)
if (edge_serial->rxBytesAvail > 0 &&
!edge_serial->read_in_progress) {
dbg("%s - posting a read", __FUNCTION__);
edge_serial->read_in_progress = TRUE;
edge_serial->read_in_progress = true;
/* we have pending bytes on the bulk in pipe, send a request */
edge_serial->read_urb->dev = edge_serial->serial->dev;
result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
if (result) {
dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result);
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
}
}
spin_unlock(&edge_serial->es_lock);
@ -695,13 +695,13 @@ static void edge_bulk_in_callback (struct urb *urb)
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
return;
}
if (urb->actual_length == 0) {
dbg("%s - read bulk callback with no data", __FUNCTION__);
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
return;
}
@ -725,10 +725,10 @@ static void edge_bulk_in_callback (struct urb *urb)
status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
if (status) {
dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
}
} else {
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
}
spin_unlock(&edge_serial->es_lock);
@ -759,7 +759,7 @@ static void edge_bulk_out_data_callback (struct urb *urb)
}
// Release the Write URB
edge_port->write_in_progress = FALSE;
edge_port->write_in_progress = false;
// Check if more data needs to be sent
send_more_port_data((struct edgeport_serial *)(usb_get_serial_data(edge_port->port->serial)), edge_port);
@ -779,8 +779,8 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
dbg("%s", __FUNCTION__);
CmdUrbs--;
dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
atomic_dec(&CmdUrbs);
dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
/* clean up the transfer buffer */
@ -802,7 +802,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
tty_wakeup(tty);
/* we have completed the command */
edge_port->commandPending = FALSE;
edge_port->commandPending = false;
wake_up(&edge_port->wait_command);
}
@ -868,7 +868,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
port0->bulk_in_buffer,
edge_serial->read_urb->transfer_buffer_length,
edge_bulk_in_callback, edge_serial);
edge_serial->read_in_progress = FALSE;
edge_serial->read_in_progress = false;
/* start interrupt read for this edgeport
* this interrupt will continue as long as the edgeport is connected */
@ -890,26 +890,26 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* initialize our port settings */
edge_port->txCredits = 0; /* Can't send any data yet */
edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */
edge_port->chaseResponsePending = FALSE;
edge_port->chaseResponsePending = false;
/* send a open port command */
edge_port->openPending = TRUE;
edge_port->open = FALSE;
edge_port->openPending = true;
edge_port->open = false;
response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
if (response < 0) {
dev_err(&port->dev, "%s - error sending open port command\n", __FUNCTION__);
edge_port->openPending = FALSE;
edge_port->openPending = false;
return -ENODEV;
}
/* now wait for the port to be completely opened */
wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
wait_event_timeout(edge_port->wait_open, !edge_port->openPending, OPEN_TIMEOUT);
if (edge_port->open == FALSE) {
if (!edge_port->open) {
/* open timed out */
dbg("%s - open timedout", __FUNCTION__);
edge_port->openPending = FALSE;
edge_port->openPending = false;
return -ENODEV;
}
@ -928,7 +928,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* Allocate a URB for the write */
edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
edge_port->write_in_progress = FALSE;
edge_port->write_in_progress = false;
if (!edge_port->write_urb) {
dbg("%s - no memory", __FUNCTION__);
@ -966,7 +966,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
lastCredits = edge_port->txCredits;
// Did we get our Chase response
if (edge_port->chaseResponsePending == FALSE) {
if (!edge_port->chaseResponsePending) {
dbg("%s - Got Chase Response", __FUNCTION__);
// did we get all of our credit back?
@ -985,7 +985,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
// No activity.. count down.
loop--;
if (loop == 0) {
edge_port->chaseResponsePending = FALSE;
edge_port->chaseResponsePending = false;
dbg("%s - Chase TIMEOUT", __FUNCTION__);
return;
}
@ -1068,13 +1068,13 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
// block until tx is empty
block_until_tx_empty(edge_port);
edge_port->closePending = TRUE;
edge_port->closePending = true;
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPChase))) {
/* flush and chase */
edge_port->chaseResponsePending = TRUE;
edge_port->chaseResponsePending = true;
dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
@ -1082,7 +1082,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
// block until chase finished
block_until_chase_response(edge_port);
} else {
edge_port->chaseResponsePending = FALSE;
edge_port->chaseResponsePending = false;
}
}
@ -1094,10 +1094,10 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
}
//port->close = TRUE;
edge_port->closePending = FALSE;
edge_port->open = FALSE;
edge_port->openPending = FALSE;
//port->close = true;
edge_port->closePending = false;
edge_port->open = false;
edge_port->openPending = false;
usb_kill_urb(edge_port->write_urb);
@ -1247,7 +1247,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
}
// lock this write
edge_port->write_in_progress = TRUE;
edge_port->write_in_progress = true;
// get a pointer to the write_urb
urb = edge_port->write_urb;
@ -1261,7 +1261,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
buffer = kmalloc (count+2, GFP_ATOMIC);
if (buffer == NULL) {
dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__);
edge_port->write_in_progress = FALSE;
edge_port->write_in_progress = false;
goto exit_send;
}
buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count);
@ -1301,7 +1301,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
if (status) {
/* something went wrong */
dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status);
edge_port->write_in_progress = FALSE;
edge_port->write_in_progress = false;
/* revert the credits as something bad happened. */
edge_port->txCredits += count;
@ -1332,7 +1332,7 @@ static int edge_write_room (struct usb_serial_port *port)
if (edge_port == NULL)
return -ENODEV;
if (edge_port->closePending == TRUE)
if (edge_port->closePending)
return -ENODEV;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -1371,7 +1371,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
if (edge_port == NULL)
return -ENODEV;
if (edge_port->closePending == TRUE)
if (edge_port->closePending)
return -ENODEV;
if (!edge_port->open) {
@ -1762,7 +1762,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPChase))) {
/* flush and chase */
edge_port->chaseResponsePending = TRUE;
edge_port->chaseResponsePending = true;
dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
@ -1770,7 +1770,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
// block until chase finished
block_until_chase_response(edge_port);
} else {
edge_port->chaseResponsePending = FALSE;
edge_port->chaseResponsePending = false;
}
}
@ -1952,13 +1952,13 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
// Also, we currently clear flag and close the port regardless of content of above's Byte3.
// We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
// like wait longer in block_until_chase_response, but for now we don't.
edge_port->chaseResponsePending = FALSE;
edge_port->chaseResponsePending = false;
wake_up (&edge_port->wait_chase);
return;
case IOSP_EXT_STATUS_RX_CHECK_RSP:
dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 );
//Port->RxCheckRsp = TRUE;
//Port->RxCheckRsp = true;
return;
}
}
@ -1974,8 +1974,8 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
change_port_settings (edge_port, edge_port->port->tty->termios);
/* we have completed the open */
edge_port->openPending = FALSE;
edge_port->open = TRUE;
edge_port->openPending = false;
edge_port->open = true;
wake_up(&edge_port->wait_open);
return;
}
@ -1983,7 +1983,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
// If port is closed, silently discard all rcvd status. We can
// have cases where buffered status is received AFTER the close
// port command is sent to the Edgeport.
if ((!edge_port->open ) || (edge_port->closePending)) {
if (!edge_port->open || edge_port->closePending) {
return;
}
@ -1991,14 +1991,14 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
// Not currently sent by Edgeport
case IOSP_STATUS_LSR:
dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
handle_new_lsr (edge_port, FALSE, byte2, 0);
handle_new_lsr(edge_port, false, byte2, 0);
break;
case IOSP_STATUS_LSR_DATA:
dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
// byte2 is LSR Register
// byte3 is broken data byte
handle_new_lsr (edge_port, TRUE, byte2, byte3);
handle_new_lsr(edge_port, true, byte2, byte3);
break;
//
// case IOSP_EXT_4_STATUS:
@ -2317,14 +2317,14 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
if (!urb)
return -ENOMEM;
CmdUrbs++;
dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
atomic_inc(&CmdUrbs);
dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
usb_fill_bulk_urb (urb, edge_serial->serial->dev,
usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
buffer, length, edge_bulk_out_cmd_callback, edge_port);
edge_port->commandPending = TRUE;
edge_port->commandPending = true;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
@ -2332,16 +2332,16 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status);
usb_kill_urb(urb);
usb_free_urb(urb);
CmdUrbs--;
atomic_dec(&CmdUrbs);
return status;
}
// wait for command to finish
timeout = COMMAND_TIMEOUT;
#if 0
wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
wait_event (&edge_port->wait_command, !edge_port->commandPending);
if (edge_port->commandPending == TRUE) {
if (edge_port->commandPending) {
/* command timed out */
dbg("%s - command timed out", __FUNCTION__);
status = -EINVAL;
@ -2524,8 +2524,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
if ((!edge_port->open) &&
(!edge_port->openPending)) {
if (!edge_port->open &&
!edge_port->openPending) {
dbg("%s - port not opened", __FUNCTION__);
return;
}
@ -2836,9 +2836,9 @@ static int edge_startup (struct usb_serial *serial)
struct usb_device *dev;
int i, j;
int response;
int interrupt_in_found;
int bulk_in_found;
int bulk_out_found;
bool interrupt_in_found;
bool bulk_in_found;
bool bulk_out_found;
static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0,
EDGE_COMPATIBILITY_MASK1,
EDGE_COMPATIBILITY_MASK2 };
@ -2936,14 +2936,14 @@ static int edge_startup (struct usb_serial *serial)
if (edge_serial->is_epic) {
/* EPIC thing, set up our interrupt polling now and our read urb, so
* that the device knows it really is connected. */
interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
interrupt_in_found = bulk_in_found = bulk_out_found = false;
for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
struct usb_endpoint_descriptor *endpoint;
int buffer_size;
endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
if ((!interrupt_in_found) &&
if (!interrupt_in_found &&
(usb_endpoint_is_int_in(endpoint))) {
/* we found a interrupt in endpoint */
dbg("found interrupt in");
@ -2972,10 +2972,10 @@ static int edge_startup (struct usb_serial *serial)
edge_serial,
endpoint->bInterval);
interrupt_in_found = TRUE;
interrupt_in_found = true;
}
if ((!bulk_in_found) &&
if (!bulk_in_found &&
(usb_endpoint_is_bulk_in(endpoint))) {
/* we found a bulk in endpoint */
dbg("found bulk in");
@ -3001,19 +3001,19 @@ static int edge_startup (struct usb_serial *serial)
endpoint->wMaxPacketSize,
edge_bulk_in_callback,
edge_serial);
bulk_in_found = TRUE;
bulk_in_found = true;
}
if ((!bulk_out_found) &&
if (!bulk_out_found &&
(usb_endpoint_is_bulk_out(endpoint))) {
/* we found a bulk out endpoint */
dbg("found bulk out");
edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
bulk_out_found = TRUE;
bulk_out_found = true;
}
}
if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
err ("Error - the proper endpoints were not found!");
return -ENODEV;
}
@ -3083,6 +3083,7 @@ static int __init edgeport_init(void)
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
atomic_set(&CmdUrbs, 0);
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;

View File

@ -19,12 +19,6 @@
#define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */
/* typedefs that the insideout headers need */
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef LOW8
#define LOW8(a) ((unsigned char)(a & 0xff))
#endif

View File

@ -255,6 +255,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */

View File

@ -238,7 +238,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
if (rc < 0)
err("Reading line status failed (error = %d)", rc);
else {
status = status_buf[0] + (status_buf[1]<<8);
status = le16_to_cpu(*(u16 *)status_buf);
info("%s - read status %x %x", __FUNCTION__,
status_buf[0], status_buf[1]);
@ -257,7 +257,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
static int klsi_105_startup (struct usb_serial *serial)
{
struct klsi_105_private *priv;
int i;
int i, j;
/* check if we support the product id (see keyspan.c)
* FIXME
@ -265,12 +265,12 @@ static int klsi_105_startup (struct usb_serial *serial)
/* allocate the private data structure */
for (i=0; i<serial->num_ports; i++) {
int j;
priv = kmalloc(sizeof(struct klsi_105_private),
GFP_KERNEL);
if (!priv) {
dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__);
return -ENOMEM;
i--;
goto err_cleanup;
}
/* set initial values for control structures */
priv->cfg.pktlen = 5;
@ -292,15 +292,14 @@ static int klsi_105_startup (struct usb_serial *serial)
priv->write_urb_pool[j] = urb;
if (urb == NULL) {
err("No more urbs???");
continue;
goto err_cleanup;
}
urb->transfer_buffer = NULL;
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
err("%s - out of memory for urb buffers.", __FUNCTION__);
continue;
goto err_cleanup;
}
}
@ -308,7 +307,20 @@ static int klsi_105_startup (struct usb_serial *serial)
init_waitqueue_head(&serial->port[i]->write_wait);
}
return (0);
return 0;
err_cleanup:
for (; i >= 0; i--) {
priv = usb_get_serial_port_data(serial->port[i]);
for (j=0; j < NUM_URBS; j++) {
if (priv->write_urb_pool[j]) {
kfree(priv->write_urb_pool[j]->transfer_buffer);
usb_free_urb(priv->write_urb_pool[j]);
}
}
usb_set_serial_port_data(serial->port[i], NULL);
}
return -ENOMEM;
} /* klsi_105_startup */

View File

@ -438,17 +438,21 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
if (retval) {
err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
port->read_urb->pipe, retval);
goto exit;
goto error;
}
port->interrupt_in_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval)
if (retval) {
usb_kill_urb(port->read_urb);
err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
port->interrupt_in_urb->pipe, retval);
exit:
goto error;
}
return 0;
error:
return retval;
} /* mct_u232_open */

View File

@ -103,11 +103,9 @@ static void mos7720_interrupt_callback(struct urb *urb)
{
int result;
int length;
__u32 *data;
unsigned int status;
__u8 *data;
__u8 sp1;
__u8 sp2;
__u8 st;
dbg("%s"," : Entering\n");
@ -141,18 +139,19 @@ static void mos7720_interrupt_callback(struct urb *urb)
* Byte 2 IIR Port 2 (port.number is 1)
* Byte 3 --------------
* Byte 4 FIFO status for both */
if (length && length > 4) {
/* the above description is inverted
* oneukum 2007-03-14 */
if (unlikely(length != 4)) {
dbg("Wrong data !!!");
return;
}
status = *data;
sp1 = data[3];
sp2 = data[2];
sp1 = (status & 0xff000000)>>24;
sp2 = (status & 0x00ff0000)>>16;
st = status & 0x000000ff;
if ((sp1 & 0x01) || (sp2 & 0x01)) {
if ((sp1 | sp2) & 0x01) {
/* No Interrupt Pending in both the ports */
dbg("No Interrupt !!!");
} else {
@ -333,6 +332,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
int response;
int port_number;
char data;
int allocated_urbs = 0;
int j;
serial = port->serial;
@ -353,7 +353,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
/* Initialising the write urb pool */
for (j = 0; j < NUM_URBS; ++j) {
urb = usb_alloc_urb(0,GFP_ATOMIC);
urb = usb_alloc_urb(0,GFP_KERNEL);
mos7720_port->write_urb_pool[j] = urb;
if (urb == NULL) {
@ -365,10 +365,16 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
GFP_KERNEL);
if (!urb->transfer_buffer) {
err("%s-out of memory for urb buffers.", __FUNCTION__);
usb_free_urb(mos7720_port->write_urb_pool[j]);
mos7720_port->write_urb_pool[j] = NULL;
continue;
}
allocated_urbs++;
}
if (!allocated_urbs)
return -ENOMEM;
/* Initialize MCS7720 -- Write Init values to corresponding Registers
*
* Register Index
@ -526,7 +532,7 @@ static int mos7720_chars_in_buffer(struct usb_serial_port *port)
}
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
chars += URB_TRANSFER_BUFFER_SIZE;
}
dbg("%s - returns %d", __FUNCTION__, chars);
@ -629,7 +635,7 @@ static int mos7720_write_room(struct usb_serial_port *port)
}
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
room += URB_TRANSFER_BUFFER_SIZE;
}
@ -664,7 +670,7 @@ static int mos7720_write(struct usb_serial_port *port,
urb = NULL;
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
urb = mos7720_port->write_urb_pool[i];
dbg("URB:%d",i);
break;

View File

@ -176,9 +176,12 @@ struct moschip_port {
int port_num; /*Actual port number in the device(1,2,etc) */
struct urb *write_urb; /* write URB for this port */
struct urb *read_urb; /* read URB for this port */
struct urb *int_urb;
__u8 shadowLCR; /* last LCR value received */
__u8 shadowMCR; /* last MCR value received */
char open;
char open_ports;
char zombie;
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
int delta_msr_cond;
@ -191,17 +194,17 @@ struct moschip_port {
__u8 DcrRegOffset;
//for processing control URBS in interrupt context
struct urb *control_urb;
struct usb_ctrlrequest *dr;
char *ctrl_buf;
int MsrLsr;
spinlock_t pool_lock;
struct urb *write_urb_pool[NUM_URBS];
char busy[NUM_URBS];
};
static int debug;
static int mos7840_num_ports; //this says the number of ports in the device
static int mos7840_num_open_ports;
/*
* mos7840_set_reg_sync
@ -254,7 +257,7 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
struct usb_device *dev = port->serial->dev;
val = val & 0x00ff;
// For the UART control registers, the application number need to be Or'ed
if (mos7840_num_ports == 4) {
if (port->serial->num_ports == 4) {
val |=
(((__u16) port->number - (__u16) (port->serial->minor)) +
1) << 8;
@ -294,7 +297,7 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
//dbg("application number is %4x \n",(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8);
/*Wval is same as application number */
if (mos7840_num_ports == 4) {
if (port->serial->num_ports == 4) {
Wval =
(((__u16) port->number - (__u16) (port->serial->minor)) +
1) << 8;
@ -352,7 +355,7 @@ static inline struct moschip_port *mos7840_get_port_private(struct
return (struct moschip_port *)usb_get_serial_port_data(port);
}
static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
{
struct moschip_port *mos7840_port;
struct async_icount *icount;
@ -366,22 +369,24 @@ static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
/* update input line counters */
if (new_msr & MOS_MSR_DELTA_CTS) {
icount->cts++;
smp_wmb();
}
if (new_msr & MOS_MSR_DELTA_DSR) {
icount->dsr++;
smp_wmb();
}
if (new_msr & MOS_MSR_DELTA_CD) {
icount->dcd++;
smp_wmb();
}
if (new_msr & MOS_MSR_DELTA_RI) {
icount->rng++;
smp_wmb();
}
}
return 0;
}
static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
{
struct async_icount *icount;
@ -400,18 +405,20 @@ static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
icount = &port->icount;
if (new_lsr & SERIAL_LSR_BI) {
icount->brk++;
smp_wmb();
}
if (new_lsr & SERIAL_LSR_OE) {
icount->overrun++;
smp_wmb();
}
if (new_lsr & SERIAL_LSR_PE) {
icount->parity++;
smp_wmb();
}
if (new_lsr & SERIAL_LSR_FE) {
icount->frame++;
smp_wmb();
}
return 0;
}
/************************************************************************/
@ -426,12 +433,15 @@ static void mos7840_control_callback(struct urb *urb)
unsigned char *data;
struct moschip_port *mos7840_port;
__u8 regval = 0x0;
int result = 0;
if (!urb) {
dbg("%s", "Invalid Pointer !!!!:\n");
return;
}
mos7840_port = (struct moschip_port *)urb->context;
switch (urb->status) {
case 0:
/* success */
@ -449,8 +459,6 @@ static void mos7840_control_callback(struct urb *urb)
goto exit;
}
mos7840_port = (struct moschip_port *)urb->context;
dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length);
dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__,
mos7840_port->MsrLsr, mos7840_port->port_num);
@ -462,21 +470,26 @@ static void mos7840_control_callback(struct urb *urb)
else if (mos7840_port->MsrLsr == 1)
mos7840_handle_new_lsr(mos7840_port, regval);
exit:
return;
exit:
spin_lock(&mos7840_port->pool_lock);
if (!mos7840_port->zombie)
result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC);
spin_unlock(&mos7840_port->pool_lock);
if (result) {
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
__FUNCTION__, result);
}
}
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
__u16 * val)
{
struct usb_device *dev = mcs->port->serial->dev;
struct usb_ctrlrequest *dr = NULL;
unsigned char *buffer = NULL;
int ret = 0;
buffer = (__u8 *) mcs->ctrl_buf;
struct usb_ctrlrequest *dr = mcs->dr;
unsigned char *buffer = mcs->ctrl_buf;
int ret;
// dr=(struct usb_ctrlrequest *)(buffer);
dr = (void *)(buffer + 2);
dr->bRequestType = MCS_RD_RTYPE;
dr->bRequest = MCS_RDREQ;
dr->wValue = cpu_to_le16(Wval); //0;
@ -506,8 +519,8 @@ static void mos7840_interrupt_callback(struct urb *urb)
__u16 Data;
unsigned char *data;
__u8 sp[5], st;
int i;
__u16 wval;
int i, rv = 0;
__u16 wval, wreg = 0;
dbg("%s", " : Entering\n");
if (!urb) {
@ -569,31 +582,34 @@ static void mos7840_interrupt_callback(struct urb *urb)
dbg("Serial Port %d: Receiver status error or ", i);
dbg("address bit detected in 9-bit mode\n");
mos7840_port->MsrLsr = 1;
mos7840_get_reg(mos7840_port, wval,
LINE_STATUS_REGISTER,
&Data);
wreg = LINE_STATUS_REGISTER;
break;
case SERIAL_IIR_MS:
dbg("Serial Port %d: Modem status change\n", i);
mos7840_port->MsrLsr = 0;
mos7840_get_reg(mos7840_port, wval,
MODEM_STATUS_REGISTER,
&Data);
wreg = MODEM_STATUS_REGISTER;
break;
}
spin_lock(&mos7840_port->pool_lock);
if (!mos7840_port->zombie) {
rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
} else {
spin_unlock(&mos7840_port->pool_lock);
return;
}
spin_unlock(&mos7840_port->pool_lock);
}
}
}
exit:
if (!(rv < 0)) /* the completion handler for the control urb will resubmit */
return;
exit:
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
__FUNCTION__, result);
}
return;
}
static int mos7840_port_paranoia_check(struct usb_serial_port *port,
@ -634,7 +650,8 @@ static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
if (!port ||
mos7840_port_paranoia_check(port, function) ||
mos7840_serial_paranoia_check(port->serial, function)) {
/* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */
/* then say that we don't have a valid usb_serial thing, which will
* end up genrating -ENODEV return values */
return NULL;
}
@ -699,6 +716,7 @@ static void mos7840_bulk_in_callback(struct urb *urb)
tty_flip_buffer_push(tty);
}
mos7840_port->icount.rx += urb->actual_length;
smp_wmb();
dbg("mos7840_port->icount.rx is %d:\n",
mos7840_port->icount.rx);
}
@ -708,15 +726,14 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
if (mos7840_port->read_urb->status != -EINPROGRESS) {
mos7840_port->read_urb->dev = serial->dev;
status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
mos7840_port->read_urb->dev = serial->dev;
if (status) {
dbg(" usb_submit_urb(read bulk) failed, status = %d",
status);
}
status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
if (status) {
dbg(" usb_submit_urb(read bulk) failed, status = %d",
status);
}
}
@ -730,17 +747,28 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7840_port;
struct tty_struct *tty;
int i;
if (!urb) {
dbg("%s", "Invalid Pointer !!!!:\n");
return;
}
mos7840_port = (struct moschip_port *)urb->context;
spin_lock(&mos7840_port->pool_lock);
for (i = 0; i < NUM_URBS; i++) {
if (urb == mos7840_port->write_urb_pool[i]) {
mos7840_port->busy[i] = 0;
break;
}
}
spin_unlock(&mos7840_port->pool_lock);
if (urb->status) {
dbg("nonzero write bulk status received:%d\n", urb->status);
return;
}
mos7840_port = (struct moschip_port *)urb->context;
if (!mos7840_port) {
dbg("%s", "NULL mos7840_port pointer \n");
return;
@ -792,13 +820,13 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
__u16 Data;
int status;
struct moschip_port *mos7840_port;
struct moschip_port *port0;
if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
dbg("%s", "Port Paranoia failed \n");
return -ENODEV;
}
mos7840_num_open_ports++;
serial = port->serial;
if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
@ -807,16 +835,18 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
}
mos7840_port = mos7840_get_port_private(port);
port0 = mos7840_get_port_private(serial->port[0]);
if (mos7840_port == NULL)
if (mos7840_port == NULL || port0 == NULL)
return -ENODEV;
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
port0->open_ports++;
/* Initialising the write urb pool */
for (j = 0; j < NUM_URBS; ++j) {
urb = usb_alloc_urb(0, GFP_ATOMIC);
urb = usb_alloc_urb(0, GFP_KERNEL);
mos7840_port->write_urb_pool[j] = urb;
if (urb == NULL) {
@ -824,10 +854,10 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
continue;
}
urb->transfer_buffer = NULL;
urb->transfer_buffer =
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (!urb->transfer_buffer) {
usb_free_urb(urb);
mos7840_port->write_urb_pool[j] = NULL;
err("%s-out of memory for urb buffers.", __FUNCTION__);
continue;
}
@ -879,9 +909,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
}
Data |= 0x08; //Driver done bit
Data |= 0x20; //rx_disable
status = 0;
status =
mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
if (status < 0) {
dbg("writing Controlreg failed\n");
return -1;
@ -893,7 +921,6 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
////////////////////////////////////
Data = 0x00;
status = 0;
status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
if (status < 0) {
dbg("disableing interrupts failed\n");
@ -901,7 +928,6 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
}
// Set FIFO_CONTROL_REGISTER to the default value
Data = 0x00;
status = 0;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dbg("Writing FIFO_CONTROL_REGISTER failed\n");
@ -909,7 +935,6 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
}
Data = 0xcf;
status = 0;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dbg("Writing FIFO_CONTROL_REGISTER failed\n");
@ -917,22 +942,18 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
}
Data = 0x03;
status = 0;
status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
mos7840_port->shadowLCR = Data;
Data = 0x0b;
status = 0;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
mos7840_port->shadowMCR = Data;
Data = 0x00;
status = 0;
status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
mos7840_port->shadowLCR = Data;
Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
status = 0;
status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
Data = 0x0c;
@ -999,7 +1020,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
/* Check to see if we've set up our endpoint info yet *
* (can't set it up in mos7840_startup as the structures *
* were not set up at that time.) */
if (mos7840_num_open_ports == 1) {
if (port0->open_ports == 1) {
if (serial->port[0]->interrupt_in_buffer == NULL) {
/* set up interrupt urb */
@ -1097,6 +1118,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
{
int i;
int chars = 0;
unsigned long flags;
struct moschip_port *mos7840_port;
dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
@ -1112,13 +1134,15 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
return -1;
}
spin_lock_irqsave(&mos7840_port->pool_lock,flags);
for (i = 0; i < NUM_URBS; ++i) {
if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) {
if (mos7840_port->busy[i]) {
chars += URB_TRANSFER_BUFFER_SIZE;
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock,flags);
dbg("%s - returns %d", __FUNCTION__, chars);
return (chars);
return chars;
}
@ -1172,6 +1196,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial;
struct moschip_port *mos7840_port;
struct moschip_port *port0;
int j;
__u16 Data;
@ -1189,10 +1214,10 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
}
mos7840_port = mos7840_get_port_private(port);
port0 = mos7840_get_port_private(serial->port[0]);
if (mos7840_port == NULL) {
if (mos7840_port == NULL || port0 == NULL)
return;
}
for (j = 0; j < NUM_URBS; ++j)
usb_kill_urb(mos7840_port->write_urb_pool[j]);
@ -1234,12 +1259,13 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
}
// if(mos7840_port->ctrl_buf != NULL)
// kfree(mos7840_port->ctrl_buf);
mos7840_num_open_ports--;
port0->open_ports--;
dbg("mos7840_num_open_ports in close%d:in port%d\n",
mos7840_num_open_ports, port->number);
if (mos7840_num_open_ports == 0) {
port0->open_ports, port->number);
if (port0->open_ports == 0) {
if (serial->port[0]->interrupt_in_urb) {
dbg("%s", "Shutdown interrupt_in_urb\n");
usb_kill_urb(serial->port[0]->interrupt_in_urb);
}
}
@ -1368,6 +1394,7 @@ static int mos7840_write_room(struct usb_serial_port *port)
{
int i;
int room = 0;
unsigned long flags;
struct moschip_port *mos7840_port;
dbg("%s \n", " mos7840_write_room:entering ...........");
@ -1384,14 +1411,17 @@ static int mos7840_write_room(struct usb_serial_port *port)
return -1;
}
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
for (i = 0; i < NUM_URBS; ++i) {
if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
if (!mos7840_port->busy[i]) {
room += URB_TRANSFER_BUFFER_SIZE;
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
dbg("%s - returns %d", __FUNCTION__, room);
return (room);
return room;
}
@ -1410,6 +1440,7 @@ static int mos7840_write(struct usb_serial_port *port,
int i;
int bytes_sent = 0;
int transfer_size;
unsigned long flags;
struct moschip_port *mos7840_port;
struct usb_serial *serial;
@ -1476,13 +1507,16 @@ static int mos7840_write(struct usb_serial_port *port,
/* try to find a free urb in the list */
urb = NULL;
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
for (i = 0; i < NUM_URBS; ++i) {
if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
if (!mos7840_port->busy[i]) {
mos7840_port->busy[i] = 1;
urb = mos7840_port->write_urb_pool[i];
dbg("\nURB:%d", i);
break;
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
if (urb == NULL) {
dbg("%s - no more free urbs", __FUNCTION__);
@ -1518,6 +1552,7 @@ static int mos7840_write(struct usb_serial_port *port,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
mos7840_port->busy[i] = 0;
err("%s - usb_submit_urb(write bulk) failed with status = %d",
__FUNCTION__, status);
bytes_sent = status;
@ -1525,6 +1560,7 @@ static int mos7840_write(struct usb_serial_port *port,
}
bytes_sent = transfer_size;
mos7840_port->icount.tx += transfer_size;
smp_wmb();
dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
exit:
@ -2490,6 +2526,7 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
if (signal_pending(current))
return -ERESTARTSYS;
cnow = mos7840_port->icount;
smp_rmb();
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
@ -2506,6 +2543,7 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
case TIOCGICOUNT:
cnow = mos7840_port->icount;
smp_rmb();
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
@ -2535,19 +2573,18 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
static int mos7840_calc_num_ports(struct usb_serial *serial)
{
int mos7840_num_ports = 0;
dbg("numberofendpoints: %d \n",
(int)serial->interface->cur_altsetting->desc.bNumEndpoints);
dbg("numberofendpoints: %d \n",
(int)serial->interface->altsetting->desc.bNumEndpoints);
if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
mos7840_num_ports = 2;
serial->type->num_ports = 2;
mos7840_num_ports = serial->num_ports = 2;
} else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
mos7840_num_ports = 4;
serial->type->num_bulk_in = 4;
serial->type->num_bulk_out = 4;
serial->type->num_ports = 4;
serial->num_bulk_in = 4;
serial->num_bulk_out = 4;
mos7840_num_ports = serial->num_ports = 4;
}
return mos7840_num_ports;
@ -2583,7 +2620,9 @@ static int mos7840_startup(struct usb_serial *serial)
mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7840_port == NULL) {
err("%s - Out of memory", __FUNCTION__);
return -ENOMEM;
status = -ENOMEM;
i--; /* don't follow NULL pointer cleaning up */
goto error;
}
/* Initialize all port interrupt end point to port 0 int endpoint *
@ -2591,6 +2630,7 @@ static int mos7840_startup(struct usb_serial *serial)
mos7840_port->port = serial->port[i];
mos7840_set_port_private(serial->port[i], mos7840_port);
spin_lock_init(&mos7840_port->pool_lock);
mos7840_port->port_num = ((serial->port[i]->number -
(serial->port[i]->serial->minor)) +
@ -2601,22 +2641,22 @@ static int mos7840_startup(struct usb_serial *serial)
mos7840_port->ControlRegOffset = 0x1;
mos7840_port->DcrRegOffset = 0x4;
} else if ((mos7840_port->port_num == 2)
&& (mos7840_num_ports == 4)) {
&& (serial->num_ports == 4)) {
mos7840_port->SpRegOffset = 0x8;
mos7840_port->ControlRegOffset = 0x9;
mos7840_port->DcrRegOffset = 0x16;
} else if ((mos7840_port->port_num == 2)
&& (mos7840_num_ports == 2)) {
&& (serial->num_ports == 2)) {
mos7840_port->SpRegOffset = 0xa;
mos7840_port->ControlRegOffset = 0xb;
mos7840_port->DcrRegOffset = 0x19;
} else if ((mos7840_port->port_num == 3)
&& (mos7840_num_ports == 4)) {
&& (serial->num_ports == 4)) {
mos7840_port->SpRegOffset = 0xa;
mos7840_port->ControlRegOffset = 0xb;
mos7840_port->DcrRegOffset = 0x19;
} else if ((mos7840_port->port_num == 4)
&& (mos7840_num_ports == 4)) {
&& (serial->num_ports == 4)) {
mos7840_port->SpRegOffset = 0xc;
mos7840_port->ControlRegOffset = 0xd;
mos7840_port->DcrRegOffset = 0x1c;
@ -2701,21 +2741,19 @@ static int mos7840_startup(struct usb_serial *serial)
dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status);
Data = 0x20;
status = 0;
status =
mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
Data);
if (status < 0) {
dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n",
status);
break;
goto error;
} else
dbg("CLK_MULTI_REGISTER Writing success status%d\n",
status);
//write value 0x0 to scratchpad register
Data = 0x00;
status = 0;
status =
mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER,
Data);
@ -2729,7 +2767,7 @@ static int mos7840_startup(struct usb_serial *serial)
//Zero Length flag register
if ((mos7840_port->port_num != 1)
&& (mos7840_num_ports == 2)) {
&& (serial->num_ports == 2)) {
Data = 0xff;
status = 0;
@ -2770,14 +2808,17 @@ static int mos7840_startup(struct usb_serial *serial)
i + 1, status);
}
mos7840_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC);
mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || !mos7840_port->dr) {
status = -ENOMEM;
goto error;
}
}
//Zero Length flag enable
Data = 0x0f;
status = 0;
status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
if (status < 0) {
dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
@ -2789,6 +2830,17 @@ static int mos7840_startup(struct usb_serial *serial)
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
(__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
return 0;
error:
for (/* nothing */; i >= 0; i--) {
mos7840_port = mos7840_get_port_private(serial->port[i]);
kfree(mos7840_port->dr);
kfree(mos7840_port->ctrl_buf);
usb_free_urb(mos7840_port->control_urb);
kfree(mos7840_port);
serial->port[i] = NULL;
}
return status;
}
/****************************************************************************
@ -2799,6 +2851,7 @@ static int mos7840_startup(struct usb_serial *serial)
static void mos7840_shutdown(struct usb_serial *serial)
{
int i;
unsigned long flags;
struct moschip_port *mos7840_port;
dbg("%s \n", " shutdown :entering..........");
@ -2814,8 +2867,12 @@ static void mos7840_shutdown(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
mos7840_port = mos7840_get_port_private(serial->port[i]);
kfree(mos7840_port->ctrl_buf);
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
mos7840_port->zombie = 1;
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
usb_kill_urb(mos7840_port->control_urb);
kfree(mos7840_port->ctrl_buf);
kfree(mos7840_port->dr);
kfree(mos7840_port);
mos7840_set_port_private(serial->port[i], NULL);
}

View File

@ -69,6 +69,7 @@ static void omninet_write_bulk_callback (struct urb *urb);
static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int omninet_write_room (struct usb_serial_port *port);
static void omninet_shutdown (struct usb_serial *serial);
static int omninet_attach (struct usb_serial *serial);
static struct usb_device_id id_table [] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
.num_bulk_in = 1,
.num_bulk_out = 2,
.num_ports = 1,
.attach = omninet_attach,
.open = omninet_open,
.close = omninet_close,
.write = omninet_write,
@ -145,22 +147,30 @@ struct omninet_data
__u8 od_outseq; // Sequence number for bulk_out URBs
};
static int omninet_open (struct usb_serial_port *port, struct file *filp)
static int omninet_attach (struct usb_serial *serial)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
struct omninet_data *od;
int result = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
struct omninet_data *od;
struct usb_serial_port *port = serial->port[0];
od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
if( !od ) {
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
return -ENOMEM;
}
usb_set_serial_port_data(port, od);
return 0;
}
static int omninet_open (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
struct omninet_data *od = usb_get_serial_port_data(port);
int result = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
wport = serial->port[1];
wport->tty = port->tty;
@ -170,24 +180,17 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
omninet_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
if (result) {
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
}
return result;
}
static void omninet_close (struct usb_serial_port *port, struct file * filp)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
dbg("%s - port %d", __FUNCTION__, port->number);
wport = serial->port[1];
usb_kill_urb(wport->write_urb);
usb_kill_urb(port->read_urb);
kfree(usb_get_serial_port_data(port));
}
@ -326,7 +329,12 @@ static void omninet_write_bulk_callback (struct urb *urb)
static void omninet_shutdown (struct usb_serial *serial)
{
struct usb_serial_port *wport = serial->port[1];
struct usb_serial_port *port = serial->port[0];
dbg ("%s", __FUNCTION__);
usb_kill_urb(wport->write_urb);
kfree(usb_get_serial_port_data(port));
}

View File

@ -113,6 +113,12 @@ static int option_send_setup(struct usb_serial_port *port);
#define ANYDATA_VENDOR_ID 0x16d5
#define ANYDATA_PRODUCT_ID 0x6501
#define BANDRICH_VENDOR_ID 0x1A8D
#define BANDRICH_PRODUCT_C100_1 0x1002
#define BANDRICH_PRODUCT_C100_2 0x1003
#define DELL_VENDOR_ID 0x413C
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@ -165,6 +171,9 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@ -591,12 +600,6 @@ static int option_open(struct usb_serial_port *port, struct file *filp)
return (0);
}
static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS)
usb_kill_urb(urb);
}
static void option_close(struct usb_serial_port *port, struct file *filp)
{
int i;
@ -614,9 +617,9 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
stop_urb(portdata->in_urbs[i]);
usb_kill_urb(portdata->in_urbs[i]);
for (i = 0; i < N_OUT_URB; i++)
stop_urb(portdata->out_urbs[i]);
usb_kill_urb(portdata->out_urbs[i]);
}
port->tty = NULL;
}
@ -747,9 +750,9 @@ static void option_shutdown(struct usb_serial *serial)
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
for (j = 0; j < N_IN_URB; j++)
stop_urb(portdata->in_urbs[j]);
usb_kill_urb(portdata->in_urbs[j]);
for (j = 0; j < N_OUT_URB; j++)
stop_urb(portdata->out_urbs[j]);
usb_kill_urb(portdata->out_urbs[j]);
}
/* Now free them */

View File

@ -456,12 +456,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
return (0);
}
static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS)
usb_kill_urb(urb);
}
static void sierra_close(struct usb_serial_port *port, struct file *filp)
{
int i;
@ -479,9 +473,9 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
stop_urb(portdata->in_urbs[i]);
usb_unlink_urb(portdata->in_urbs[i]);
for (i = 0; i < N_OUT_URB; i++)
stop_urb(portdata->out_urbs[i]);
usb_unlink_urb(portdata->out_urbs[i]);
}
port->tty = NULL;
}
@ -583,17 +577,26 @@ static void sierra_shutdown(struct usb_serial *serial)
/* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (!port)
continue;
portdata = usb_get_serial_port_data(port);
if (!portdata)
continue;
for (j = 0; j < N_IN_URB; j++)
stop_urb(portdata->in_urbs[j]);
usb_unlink_urb(portdata->in_urbs[j]);
for (j = 0; j < N_OUT_URB; j++)
stop_urb(portdata->out_urbs[j]);
usb_unlink_urb(portdata->out_urbs[j]);
}
/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (!port)
continue;
portdata = usb_get_serial_port_data(port);
if (!portdata)
continue;
for (j = 0; j < N_IN_URB; j++) {
if (portdata->in_urbs[j]) {
@ -612,6 +615,8 @@ static void sierra_shutdown(struct usb_serial *serial)
/* Now free per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (!port)
continue;
kfree(usb_get_serial_port_data(port));
}
}

View File

@ -384,19 +384,21 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
dbg("%s - write limit hit\n", __FUNCTION__);
return 0;
}
priv->outstanding_urbs++;
spin_unlock_irqrestore(&priv->lock, flags);
buffer = kmalloc (count, GFP_ATOMIC);
if (!buffer) {
dev_err(&port->dev, "out of memory\n");
return -ENOMEM;
count = -ENOMEM;
goto error_no_buffer;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&port->dev, "no more free urbs\n");
kfree (buffer);
return -ENOMEM;
count = -ENOMEM;
goto error_no_urb;
}
memcpy (buffer, buf, count);
@ -415,18 +417,26 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
__FUNCTION__, status);
count = status;
kfree (buffer);
goto error;
} else {
spin_lock_irqsave(&priv->lock, flags);
++priv->outstanding_urbs;
priv->bytes_out += count;
spin_unlock_irqrestore(&priv->lock, flags);
}
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
usb_free_urb (urb);
usb_free_urb(urb);
return count;
error:
usb_free_urb(urb);
error_no_urb:
kfree(buffer);
error_no_buffer:
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}

View File

@ -1109,7 +1109,7 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *
command_port = port->serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
spin_lock_irqsave(&command_info->lock, flags);
command_info->command_finished = FALSE;
command_info->command_finished = false;
transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer;
transfer_buffer[0] = command;
@ -1124,12 +1124,12 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *
spin_unlock_irqrestore(&command_info->lock, flags);
/* wait for the command to complete */
wait_event_interruptible_timeout(command_info->wait_command,
(command_info->command_finished != FALSE), COMMAND_TIMEOUT);
wait_event_interruptible_timeout(command_info->wait_command,
(bool)command_info->command_finished, COMMAND_TIMEOUT);
spin_lock_irqsave(&command_info->lock, flags);
if (command_info->command_finished == FALSE) {
if (command_info->command_finished == false) {
dbg("%s - command timed out.", __FUNCTION__);
retval = -ETIMEDOUT;
goto exit;

View File

@ -20,10 +20,6 @@
#define __LINUX_USB_SERIAL_WHITEHEAT_H
#define FALSE 0
#define TRUE 1
/* WhiteHEAT commands */
#define WHITEHEAT_OPEN 1 /* open the port */
#define WHITEHEAT_CLOSE 2 /* close the port */

View File

@ -117,6 +117,7 @@ EXPORT_SYMBOL_GPL(usb_usual_check_type);
static int usu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int rc;
unsigned long type;
struct task_struct* task;
unsigned long flags;
@ -135,7 +136,7 @@ static int usu_probe(struct usb_interface *intf,
task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
if (IS_ERR(task)) {
int rc = PTR_ERR(task);
rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
"Unable to start the thread for %s: %d\n",
bias_names[type], rc);

View File

@ -1371,15 +1371,6 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* This prevents the kernel from detecting the virtual cd-drive with the
* Windows drivers. <johann.wilhelm@student.tugraz.at>
*/
UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff,
"HUAWEI",
"E220 USB-UMTS Install",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_DEVICE),
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",

View File

@ -34,18 +34,25 @@ static struct usb_device_id skel_table [] = {
};
MODULE_DEVICE_TABLE(usb, skel_table);
/* to prevent a race between open and disconnect */
static DEFINE_MUTEX(skel_open_lock);
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
/* our private defines. if this grows any larger, use your own .h file */
#define MAX_TRANSFER (PAGE_SIZE - 512)
/* MAX_TRANSFER is chosen so that the VM is not stressed by
allocations > PAGE_SIZE and the number of packets in a page
is an integer 512 is the largest possible packet on EHCI */
#define WRITES_IN_FLIGHT 8
/* arbitrarily chosen */
/* Structure to hold all of our device specific stuff */
struct usb_skel {
struct usb_device *dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
@ -76,8 +83,10 @@ static int skel_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
mutex_lock(&skel_open_lock);
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
mutex_unlock(&skel_open_lock);
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
@ -86,12 +95,15 @@ static int skel_open(struct inode *inode, struct file *file)
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&skel_open_lock);
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
/* now we can drop the lock */
mutex_unlock(&skel_open_lock);
/* prevent the device from being autosuspended */
retval = usb_autopm_get_interface(interface);
@ -201,12 +213,6 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
goto exit;
}
mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* disconnect() was called */
retval = -ENODEV;
goto error;
}
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
@ -225,6 +231,14 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
goto error;
}
/* this lock makes sure we don't submit URBs to gone devices */
mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* disconnect() was called */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
}
/* initialize the urb properly */
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
@ -233,6 +247,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
@ -241,7 +256,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);
mutex_unlock(&dev->io_mutex);
return writesize;
error:
@ -249,7 +264,6 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
usb_free_urb(urb);
}
mutex_unlock(&dev->io_mutex);
up(&dev->limit_sem);
exit:
@ -344,6 +358,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
error:
if (dev)
/* this frees allocated memory */
kref_put(&dev->kref, skel_delete);
return retval;
}
@ -354,20 +369,21 @@ static void skel_disconnect(struct usb_interface *interface)
int minor = interface->minor;
/* prevent skel_open() from racing skel_disconnect() */
lock_kernel();
mutex_lock(&skel_open_lock);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &skel_class);
mutex_unlock(&skel_open_lock);
/* prevent more I/O from starting */
mutex_lock(&dev->io_mutex);
dev->interface = NULL;
mutex_unlock(&dev->io_mutex);
unlock_kernel();
/* decrement our usage count */
kref_put(&dev->kref, skel_delete);
@ -380,6 +396,7 @@ static struct usb_driver skel_driver = {
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
.supports_autosuspend = 1,
};
static int __init usb_skel_init(void)

View File

@ -299,8 +299,9 @@ struct usb_bus {
int bandwidth_int_reqs; /* number of Interrupt requests */
int bandwidth_isoc_reqs; /* number of Isoc. requests */
#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
#endif
struct class_device *class_dev; /* class device for this bus */
#if defined(CONFIG_USB_MON)
@ -373,9 +374,12 @@ struct usb_device {
char *serial; /* iSerialNumber string, if present */
struct list_head filelist;
struct device *usbfs_dev;
#ifdef CONFIG_USB_DEVICE_CLASS
struct device *usb_classdev;
#endif
#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
#endif
/*
* Child devices - these can be either new devices
* (if this is a hub device), or different instances
@ -394,10 +398,13 @@ struct usb_device {
struct delayed_work autosuspend; /* for delayed autosuspends */
struct mutex pm_mutex; /* protects PM operations */
unsigned autosuspend_delay; /* in jiffies */
unsigned long last_busy; /* time of last use */
int autosuspend_delay; /* in jiffies */
unsigned auto_pm:1; /* autosuspend/resume in progress */
unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */
unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
unsigned autoresume_disabled:1; /* disabled by the user */
#endif
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@ -437,6 +444,11 @@ static inline void usb_autopm_disable(struct usb_interface *intf)
usb_autopm_set_interface(intf);
}
static inline void usb_mark_last_busy(struct usb_device *udev)
{
udev->last_busy = jiffies;
}
#else
static inline int usb_autopm_set_interface(struct usb_interface *intf)
@ -451,6 +463,8 @@ static inline void usb_autopm_enable(struct usb_interface *intf)
{ }
static inline void usb_autopm_disable(struct usb_interface *intf)
{ }
static inline void usb_mark_last_busy(struct usb_device *udev)
{ }
#endif
/*-------------------------------------------------------------------------*/

View File

@ -91,6 +91,17 @@ struct usb_cdc_union_desc {
/* ... and there could be other slave interfaces */
} __attribute__ ((packed));
/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
struct usb_cdc_country_functional_desc {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 iCountryCodeRelDate;
__le16 wCountyCode0;
/* ... and there can be a lot of country codes */
} __attribute__ ((packed));
/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
struct usb_cdc_network_terminal_desc {
__u8 bLength;

View File

@ -181,12 +181,15 @@ struct usb_ctrlrequest {
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
/* conventional codes for class-specific descriptors */
#define USB_DT_CS_DEVICE 0x21
#define USB_DT_CS_CONFIG 0x22
#define USB_DT_CS_STRING 0x23
#define USB_DT_CS_INTERFACE 0x24
#define USB_DT_CS_ENDPOINT 0x25
/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
* are authoritative for their usage, not the "common class" writeup.
*/
#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE)
#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG)
#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING)
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
/* All standard descriptors have these 2 fields at the beginning */
struct usb_descriptor_header {