mirror of https://gitee.com/openkylin/linux.git
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:
commit
50f732ee63
8
CREDITS
8
CREDITS
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
12
MAINTAINERS
12
MAINTAINERS
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ struct rndis_packet_msg_type
|
|||
__le32 PerPacketInfoLength;
|
||||
__le32 VcHandle;
|
||||
__le32 Reserved;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rndis_config_parameter
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue