Commit 699ddda6 authored by Linus Torvalds's avatar Linus Torvalds

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: (47 commits)
  USB: Add device id for Sierra Wireless MC8755
  USB: cleanup sierra wireless driver a bit
  USB: Sierra Wireless driver update
  USB: ftdi_sio whitespace fixes
  USB-SERIAL:cp2101 Add new device ID
  USB/gadget/net2280: handle sysfs errors
  usbtouchscreen: fix data reading for ITM touchscreens
  UEAGLE: fix ueagle-atm Oops
  USB: xpad: dance pad support
  USB: input: extract() and implement() are bit field manipulation routines
  USB: Memory leak in drivers/usb/serial/airprime.c
  USB Storage: unusual_devs.h entry for Sony Ericsson P990i
  USB: fix usbatm tiny race
  USB: unusual_devs entry for Nokia 6234
  USB: mos7840.c: fix a check-after-dereference
  USB: ftdi-elan.c: remove dead code
  USB: Mitsumi USB FDD 061M: UNUSUAL_DEV multilun fix
  USB: fix dereference in drivers/usb/misc/adutux.c
  USB: add USB serial mos7720 driver
  USB: move trancevibrator.c to the proper usb directory
  ...
parents acbb67d5 ab352c26
......@@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepads
This is the very first release of a driver for X-Box gamepads.
Basically, this was hacked away in just a few hours, so don't expect
miracles.
In particular, there is currently NO support for the rumble pack.
You won't find many ff-aware linux applications anyway.
0. Status
---------
0. Notes
--------
Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.)
For now, this driver has only been tested on just one Linux-Box.
This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600.
The number of buttons/axes reported varies based on 3 things:
- if you are using a known controller
- if you are using a known dance pad
- if using an unknown device (one not listed below), what you set in the
module configuration for "Map D-PAD to buttons rather than axes for unknown
pads" (module option dpad_to_buttons)
The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
8 axes and 10 buttons.
If you set dpad_to_buttons to 0 and you are using an unknown device (one
not listed below), the driver will map the directional pad to axes (X/Y),
if you said N it will map the d-pad to buttons, which is needed for dance
style games to function correctly. The default is Y.
dpad_to_buttons has no effect for known pads.
0.1 Normal Controllers
----------------------
With a normal controller, the directional pad is mapped to its own X/Y axes.
The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8
axes and 10 buttons.
Alls 8 axes work, though they all have the same range (-32768..32767)
All 8 axes work, though they all have the same range (-32768..32767)
and the zero-setting is not correct for the triggers (I don't know if that
is some limitation of jstest, since the input device setup should be fine. I
didn't have a look at jstest itself yet).
......@@ -30,16 +47,50 @@ in game functionality were OK. However, I find it rather difficult to
play first person shooters with a pad. Your mileage may vary.
0.2 Xbox Dance Pads
-------------------
When using a known dance pad, jstest will report 6 axes and 14 buttons.
For dance style pads (like the redoctane pad) several changes
have been made. The old driver would map the d-pad to axes, resulting
in the driver being unable to report when the user was pressing both
left+right or up+down, making DDR style games unplayable.
Known dance pads automatically map the d-pad to buttons and will work
correctly out of the box.
If your dance pad is recognized by the driver but is using axes instead
of buttons, see section 0.3 - Unknown Controllers
I've tested this with Stepmania, and it works quite well.
0.3 Unkown Controllers
----------------------
If you have an unkown xbox controller, it should work just fine with
the default settings.
HOWEVER if you have an unknown dance pad not listed below, it will not
work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with
a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
whether it is a dance pad or normal controller) so that we can add your pad
to the list of supported devices, ensuring that it will work out of the
box in the future.
1. USB adapter
--------------
Before you can actually use the driver, you need to get yourself an
adapter cable to connect the X-Box controller to your Linux-Box.
adapter cable to connect the X-Box controller to your Linux-Box. You
can buy these online fairly cheap, or build your own.
Such a cable is pretty easy to build. The Controller itself is a USB compound
device (a hub with three ports for two expansion slots and the controller
device) with the only difference in a nonstandard connector (5 pins vs. 4 on
standard USB connector).
Such a cable is pretty easy to build. The Controller itself is a USB
compound device (a hub with three ports for two expansion slots and
the controller device) with the only difference in a nonstandard connector
(5 pins vs. 4 on standard USB connector).
You just need to solder a USB connector onto the cable and keep the
yellow wire unconnected. The other pins have the same order on both
......@@ -51,36 +102,36 @@ original one. You can buy an extension cable and cut that instead. That way,
you can still use the controller with your X-Box, if you have one ;)
2. driver installation
2. Driver Installation
----------------------
Once you have the adapter cable and the controller is connected, you need
to load your USB subsystem and should cat /proc/bus/usb/devices.
There should be an entry like the one at the end [4].
Currently (as of version 0.0.4), the following three devices are included:
Currently (as of version 0.0.6), the following devices are included:
original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202
smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289
original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285
InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a
RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809
If you have another controller that is not listed above and is not recognized
by the driver, please drop me a line with the appropriate info (that is, include
the name, vendor and product ID, as well as the country where you bought it;
sending the whole dump out of /proc/bus/usb/devices along would be even better).
The driver should work with xbox pads not listed above as well, however
you will need to do something extra for dance pads to work.
In theory, the driver should work with other controllers than mine
(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this
for I only have this one controller.
If you have a controller not listed above, see 0.3 - Unknown Controllers
If you compiled and installed the driver, test the functionality:
> modprobe xpad
> modprobe joydev
> jstest /dev/js0
There should be a single line showing 18 inputs (8 axes, 10 buttons), and
it's values should change if you move the sticks and push the buttons.
If you're using a normal controller, there should be a single line showing
18 inputs (8 axes, 10 buttons), and its values should change if you move
the sticks and push the buttons. If you're using a dance pad, it should
show 20 inputs (6 axes, 14 buttons).
It works? Voila, your done ;)
It works? Voila, you're done ;)
3. Thanks
......@@ -111,6 +162,22 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none)
E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms
E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms
5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US):
T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0c12 ProdID=8809 Rev= 0.01
S: Product=XBOX DDR
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad
E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms
E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms
--
Marko Friedemann <mfr@bmx-chemnitz.de>
2002-07-16
- original doc
Dominic Cerquetti <binary1230@yahoo.com>
2005-03-19
- added stuff for dance pads, new d-pad->axes mappings
......@@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB) += input/
obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/
obj-$(CONFIG_USB_WACOM) += input/
obj-$(CONFIG_USB_XPAD) += input/
......@@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_ATM) += atm/
......
......@@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = {
{ /* V = Conexant P = ADSL modem */
USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */
USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Olitec P = ADSL modem version 2 */
USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe
},
......
......@@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch";
#define OFFSET_d 9 /* size 4 */
#define OFFSET_e 13 /* size 1 */
#define OFFSET_f 14 /* size 1 */
#define TOTAL 15
#define SIZE_7 1
#define SIZE_b 8
......@@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST;
static int enable_isoc = DEFAULT_ENABLE_ISOC;
static int sw_buffering = DEFAULT_SW_BUFFERING;
#define DEFAULT_B_MAX_DSL 8128
#define DEFAULT_MODEM_MODE 11
#define MODEM_OPTION_LENGTH 16
static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
static unsigned char ModemMode = DEFAULT_MODEM_MODE;
static unsigned char ModemOption[MODEM_OPTION_LENGTH];
static int num_ModemOption;
module_param(altsetting, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(altsetting,
"Alternative setting for data interface (bulk_default: "
......@@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering,
"Enable software buffering (default: "
__MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(BMaxDSL,
"default: " __MODULE_STRING(DEFAULT_B_MAX_DSL));
module_param(ModemMode, byte, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ModemMode,
"default: " __MODULE_STRING(DEFAULT_MODEM_MODE));
module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO);
MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
#define INTERFACE_DATA 1
#define ENDPOINT_INT 0x81
#define ENDPOINT_BULK_DATA 0x07
......@@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering,
#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
struct speedtch_params {
unsigned int altsetting;
unsigned int BMaxDSL;
unsigned char ModemMode;
unsigned char ModemOption[MODEM_OPTION_LENGTH];
};
struct speedtch_instance_data {
struct usbatm_data *usbatm;
unsigned int altsetting;
struct speedtch_params params; /* set in probe, constant afterwards */
struct work_struct status_checker;
......@@ -123,7 +152,7 @@ struct speedtch_instance_data {
struct urb *int_urb;
unsigned char int_data[16];
unsigned char scratch_buffer[TOTAL];
unsigned char scratch_buffer[16];
};
/***************
......@@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance)
0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
if (ret < 0)
usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
/* Extra initialisation in recent drivers - gives higher speeds */
/* URBext1 */
buf[0] = instance->params.ModemMode;
ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT);
if (ret < 0)
usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret);
/* URBext2 */
/* This seems to be the one which actually triggers the higher sync
rate -- it does require the new firmware too, although it works OK
with older firmware */
ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
0x01, 0x40, 0x14, 0x00,
instance->params.ModemOption,
MODEM_OPTION_LENGTH, CTRL_TIMEOUT);
if (ret < 0)
usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret);
/* URBext3 */
buf[0] = instance->params.BMaxDSL & 0xff;
buf[1] = instance->params.BMaxDSL >> 8;
ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT);
if (ret < 0)
usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret);
}
static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
......@@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
because we're in our own kernel thread anyway. */
msleep_interruptible(1000);
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret);
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret);
goto out_free;
}
......@@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance)
unsigned char *buf = instance->scratch_buffer;
int ret;
memset(buf, 0, TOTAL);
memset(buf, 0, 16);
ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
......@@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm,
instance->usbatm = usbatm;
/* altsetting and enable_isoc may change at any moment, so take a snapshot */
instance->altsetting = altsetting;
/* module parameters may change at any moment, so take a snapshot */
instance->params.altsetting = altsetting;
instance->params.BMaxDSL = BMaxDSL;
instance->params.ModemMode = ModemMode;
memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH);
memcpy(instance->params.ModemOption, ModemOption, num_ModemOption);
use_isoc = enable_isoc;
if (instance->altsetting)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret);
instance->altsetting = 0; /* fall back to default */
if (instance->params.altsetting)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret);
instance->params.altsetting = 0; /* fall back to default */
}
if (!instance->altsetting && use_isoc)
if (!instance->params.altsetting && use_isoc)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) {
usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret);
use_isoc = 0; /* fall back to bulk */
......@@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm,
usb_info(usbatm, "isochronous transfer not supported - using bulk\n");
}
if (!use_isoc && !instance->altsetting)
if (!use_isoc && !instance->params.altsetting)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) {
usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret);
goto fail_free;
}
if (!instance->altsetting)
instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
if (!instance->params.altsetting)
instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
......
......@@ -68,7 +68,7 @@
#include "usbatm.h"
#define EAGLEUSBVERSION "ueagle 1.3"
#define EAGLEUSBVERSION "ueagle 1.4"
/*
......@@ -80,14 +80,14 @@
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm dbg] %s: " format, \
__FUNCTION__, ##args); \
} while (0)
} while (0)
#define uea_vdbg(usb_dev, format, args...) \
do { \
if (debug >= 2) \
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm vdbg] " format, ##args); \
} while (0)
} while (0)
#define uea_enters(usb_dev) \
uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
......@@ -218,8 +218,8 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
#define IS_ISDN(sc) \
(le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)
#define IS_ISDN(usb_dev) \
(le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
#define INS_TO_USBDEV(ins) ins->usb_dev
......@@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc)
char *dsp_name;
if (UEA_CHIP_VERSION(sc) == ADI930) {
if (IS_ISDN(sc))
if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
if (IS_ISDN(sc))
if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
......@@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc)
static inline int wait_cmv_ack(struct uea_softc *sc)
{
int ret = wait_event_timeout(sc->cmv_ack_wait,
int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
sc->cmv_ack, ACK_TIMEOUT);
sc->cmv_ack = 0;
......@@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc)
break;
case 3: /* fail ... */
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n");
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
" (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
......@@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc)
release_firmware(sc->dsp_firm);
sc->dsp_firm = NULL;
}
ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
if (ret < 0)
return ret;
uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
sc->stats.phy.firmid);
}
/* always update it as atm layer could not be init when we switch to
......@@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc *sc,
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin";
file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
else
file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin";
file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
} else
file = cmv_file[sc->modem_index];
......@@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc)
if (ret < 0)
return ret;
/* Dump firmware version */
ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
if (ret < 0)
return ret;
uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
sc->stats.phy.firmid);
/* get options */
ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
if (ret < 0)
......@@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc)
/* Enter in R-ACT-REQ */
ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
uea_info(INS_TO_USBDEV(sc), "Modem started, "
"waiting synchronization\n");
out:
release_firmware(cmvs_fw);
sc->reset = 0;
......@@ -1172,7 +1176,10 @@ static int uea_kthread(void *data)
if (!ret)
ret = uea_stat(sc);
if (ret != -EAGAIN)
msleep(1000);
msleep_interruptible(1000);
if (try_to_freeze())
uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
"please unplug/replug your modem\n");
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
......@@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0);
UEA_ATTR(dscorr, 0);
UEA_ATTR(usunc, 0);
UEA_ATTR(dsunc, 0);
UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */
......@@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
wait_event(sc->sync_q, IS_OPERATIONAL(sc));
wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc));
return 0;
......@@ -1639,16 +1647,13 @@ static struct attribute *attrs[] = {
&dev_attr_stat_dscorr.attr,
&dev_attr_stat_usunc.attr,
&dev_attr_stat_dsunc.attr,
&dev_attr_stat_firmid.attr,
NULL,
};
static struct attribute_group attr_grp = {
.attrs = attrs,
};
static int create_fs_entries(struct usb_interface *intf)
{
return sysfs_create_group(&intf->dev.kobj, &attr_grp);
}
static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
const struct usb_device_id *id)
{
......@@ -1708,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
}
}
ret = sysfs_create_group(&intf->dev.kobj, &attr_grp);
if (ret < 0)
goto error;
ret = uea_boot(sc);
if (ret < 0) {
kfree(sc);
return ret;
}
if (ret < 0)
goto error;
ret = create_fs_entries(intf);
if (ret) {
uea_stop(sc);
kfree(sc);
return ret;
}
return 0;
}
static void destroy_fs_entries(struct usb_interface *intf)
{
sysfs_remove_group(&intf->dev.kobj, &attr_grp);
error:
kfree(sc);
return ret;
}
static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
destroy_fs_entries(intf);
sysfs_remove_group(&intf->dev.kobj, &attr_grp);
uea_stop(sc);
kfree(sc);
}
......@@ -1753,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n",
uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
le16_to_cpu(usb->descriptor.idVendor),
le16_to_cpu(usb->descriptor.idProduct),
chip_name[UEA_CHIP_VERSION(id)]);
chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
usb_reset_device(usb);
......
......@@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg)
daemonize(instance->driver->driver_name);
allow_signal(SIGTERM);
instance->thread_pid = current->pid;
complete(&instance->thread_started);
......@@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
return ret;
}
mutex_lock(&instance->serialize);
instance->thread_pid = ret;
mutex_unlock(&instance->serialize);
wait_for_completion(&instance->thread_started);
return 0;
......
......@@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm)
struct acm_rb *buf;
struct tty_struct *tty = acm->tty;
struct acm_ru *rcv;
//unsigned long flags;
unsigned long flags;
int i = 0;
dbg("Entering acm_rx_tasklet");
......@@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm)
return;
next_buffer:
spin_lock(&acm->read_lock);
spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->filled_read_bufs)) {
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
goto urbs;
}
buf = list_entry(acm->filled_read_bufs.next,
struct acm_rb, list);
list_del(&buf->list);
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
......@@ -356,29 +356,29 @@ static void acm_rx_tasklet(unsigned long _acm)
memmove(buf->base, buf->base + i, buf->size - i);
buf->size -= i;
spin_unlock(&acm->throttle_lock);
spin_lock(&acm->read_lock);
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->filled_read_bufs);
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
spin_unlock(&acm->throttle_lock);
spin_lock(&acm->read_lock);
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->spare_read_bufs);
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
goto next_buffer;
urbs:
while (!list_empty(&acm->spare_read_bufs)) {
spin_lock(&acm->read_lock);
spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->spare_read_urbs)) {
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
rcv = list_entry(acm->spare_read_urbs.next,
struct acm_ru, list);
list_del(&rcv->list);
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
buf = list_entry(acm->spare_read_bufs.next,
struct acm_rb, list);
......@@ -400,9 +400,9 @@ static void acm_rx_tasklet(unsigned long _acm)
free-urbs-pool and resubmited ASAP */
if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
list_add(&buf->list, &acm->spare_read_bufs);
spin_lock(&acm->read_lock);
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&rcv->list, &acm->spare_read_urbs);
spin_unlock(&acm->read_lock);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
}
......@@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
......
......@@ -154,6 +154,7 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
......@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"",
usblp->device_id_string ?
usblp->device_id_string + 2 :
......@@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err)
return newerr;
}
static int handle_bidir (struct usblp *usblp)
{
if (usblp->bidir && usblp->used && !usblp->sleeping) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
usblp->used = 0;
return -EIO;
}
}
return 0;
}
/*
* File op functions.
*/
......@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->status = 0;
usblp->readurb->status = 0;
if (usblp->bidir) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
retval = -EIO;
usblp->used = 0;
file->private_data = NULL;
}
if (handle_bidir(usblp) < 0) {
file->private_data = NULL;
retval = -EIO;
}
out:
mutex_unlock (&usblp_mutex);
......@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
if (usblp->sleeping) {
retval = -ENODEV;
goto done;
}
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
......@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
return -ENODEV;
}
if (usblp->sleeping) {
up (&usblp->sem);
return writecount ? writecount : -ENODEV;
}
if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete)
......@@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
goto done;
}
if (usblp->sleeping) {
count = -ENODEV;
goto done;
}
if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb->status);
......@@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_unlock (&usblp_mutex);
}
static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
/* this races against normal access and open */
mutex_lock (&usblp_mutex);
down (&usblp->sem);
/* we take no more IO */
usblp->sleeping = 1;
/* we wait for anything printing */
wait_event (usblp->wait, usblp->wcomplete || !usblp->present);
usblp_unlink_urbs(usblp);
up (&usblp->sem);
mutex_unlock (&usblp_mutex);
return 0;
}
static int usblp_resume (struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
int r;
mutex_lock (&usblp_mutex);
down (&usblp->sem);
usblp->sleeping = 0;
r = handle_bidir (usblp);
up (&usblp->sem);
mutex_unlock (&usblp_mutex);
return r;
}
static struct usb_device_id usblp_ids [] = {
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
......@@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = {
.name = "usblp",
.probe = usblp_probe,
.disconnect = usblp_disconnect,
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
};
......
......@@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = {
.release = usbdev_release,
};
static void usbdev_add(struct usb_device *dev)
static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class, NULL,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
if (IS_ERR(dev->class_dev))
return PTR_ERR(dev->class_dev);
dev->class_dev->class_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
......@@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action,
{
switch (action) {
case USB_DEVICE_ADD:
usbdev_add(dev);
if (usbdev_add(dev))
return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
......
......@@ -223,7 +223,7 @@ int usb_create_ep_files(struct device *parent,
ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
if (!ep_dev) {
retval = -ENOMEM;
goto exit;
goto error_alloc;
}
/* fun calculation to determine the minor of this endpoint */
......@@ -241,33 +241,31 @@ int usb_create_ep_files(struct device *parent,
retval = device_register(&ep_dev->dev);
if (retval)
goto error;
goto error_register;
retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
if (retval)
goto error_group;
endpoint->ep_dev = ep_dev;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
retval = sysfs_create_link(&parent->kobj,
&endpoint->ep_dev->dev.kobj, name);
retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
if (retval)
goto error_link;
exit:
endpoint->ep_dev = ep_dev;
return retval;
error_link:
sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
error_group:
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
return retval;
error:
error_register:
kfree(ep_dev);
error_alloc:
destroy_endpoint_class();
exit:
return retval;
}
......@@ -282,8 +280,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
device_unregister(&endpoint->ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
}
destroy_endpoint_class();
}
......@@ -2044,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
return retval;
}
device_create_file (&dev->pdev->dev, &dev_attr_function);
device_create_file (&dev->pdev->dev, &dev_attr_queues);
retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
if (retval) goto err_unbind;
retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
if (retval) goto err_func;
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
......@@ -2060,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
/* pci writes may still be posted */
return 0;
err_func:
device_remove_file (&dev->pdev->dev, &dev_attr_function);
err_unbind:
driver->unbind (&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
return retval;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
......@@ -2974,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
: "disabled");
the_controller = dev;
device_register (&dev->gadget.dev);
device_create_file (&pdev->dev, &dev_attr_registers);
retval = device_register (&dev->gadget.dev);
if (retval) goto done;
retval = device_create_file (&pdev->dev, &dev_attr_registers);
if (retval) goto done;
return 0;
......
......@@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf)
}
if (ehci->reclaim) {
temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim);
temp = scnprintf (next, size, "reclaim qh %p%s\n",
ehci->reclaim,
ehci->reclaim_ready ? " ready" : "");
size -= temp;
next += temp;
}
......
......@@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
......@@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
static void end_unlink_async (struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
#include "ehci-hub.c"
......@@ -264,37 +263,25 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
static void ehci_iaa_watchdog (unsigned long param)
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
u32 status;
spin_lock_irqsave (&ehci->lock, flags);
WARN_ON(!ehci->reclaim);
/* lost IAA irqs wedge things badly; seen first with a vt8235 */
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
status = readl (&ehci->regs->status);
u32 status = readl (&ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status);
end_unlink_async (ehci);
ehci->reclaim_ready = 1;
}
}
spin_unlock_irqrestore (&ehci->lock, flags);
}
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
spin_lock_irqsave (&ehci->lock, flags);
/* stop async processing after it's idled a bit */
/* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
start_unlink_async (ehci, ehci->async);
......@@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
static void ehci_work (struct ehci_hcd *ehci)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
if (ehci->reclaim_ready)
end_unlink_async (ehci);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
......@@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd)
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
del_timer_sync (&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
......@@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
init_timer(&ehci->iaa_watchdog);
ehci->iaa_watchdog.function = ehci_iaa_watchdog;
ehci->iaa_watchdog.data = (unsigned long) ehci;
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
......@@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
ehci->reclaim = NULL;
ehci->reclaim_ready = 0;
ehci->next_uframe = -1;
/*
......@@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
end_unlink_async (ehci);
ehci->reclaim_ready = 1;
bh = 1;
}
......@@ -723,14 +708,10 @@ static int ehci_urb_enqueue (
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
// BUG_ON(qh->qh_state != QH_STATE_LINKED);
/* failfast */
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
end_unlink_async (ehci);
/* defer till later if busy */
else if (ehci->reclaim) {
/* if we need to use IAA and it's busy, defer */
if (qh->qh_state == QH_STATE_LINKED
&& ehci->reclaim
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
struct ehci_qh *last;
for (last = ehci->reclaim;
......@@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;
/* start IAA cycle */
} else
/* bypass IAA if the hc can't care */
} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
end_unlink_async (ehci);
/* something else might have unlinked the qh by now */
if (qh->qh_state == QH_STATE_LINKED)
start_unlink_async (ehci, qh);
}
......@@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
switch (qh->qh_state) {
case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
unlink_async (ehci, qh);
break;
case QH_STATE_UNLINK:
case QH_STATE_UNLINK_WAIT:
/* already started */
break;
case QH_STATE_IDLE:
WARN_ON(1);
break;
}
unlink_async (ehci, qh);
break;
case PIPE_INTERRUPT:
......@@ -867,7 +840,6 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);
......
......@@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
end_unlink_async (ehci);
ehci->reclaim_ready = 1;
ehci_work(ehci);
/* suspend any active/unsuspended ports, maybe allow wakeup */
......
......@@ -303,7 +303,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
end_unlink_async (ehci);
ehci->reclaim_ready = 1;
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);
......
......@@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
iaa_watchdog_done (ehci);
timer_action_done (ehci, TIMER_IAA_WATCHDOG);
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
......@@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
ehci->reclaim_ready = 0;
qh->reclaim = NULL;
qh_completions (ehci, qh);
......@@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
return;
}
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
writel (cmd, &ehci->regs->command);
(void) readl (&ehci->regs->command);
iaa_watchdog_start (ehci);
timer_action (ehci, TIMER_IAA_WATCHDOG);
}
/*-------------------------------------------------------------------------*/
......
......@@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
unsigned reclaim_ready : 1;
unsigned scanning : 1;
/* periodic schedule support */
......@@ -80,7 +81,6 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
......@@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
}
static inline void
iaa_watchdog_start (struct ehci_hcd *ehci)
{
WARN_ON(timer_pending(&ehci->iaa_watchdog));
mod_timer (&ehci->iaa_watchdog,
jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
}
static inline void iaa_watchdog_done (struct ehci_hcd *ehci)
{
del_timer (&ehci->iaa_watchdog);
}
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
......@@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
unsigned long t;
switch (action) {
case TIMER_IAA_WATCHDOG:
t = EHCI_IAA_JIFFIES;
break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
......@@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
if (time_before_eq(t, ehci->watchdog.expires)
if (action != TIMER_IAA_WATCHDOG
&& t > ehci->watchdog.expires
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);
......
......@@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
*/
.start = ohci_pnx4008_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
......@@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
};
......@@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
goto out4;
}
hcd->self.hcpriv = (void *)hcd;
pnx4008_start_hc();
platform_set_drvdata(pdev, hcd);
ohci = hcd_to_ohci(hcd);
......
......@@ -40,6 +40,7 @@
#include <linux/dma-mapping.h>
#include <linux/usb.h>
#include <linux/bitops.h>
#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>
......@@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0;
}
static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
{
static struct dmi_system_id broken_wakeup_table[] = {
{
.ident = "Asus A7V8X",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"),
DMI_MATCH(DMI_BOARD_NAME, "A7V8X"),
DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"),
}
},
{ }
};
int port;
/* One of Asus's motherboards has a bug which causes it to
* wake up immediately from suspend-to-RAM if any of the ports
* are connected. In such cases we will not set EGSM.
*/
if (dmi_check_system(broken_wakeup_table)) {
for (port = 0; port < uhci->rh_numports; ++port) {
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
USBPORTSC_CCS)
return 1;
}
}
return 0;
}
static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
__releases(uhci->lock)
__acquires(uhci->lock)
{
int auto_stop;
int int_enable;
int int_enable, egsm_enable;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
......@@ -217,15 +248,18 @@ __acquires(uhci->lock)
}
/* Enable resume-detect interrupts if they work.
* Then enter Global Suspend mode, still configured.
* Then enter Global Suspend mode if _it_ works, still configured.
*/
egsm_enable = USBCMD_EGSM;
uhci->working_RD = 1;
int_enable = USBINTR_RESUME;
if (resume_detect_interrupts_are_broken(uhci)) {
if (remote_wakeup_is_broken(uhci))
egsm_enable = 0;
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable)
uhci->working_RD = int_enable = 0;
}
outw(int_enable, uhci->io_addr + USBINTR);
outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
mb();
udelay(5);
......
......@@ -348,13 +348,3 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
config USB_TRANCEVIBRATOR
tristate "PlayStation 2 Trance Vibrator driver support"
depends on USB
help
Say Y here if you want to connect a PlayStation 2 Trance Vibrator
device to your computer's USB port.
To compile this driver as a module, choose M here: the
module will be called trancevibrator.
......@@ -3,7 +3,7 @@
#
# Multipart objects.
wacom-objs := wacom_sys.o wacom_wac.o
wacom-objs := wacom_wac.o wacom_sys.o
usbhid-objs := hid-core.o
# Optional parts of multipart objects.
......@@ -48,7 +48,6 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -750,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
}
/*
* Extract/implement a data field from/to a report.
* Extract/implement a data field from/to a little endian report (bit array).
*/
static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
{
report += (offset >> 5) << 2; offset &= 31;
return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
u32 x;
report += offset >> 3; /* adjust byte index */
offset &= 8 - 1;
x = get_unaligned((u32 *) report);
x = le32_to_cpu(x);
x = (x >> offset) & ((1 << n) - 1);
return x;
}
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
{
report += (offset >> 5) << 2; offset &= 31;
put_unaligned((get_unaligned((__le64*)report)
& cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
| cpu_to_le64((__u64)value << offset), (__le64*)report);
u32 x;
report += offset >> 3;
offset &= 8 - 1;
x = get_unaligned((u32 *)report);
x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset));
x |= cpu_to_le32(value << offset);
put_unaligned(x,(u32 *)report);
}
/*
......
......@@ -256,10 +256,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
{
*x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
*y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
*press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F);
*press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
*touch = ~pkt[7] & 0x20;
return 1;
return *touch;
}
#endif
......
......@@ -63,6 +63,7 @@
* v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
* - where wacom_sys.c deals with system specific code,
* - and wacom_wac.c deals with Wacom specific code
* - Support Intuos3 4x6
*/
/*
......@@ -118,6 +119,7 @@ extern void wacom_input_sync(void *wcombo);
extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
......
......@@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data)
__u16 wacom_le16_to_cpu(unsigned char *data)
{
__u16 value;
value = be16_to_cpu(*(__be16 *) data);
value = le16_to_cpu(*(__le16 *) data);
return value;
}
......@@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
input_dev->evbit[0] |= BIT(EV_MSC);
input_dev->mscbit[0] |= BIT(MSC_SERIAL);
input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
}
void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
......@@ -155,11 +155,16 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
}
void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
}
void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
}
......@@ -218,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
wacom_wac->features = get_wacom_feature(id);
if (wacom_wac->features->pktlen > 10)
BUG();
BUG_ON(wacom_wac->features->pktlen > 10);
input_dev->name = wacom_wac->features->name;
wacom->wacom_wac = wacom_wac;
......@@ -244,7 +248,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_fill_int_urb(wacom->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
wacom_wac->data, wacom_wac->features->pktlen,
wacom_wac->features->irq, wacom, endpoint->bInterval);
wacom_sys_irq, wacom, endpoint->bInterval);
wacom->irq->transfer_dma = wacom->data_dma;
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
......@@ -278,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf)
input_unregister_device(wacom->dev);
usb_free_urb(wacom->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
kfree(wacom);
kfree(wacom->wacom_wac);
kfree(wacom);
}
}
......
This diff is collapsed.
......@@ -20,6 +20,7 @@ enum {
PTU,
PL,
INTUOS,
INTUOS3S,
INTUOS3,
INTUOS3L,
CINTIQ,
......@@ -34,7 +35,6 @@ struct wacom_features {
int pressure_max;
int distance_max;
int type;
usb_complete_t irq;
};
struct wacom_wac {
......
/*
* X-Box gamepad - v0.0.5
* X-Box gamepad - v0.0.6
*
* Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
*
* 2005 Dominic Cerquetti <binary1230@yahoo.com>
* 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -30,9 +31,10 @@
* - Greg Kroah-Hartman - usb-skeleton driver
*
* TODO:
* - fine tune axes
* - fine tune axes (especially trigger axes)
* - fix "analog" buttons (reported as digital now)
* - get rumble working
* - need USB IDs for other dance pads
*
* History:
*
......@@ -57,25 +59,40 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/smp_lock.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.5"
#define DRIVER_VERSION "v0.0.6"
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
#define XPAD_PKT_LEN 32
/* xbox d-pads should map to buttons, as is required for DDR pads
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS 0
#define MAP_DPAD_TO_AXES 1
#define MAP_DPAD_UNKNOWN -1
static int dpad_to_buttons;
module_param(dpad_to_buttons, bool, S_IRUGO);
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
static const struct xpad_device {
u16 idVendor;
u16 idProduct;
char *name;
u8 dpad_mapping;
} xpad_device[] = {
{ 0x045e, 0x0202, "Microsoft X-Box pad (US)" },
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" },
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" },
{ 0x0000, 0x0000, "X-Box pad" }
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
};
static const signed short xpad_btn[] = {
......@@ -84,11 +101,23 @@ static const signed short xpad_btn[] = {
-1 /* terminating entry */
};
/* only used if MAP_DPAD_TO_BUTTONS */
static const signed short xpad_btn_pad[] = {
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
-1 /* terminating entry */
};
static const signed short xpad_abs[] = {
ABS_X, ABS_Y, /* left stick */
ABS_RX, ABS_RY, /* right stick */
ABS_Z, ABS_RZ, /* triggers left/right */
ABS_HAT0X, ABS_HAT0Y, /* digital pad */
-1 /* terminating entry */
};
/* only used if MAP_DPAD_TO_AXES */
static const signed short xpad_abs_pad[] = {
ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
-1 /* terminating entry */
};
......@@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = {
MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad {
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
char phys[65]; /* physical device path */
char phys[65]; /* physical device path */
int dpad_mapping; /* map d-pad to buttons or to axes */
};
/*
......@@ -137,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
input_report_abs(dev, ABS_RZ, data[11]);
/* digital pad */
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
input_report_key(dev, BTN_0, data[2] & 0x01); // up
input_report_key(dev, BTN_1, data[2] & 0x02); // down
}
/* start/back buttons and stick press left/right */
input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
input_report_key(dev, BTN_THUMBR, data[2] >> 7);
input_report_key(dev, BTN_START, data[2] & 0x10);
input_report_key(dev, BTN_BACK, data[2] & 0x20);
input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
/* "analog" buttons A, B, X, Y */
input_report_key(dev, BTN_A, data[4]);
......@@ -206,6 +244,28 @@ static void xpad_close (struct input_dev *dev)
usb_kill_urb(xpad->irq_in);
}
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
{
set_bit(abs, input_dev->absbit);
switch (abs) {
case ABS_X:
case ABS_Y:
case ABS_RX:
case ABS_RY: /* the two sticks */
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
break;
case ABS_Z:
case ABS_RZ: /* the triggers */
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
break;
case ABS_HAT0X:
case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
break;
}
}
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev (intf);
......@@ -235,6 +295,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto fail2;
xpad->udev = udev;
xpad->dpad_mapping = xpad_device[i].dpad_mapping;
if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
xpad->dpad_mapping = dpad_to_buttons;
xpad->dev = input_dev;
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
......@@ -249,32 +312,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
/* set up buttons */
for (i = 0; xpad_btn[i] >= 0; i++)
set_bit(xpad_btn[i], input_dev->keybit);
if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
for (i = 0; xpad_btn_pad[i] >= 0; i++)
set_bit(xpad_btn_pad[i], input_dev->keybit);
for (i = 0; xpad_abs[i] >= 0; i++) {
signed short t = xpad_abs[i];
set_bit(t, input_dev->absbit);
switch (t) {
case ABS_X:
case ABS_Y:
case ABS_RX:
case ABS_RY: /* the two sticks */
input_set_abs_params(input_dev, t, -32768, 32767, 16, 128);
break;
case ABS_Z:
case ABS_RZ: /* the triggers */
input_set_abs_params(input_dev, t, 0, 255, 0, 0);
break;
case ABS_HAT0X:
case ABS_HAT0Y: /* the d-pad */
input_set_abs_params(input_dev, t, -1, 1, 0, 0);
break;
}
}
/* set up axes */
for (i = 0; xpad_abs[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs[i]);
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
for (i = 0; xpad_abs_pad[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev,
......@@ -305,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf)
usb_kill_urb(xpad->irq_in);
input_unregister_device(xpad->dev);
usb_free_urb(xpad->irq_in);
usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
kfree(xpad);
}
}
......
......@@ -223,6 +223,16 @@ config USB_LD
To compile this driver as a module, choose M here: the
module will be called ldusb.
config USB_TRANCEVIBRATOR
tristate "PlayStation 2 Trance Vibrator driver support"
depends on USB
help
Say Y here if you want to connect a PlayStation 2 Trance Vibrator
device to your computer's USB port.
To compile this driver as a module, choose M here: the
module will be called trancevibrator.
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
......
......@@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file)
retval = adu_release_internal(dev);
exit:
up(&dev->sem);
if (dev)
up(&dev->sem);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
}
......
......@@ -513,8 +513,6 @@ static void ftdi_elan_respond_work(void *data)
ftdi->disconnected += 1;
} else if (retval == -ENODEV) {
ftdi->disconnected += 1;
} else if (retval == -ENODEV) {
ftdi->disconnected += 1;
} else if (retval == -EILSEQ) {
ftdi->disconnected += 1;
} else {
......@@ -1186,11 +1184,8 @@ static ssize_t ftdi_elan_write(struct file *file,
int retval = 0;
struct urb *urb;
char *buf;
char data[30 *3 + 4];
char *d = data;
const char __user *s = user_buffer;
int m = (sizeof(data) - 1) / 3;
struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
struct usb_ftdi *ftdi = file->private_data;
if (ftdi->disconnected > 0) {
return -ENODEV;
}
......@@ -1220,27 +1215,18 @@ static ssize_t ftdi_elan_write(struct file *file,
if (retval) {
dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
"d\n", retval);
goto error_4;
goto error_3;
}
usb_free_urb(urb);
exit:;
if (count > m) {
int I = m - 1;
while (I-- > 0) {
d += sprintf(d, " %02X", 0x000000FF & *s++);
}
d += sprintf(d, " ..");
} else {
int I = count;
while (I-- > 0) {
d += sprintf(d, " %02X", 0x000000FF & *s++);
}
}
exit:
return count;
error_4: error_3:usb_buffer_free(ftdi->udev, count, buf,
urb->transfer_dma);
error_2:usb_free_urb(urb);
error_1:return retval;
error_3:
usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
error_2:
usb_free_urb(urb);
error_1:
return retval;
}
static struct file_operations ftdi_elan_fops = {
......
......@@ -207,6 +207,14 @@ config USB_NET_PLUSB
Choose this option if you're using a host-to-host cable
with one of these chips.
config USB_NET_MCS7830
tristate "MosChip MCS7830 based Ethernet adapters"
depends on USB_USBNET
help
Choose this option if you're using a 10/100 Ethernet USB2
adapter based on the MosChip 7830 controller. This includes
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
tristate "Host for RNDIS devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
......
......@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
ifeq ($(CONFIG_USB_DEBUG),y)
......
......@@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
struct usbnet *dev = netdev_priv(netdev);
u16 res;
mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev);
asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
mutex_unlock(&dev->phy_mutex);
devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff));
......@@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
u16 res = cpu_to_le16(val);
devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev);
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
mutex_unlock(&dev->phy_mutex);
}
/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
......@@ -700,32 +704,6 @@ static void asix_get_drvinfo (struct net_device *net,
info->eedump_len = data->eeprom_len;
}
static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
return mii_ethtool_gset(&dev->mii,cmd);
}
static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
int res = mii_ethtool_sset(&dev->mii,cmd);
/* link speed/duplex might have changed */
if (dev->driver_info->link_reset)
dev->driver_info->link_reset(dev);
return res;
}
static int asix_nway_reset(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
return mii_nway_restart(&dev->mii);
}
static u32 asix_get_link(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
......@@ -746,15 +724,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
static struct ethtool_ops ax88172_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = asix_get_link,
.nway_reset = asix_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
.set_wol = asix_set_wol,
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
.get_settings = asix_get_settings,
.set_settings = asix_set_settings,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static void ax88172_set_multicast(struct net_device *net)
......@@ -885,15 +863,15 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
static struct ethtool_ops ax88772_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = asix_get_link,
.nway_reset = asix_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
.set_wol = asix_set_wol,
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
.get_settings = asix_get_settings,
.set_settings = asix_set_settings,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static int ax88772_link_reset(struct usbnet *dev)
......@@ -1046,15 +1024,15 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
static struct ethtool_ops ax88178_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = asix_get_link,
.nway_reset = asix_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
.set_wol = asix_set_wol,
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
.get_settings = asix_get_settings,
.set_settings = asix_set_settings,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static int marvell_phy_init(struct usbnet *dev)
......
......@@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = {
static int __init cdc_init(void)
{
BUG_ON((sizeof(((struct usbnet *)0)->data)
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
return usb_register(&cdc_driver);
......
This diff is collapsed.
This diff is collapsed.
......@@ -669,6 +669,37 @@ static int usbnet_open (struct net_device *net)
* they'll probably want to use this base set.
*/
int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
if (!dev->mii.mdio_read)
return -EOPNOTSUPP;
return mii_ethtool_gset(&dev->mii, cmd);
}
EXPORT_SYMBOL_GPL(usbnet_get_settings);
int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
int retval;
if (!dev->mii.mdio_write)
return -EOPNOTSUPP;
retval = mii_ethtool_sset(&dev->mii, cmd);
/* link speed/duplex might have changed */
if (dev->driver_info->link_reset)
dev->driver_info->link_reset(dev);
return retval;
}
EXPORT_SYMBOL_GPL(usbnet_set_settings);
void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
{
struct usbnet *dev = netdev_priv(net);
......@@ -682,7 +713,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
}
EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
static u32 usbnet_get_link (struct net_device *net)
u32 usbnet_get_link (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
......@@ -690,9 +721,14 @@ static u32 usbnet_get_link (struct net_device *net)
if (dev->driver_info->check_connect)
return dev->driver_info->check_connect (dev) == 0;
/* if the device has mii operations, use those */
if (dev->mii.mdio_read)
return mii_link_ok(&dev->mii);
/* Otherwise, say we're up (to avoid breaking scripts) */
return 1;
}
EXPORT_SYMBOL_GPL(usbnet_get_link);
u32 usbnet_get_msglevel (struct net_device *net)
{
......@@ -710,10 +746,24 @@ void usbnet_set_msglevel (struct net_device *net, u32 level)
}
EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
int usbnet_nway_reset(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
if (!dev->mii.mdio_write)
return -EOPNOTSUPP;
return mii_nway_restart(&dev->mii);
}
EXPORT_SYMBOL_GPL(usbnet_nway_reset);
/* drivers may override default ethtool_ops in their bind() routine */
static struct ethtool_ops usbnet_ethtool_ops = {
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.get_drvinfo = usbnet_get_drvinfo,
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
};
......@@ -1094,6 +1144,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->delay.function = usbnet_bh;
dev->delay.data = (unsigned long) dev;
init_timer (&dev->delay);
mutex_init (&dev->phy_mutex);
SET_MODULE_OWNER (net);
dev->net = net;
......@@ -1225,7 +1276,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
static int __init usbnet_init(void)
{
/* compiler should optimize this out */
BUG_ON (sizeof (((struct sk_buff *)0)->cb)
BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
< sizeof (struct skb_data));
random_ether_addr(node_id);
......
......@@ -30,6 +30,7 @@ struct usbnet {
struct usb_device *udev;
struct driver_info *driver_info;
wait_queue_head_t *wait;
struct mutex phy_mutex;
/* i/o info: pipes etc */
unsigned in, out;
......@@ -168,9 +169,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
extern void usbnet_unlink_rx_urbs(struct usbnet *);
extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern u32 usbnet_get_link (struct net_device *net);
extern u32 usbnet_get_msglevel (struct net_device *);
extern void usbnet_set_msglevel (struct net_device *, u32);
extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
extern int usbnet_nway_reset(struct net_device *net);
/* messaging support includes the interface name, so it must not be
* used before it has one ... notably, in minidriver bind() calls.
......
......@@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232
To compile this driver as a module, choose M here: the
module will be called mct_u232.
config USB_SERIAL_MOS7720
tristate "USB Moschip 7720 Single Port 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.
To compile this driver as a module, choose M here: the
module will be called mos7720.
config USB_SERIAL_MOS7840
tristate "USB Moschip 7840/7820 USB Serial Driver"
depends on USB_SERIAL
......@@ -527,8 +537,7 @@ config USB_SERIAL_OPTION
The USB bus on these cards is not accessible externally.
Supported devices include (some of?) those made by:
Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
Anydata.
Option, Huawei, Audiovox, Novatel Wireless, or Anydata.
To compile this driver as a module, choose M here: the
module will be called option.
......
......@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
......
......@@ -18,12 +18,8 @@
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
{ USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
{ USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
......@@ -133,6 +129,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
kfree(buffer);
dev_err(&port->dev, "%s - no more urbs?\n",
__FUNCTION__);
result = -ENOMEM;
......
......@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
......
This diff is collapsed.
This diff is collapsed.
......@@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
}
mos7840_port = mos7840_get_port_private(port);
tty = mos7840_port->port->tty;
if (mos7840_port == NULL)
return -1;
tty = mos7840_port->port->tty;
dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
switch (cmd) {
......
This diff is collapsed.
......@@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE),
UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */
UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200,
"Mitsumi",
"USB FDD",
US_SC_DEVICE, US_PR_DEVICE, NULL,
......@@ -182,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
/* Reported by Bardur Arantsson <bardur@scientician.net> */
UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
"Nokia",
"6131",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
/* Reported by Alex Corcoles <alex@corcoles.net> */
UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
"Nokia",
"6234",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
......@@ -1291,6 +1306,13 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
/* Reported by Jan Mate <mate@fiit.stuba.sk> */
UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
"Sony Ericsson",
"P990i",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment