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
  ...
This commit is contained in:
Linus Torvalds 2006-10-17 15:05:22 -07:00
commit 699ddda6ec
50 changed files with 3901 additions and 646 deletions

View File

@ -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
--------
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.
Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.)
The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
8 axes and 10 buttons.
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)
Alls 8 axes work, though they all have the same range (-32768..32767)
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.
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

View File

@ -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/

View File

@ -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
},

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 @@ next_buffer:
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 @@ urbs:
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 */
},

View File

@ -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,
};

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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,29 +263,6 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
static void ehci_iaa_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 */
if (ehci->reclaim) {
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);
}
}
spin_unlock_irqrestore (&ehci->lock, flags);
}
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@ -294,7 +270,18 @@ static void ehci_watchdog (unsigned long param)
spin_lock_irqsave (&ehci->lock, flags);
/* stop async processing after it's idled a bit */
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
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);
ehci->reclaim_ready = 1;
}
}
/* 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 @@ rescan:
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);

View File

@ -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 */

View File

@ -303,7 +303,7 @@ restart:
/* 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);

View File

@ -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);
}
/*-------------------------------------------------------------------------*/

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}

View File

@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
if (wacom->features->type == WACOM_G4)
wacom_report_abs(wcombo, ABS_DISTANCE, data[6]);
wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
else
wacom_report_abs(wcombo, ABS_DISTANCE, data[7]);
wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
break;
}
}
@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
wacom->tool[idx] = BTN_TOOL_PEN;
}
/* only large I3 support Lens Cursor */
if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
(wacom->features->type == INTUOS3))) {
if(!((wacom->tool[idx] == BTN_TOOL_LENS)
&& ((wacom->features->type == INTUOS3)
|| (wacom->features->type == INTUOS3S)))) {
wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
wacom_report_key(wcombo, wacom->tool[idx], 1);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
@ -315,10 +316,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
wacom_report_key(wcombo, wacom->tool[idx], 0);
wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
return 2;
if(!((wacom->tool[idx] == BTN_TOOL_LENS)
&& ((wacom->features->type == INTUOS3)
|| (wacom->features->type == INTUOS3S)))) {
wacom_report_key(wcombo, wacom->tool[idx], 0);
wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
return 2;
}
}
return 0;
}
@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
data[2] | (data[3] & 0x1f) | data[4])
wacom_report_key(wcombo, wacom->tool[1], 1);
else
wacom_report_key(wcombo, wacom->tool[1], 0);
@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
((t - 1) / 2) : -t / 2);
}
} else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
} else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
/* 4D mouse packet */
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
- ((data[8] & 0x02) >> 1));
/* I3 2D mouse side buttons */
if (wacom->features->type == INTUOS3) {
if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
}
} else if (wacom->features->type < INTUOS3) {
} else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
/* Lens cursor packets */
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
return (wacom_ptu_irq(wacom_wac, wcombo));
break;
case INTUOS:
case INTUOS3S:
case INTUOS3:
case INTUOS3L:
case CINTIQ:
@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
case CINTIQ:
input_dev_i3(input_dev, wacom_wac);
/* fall through */
case INTUOS3S:
input_dev_i3s(input_dev, wacom_wac);
case INTUOS:
input_dev_i(input_dev, wacom_wac);
break;
@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
}
static struct wacom_features wacom_features[] = {
{ "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq },
{ "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq },
{ "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq },
{ "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq },
{ "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq},
{ "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq},
{ "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq },
{ "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq },
{ "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq },
{ "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq },
{ "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq },
{ "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq },
{ "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq },
{ "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq },
{ "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq },
{ "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq },
{ "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq },
{ "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq },
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq },
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq },
{ "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq },
{ "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq },
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
{ "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER },
{ "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE },
{ "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE },
{ "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE },
{ "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE },
{ "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE },
{ "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 },
{ "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 },
{ "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE },
{ "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE },
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE },
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE },
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE },
{ "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
{ "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
{ "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
{ "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
{ "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
{ "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
{ "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
{ "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
{ "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL },
{ "Wacom PL550", 8, 6144, 4608, 511, 0, PL },
{ "Wacom PL800", 8, 7220, 5780, 511, 0, PL },
{ "Wacom PL700", 8, 6758, 5406, 511, 0, PL },
{ "Wacom PL510", 8, 6282, 4762, 511, 0, PL },
{ "Wacom DTU710", 8, 34080, 27660, 511, 0, PL },
{ "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
{ "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
{ "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
{ "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
{ "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
{ }
};
@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ }

View File

@ -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 {

View File

@ -1,8 +1,9 @@
/*
* 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);
}
}

View File

@ -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

View File

@ -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/

View File

@ -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;
}

View File

@ -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 = {

View File

@ -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

View File

@ -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)

View File

@ -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 @@ out1:
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 @@ out1:
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)

View File

@ -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);

View File

@ -65,16 +65,6 @@
#undef DEBUG
#ifdef DEBUG
#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
#else
#define kaweth_dbg(format, arg...) do {} while (0)
#endif
#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
#include "kawethfw.h"
#define KAWETH_MTU 1514
@ -86,6 +76,9 @@
#define KAWETH_STATUS_BROKEN 0x0000001
#define KAWETH_STATUS_CLOSING 0x0000002
#define KAWETH_STATUS_SUSPENDING 0x0000004
#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
@ -112,6 +105,8 @@
#define STATE_MASK 0x40
#define STATE_SHIFT 5
#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data,
int len, int timeout);
static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
static int kaweth_resume(struct usb_interface *intf);
/****************************************************************
* usb_device_id
@ -179,6 +176,8 @@ static struct usb_driver kaweth_driver = {
.name = driver_name,
.probe = kaweth_probe,
.disconnect = kaweth_disconnect,
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table,
};
@ -222,6 +221,7 @@ struct kaweth_device
int suspend_lowmem_rx;
int suspend_lowmem_ctrl;
int linkstate;
int opened;
struct work_struct lowmem_work;
struct usb_device *dev;
@ -265,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth,
{
struct usb_ctrlrequest *dr;
kaweth_dbg("kaweth_control()");
dbg("kaweth_control()");
if(in_interrupt()) {
kaweth_dbg("in_interrupt()");
dbg("in_interrupt()");
return -EBUSY;
}
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
if (!dr) {
kaweth_dbg("kmalloc() failed");
dbg("kmalloc() failed");
return -ENOMEM;
}
@ -300,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth)
{
int retval;
kaweth_dbg("Reading kaweth configuration");
dbg("Reading kaweth configuration");
retval = kaweth_control(kaweth,
usb_rcvctrlpipe(kaweth->dev, 0),
@ -322,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
{
int retval;
kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
dbg("Setting URB size to %d", (unsigned)urb_size);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@ -344,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
{
int retval;
kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@ -367,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
{
int retval;
kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
dbg("Set receive filter to %d", (unsigned)receive_filter);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@ -392,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
__u8 type)
{
if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
kaweth_err("Firmware too big: %d", data_len);
err("Firmware too big: %d", data_len);
return -ENOSPC;
}
@ -403,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
kaweth->firmware_buf[4] = type;
kaweth->firmware_buf[5] = interrupt;
kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
kaweth->firmware_buf[2]);
kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
dbg("Downloading firmware at %p to kaweth device at %p",
data,
kaweth);
kaweth_dbg("Firmware length: %d", data_len);
dbg("Firmware length: %d", data_len);
return kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@ -437,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
kaweth->firmware_buf[6] = 0x00;
kaweth->firmware_buf[7] = 0x00;
kaweth_dbg("Triggering firmware");
dbg("Triggering firmware");
return kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@ -457,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
{
int result;
kaweth_dbg("kaweth_reset(%p)", kaweth);
dbg("kaweth_reset(%p)", kaweth);
result = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
USB_REQ_SET_CONFIGURATION,
@ -470,7 +470,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
mdelay(10);
kaweth_dbg("kaweth_reset() returns %d.",result);
dbg("kaweth_reset() returns %d.",result);
return result;
}
@ -534,7 +534,7 @@ static void kaweth_resubmit_tl(void *d)
{
struct kaweth_device *kaweth = (struct kaweth_device *)d;
if (kaweth->status | KAWETH_STATUS_CLOSING)
if (IS_BLOCKED(kaweth->status))
return;
if (kaweth->suspend_lowmem_rx)
@ -568,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth->suspend_lowmem_rx = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
}
kaweth_err("resubmitting rx_urb %d failed", result);
err("resubmitting rx_urb %d failed", result);
} else {
kaweth->suspend_lowmem_rx = 0;
}
@ -601,11 +601,15 @@ static void kaweth_usb_receive(struct urb *urb)
return;
}
if (kaweth->status & KAWETH_STATUS_CLOSING)
spin_lock(&kaweth->device_lock);
if (IS_BLOCKED(kaweth->status)) {
spin_unlock(&kaweth->device_lock);
return;
}
spin_unlock(&kaweth->device_lock);
if(urb->status && urb->status != -EREMOTEIO && count != 1) {
kaweth_err("%s RX status: %d count: %d packet_len: %d",
err("%s RX status: %d count: %d packet_len: %d",
net->name,
urb->status,
count,
@ -616,9 +620,9 @@ static void kaweth_usb_receive(struct urb *urb)
if(kaweth->net && (count > 2)) {
if(pkt_len > (count - 2)) {
kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
kaweth_err("Count 2: %x", count2);
err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
err("Packet len & 2047: %x", pkt_len & 2047);
err("Count 2: %x", count2);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
@ -655,7 +659,7 @@ static int kaweth_open(struct net_device *net)
struct kaweth_device *kaweth = netdev_priv(net);
int res;
kaweth_dbg("Opening network device.");
dbg("Opening network device.");
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
@ -678,6 +682,7 @@ static int kaweth_open(struct net_device *net)
usb_kill_urb(kaweth->rx_urb);
return -EIO;
}
kaweth->opened = 1;
netif_start_queue(net);
@ -688,14 +693,8 @@ static int kaweth_open(struct net_device *net)
/****************************************************************
* kaweth_close
****************************************************************/
static int kaweth_close(struct net_device *net)
static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
struct kaweth_device *kaweth = netdev_priv(net);
netif_stop_queue(net);
kaweth->status |= KAWETH_STATUS_CLOSING;
usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb);
usb_kill_urb(kaweth->tx_urb);
@ -706,6 +705,21 @@ static int kaweth_close(struct net_device *net)
we hit them again */
usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb);
}
/****************************************************************
* kaweth_close
****************************************************************/
static int kaweth_close(struct net_device *net)
{
struct kaweth_device *kaweth = netdev_priv(net);
netif_stop_queue(net);
kaweth->opened = 0;
kaweth->status |= KAWETH_STATUS_CLOSING;
kaweth_kill_urbs(kaweth);
kaweth->status &= ~KAWETH_STATUS_CLOSING;
@ -732,7 +746,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb)
if (unlikely(urb->status != 0))
if (urb->status != -ENOENT)
kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
dbg("%s: TX status %d.", kaweth->net->name, urb->status);
netif_wake_queue(kaweth->net);
dev_kfree_skb_irq(skb);
@ -752,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
netif_stop_queue(net);
if (IS_BLOCKED(kaweth->status)) {
goto skip;
}
/* We now decide whether we can put our special header into the sk_buff */
if (skb_cloned(skb) || skb_headroom(skb) < 2) {
@ -783,7 +800,8 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{
kaweth_warn("kaweth failed tx_urb %d", res);
warn("kaweth failed tx_urb %d", res);
skip:
kaweth->stats.tx_errors++;
netif_start_queue(net);
@ -812,7 +830,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
KAWETH_PACKET_FILTER_BROADCAST |
KAWETH_PACKET_FILTER_MULTICAST;
kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
dbg("Setting Rx mode to %d", packet_filter_bitmap);
netif_stop_queue(net);
@ -850,10 +868,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
KAWETH_CONTROL_TIMEOUT);
if(result < 0) {
kaweth_err("Failed to set Rx mode: %d", result);
err("Failed to set Rx mode: %d", result);
}
else {
kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
dbg("Set Rx mode to %d", packet_filter_bitmap);
}
}
}
@ -874,13 +892,49 @@ static void kaweth_tx_timeout(struct net_device *net)
{
struct kaweth_device *kaweth = netdev_priv(net);
kaweth_warn("%s: Tx timed out. Resetting.", net->name);
warn("%s: Tx timed out. Resetting.", net->name);
kaweth->stats.tx_errors++;
net->trans_start = jiffies;
usb_unlink_urb(kaweth->tx_urb);
}
/****************************************************************
* kaweth_suspend
****************************************************************/
static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
{
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
kaweth_kill_urbs(kaweth);
return 0;
}
/****************************************************************
* kaweth_resume
****************************************************************/
static int kaweth_resume(struct usb_interface *intf)
{
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
if (!kaweth->opened)
return 0;
kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
return 0;
}
/****************************************************************
* kaweth_probe
****************************************************************/
@ -895,15 +949,15 @@ static int kaweth_probe(
const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int result = 0;
kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
dev->devnum,
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct),
le16_to_cpu(dev->descriptor.bcdDevice));
kaweth_dbg("Device at %p", dev);
dbg("Device at %p", dev);
kaweth_dbg("Descriptor length: %x type: %x",
dbg("Descriptor length: %x type: %x",
(int)dev->descriptor.bLength,
(int)dev->descriptor.bDescriptorType);
@ -918,7 +972,7 @@ static int kaweth_probe(
spin_lock_init(&kaweth->device_lock);
init_waitqueue_head(&kaweth->term_wait);
kaweth_dbg("Resetting.");
dbg("Resetting.");
kaweth_reset(kaweth);
@ -928,17 +982,17 @@ static int kaweth_probe(
*/
if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) {
kaweth_info("Firmware present in device.");
info("Firmware present in device.");
} else {
/* Download the firmware */
kaweth_info("Downloading firmware...");
info("Downloading firmware...");
kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code,
len_kaweth_new_code,
100,
2)) < 0) {
kaweth_err("Error downloading firmware (%d)", result);
err("Error downloading firmware (%d)", result);
goto err_fw;
}
@ -947,7 +1001,7 @@ static int kaweth_probe(
len_kaweth_new_code_fix,
100,
3)) < 0) {
kaweth_err("Error downloading firmware fix (%d)", result);
err("Error downloading firmware fix (%d)", result);
goto err_fw;
}
@ -956,7 +1010,7 @@ static int kaweth_probe(
len_kaweth_trigger_code,
126,
2)) < 0) {
kaweth_err("Error downloading trigger code (%d)", result);
err("Error downloading trigger code (%d)", result);
goto err_fw;
}
@ -966,18 +1020,18 @@ static int kaweth_probe(
len_kaweth_trigger_code_fix,
126,
3)) < 0) {
kaweth_err("Error downloading trigger code fix (%d)", result);
err("Error downloading trigger code fix (%d)", result);
goto err_fw;
}
if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
kaweth_err("Error triggering firmware (%d)", result);
err("Error triggering firmware (%d)", result);
goto err_fw;
}
/* Device will now disappear for a moment... */
kaweth_info("Firmware loaded. I'll be back...");
info("Firmware loaded. I'll be back...");
err_fw:
free_page((unsigned long)kaweth->firmware_buf);
free_netdev(netdev);
@ -987,14 +1041,14 @@ err_fw:
result = kaweth_read_configuration(kaweth);
if(result < 0) {
kaweth_err("Error reading configuration (%d), no net device created", result);
err("Error reading configuration (%d), no net device created", result);
goto err_free_netdev;
}
kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
info("Statistics collection: %x", kaweth->configuration.statistics_mask);
info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
(int)kaweth->configuration.hw_addr[0],
(int)kaweth->configuration.hw_addr[1],
(int)kaweth->configuration.hw_addr[2],
@ -1005,17 +1059,17 @@ err_fw:
if(!memcmp(&kaweth->configuration.hw_addr,
&bcast_addr,
sizeof(bcast_addr))) {
kaweth_err("Firmware not functioning properly, no net device created");
err("Firmware not functioning properly, no net device created");
goto err_free_netdev;
}
if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
kaweth_dbg("Error setting URB size");
dbg("Error setting URB size");
goto err_free_netdev;
}
if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
kaweth_err("Error setting SOFS wait");
err("Error setting SOFS wait");
goto err_free_netdev;
}
@ -1025,11 +1079,11 @@ err_fw:
KAWETH_PACKET_FILTER_MULTICAST);
if(result < 0) {
kaweth_err("Error setting receive filter");
err("Error setting receive filter");
goto err_free_netdev;
}
kaweth_dbg("Initializing net device.");
dbg("Initializing net device.");
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
@ -1086,13 +1140,13 @@ err_fw:
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
kaweth_err("Error registering netdev.");
err("Error registering netdev.");
goto err_intfdata;
}
kaweth_info("kaweth interface created at %s", kaweth->net->name);
info("kaweth interface created at %s", kaweth->net->name);
kaweth_dbg("Kaweth probe returning.");
dbg("Kaweth probe returning.");
return 0;
@ -1121,16 +1175,16 @@ static void kaweth_disconnect(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
struct net_device *netdev;
kaweth_info("Unregistering");
info("Unregistering");
usb_set_intfdata(intf, NULL);
if (!kaweth) {
kaweth_warn("unregistering non-existant device");
warn("unregistering non-existant device");
return;
}
netdev = kaweth->net;
kaweth_dbg("Unregistering net device");
dbg("Unregistering net device");
unregister_netdev(netdev);
usb_free_urb(kaweth->rx_urb);
@ -1185,7 +1239,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
// timeout
kaweth_warn("usb_control/bulk_msg: timeout");
warn("usb_control/bulk_msg: timeout");
usb_kill_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
@ -1234,7 +1288,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
****************************************************************/
static int __init kaweth_init(void)
{
kaweth_dbg("Driver loading");
dbg("Driver loading");
return usb_register(&kaweth_driver);
}

534
drivers/usb/net/mcs7830.c Normal file
View File

@ -0,0 +1,534 @@
/*
* MosChips MCS7830 based USB 2.0 Ethernet Devices
*
* based on usbnet.c, asix.c and the vendor provided mcs7830 driver
*
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/init.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include "usbnet.h"
/* requests */
#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \
USB_RECIP_DEVICE)
#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \
USB_RECIP_DEVICE)
#define MCS7830_RD_BREQ 0x0E
#define MCS7830_WR_BREQ 0x0D
#define MCS7830_CTRL_TIMEOUT 1000
#define MCS7830_MAX_MCAST 64
#define MCS7830_VENDOR_ID 0x9710
#define MCS7830_PRODUCT_ID 0x7830
#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
ADVERTISE_100HALF | ADVERTISE_10FULL | \
ADVERTISE_10HALF | ADVERTISE_CSMA)
/* HIF_REG_XX coressponding index value */
enum {
HIF_REG_MULTICAST_HASH = 0x00,
HIF_REG_PACKET_GAP1 = 0x08,
HIF_REG_PACKET_GAP2 = 0x09,
HIF_REG_PHY_DATA = 0x0a,
HIF_REG_PHY_CMD1 = 0x0c,
HIF_REG_PHY_CMD1_READ = 0x40,
HIF_REG_PHY_CMD1_WRITE = 0x20,
HIF_REG_PHY_CMD1_PHYADDR = 0x01,
HIF_REG_PHY_CMD2 = 0x0d,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
HIF_REG_CONFIG = 0x0e,
HIF_REG_CONFIG_CFG = 0x80,
HIF_REG_CONFIG_SPEED100 = 0x40,
HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
HIF_REG_CONFIG_RXENABLE = 0x10,
HIF_REG_CONFIG_TXENABLE = 0x08,
HIF_REG_CONFIG_SLEEPMODE = 0x04,
HIF_REG_CONFIG_ALLMULTICAST = 0x02,
HIF_REG_CONFIG_PROMISCIOUS = 0x01,
HIF_REG_ETHERNET_ADDR = 0x0f,
HIF_REG_22 = 0x15,
HIF_REG_PAUSE_THRESHOLD = 0x16,
HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
};
struct mcs7830_data {
u8 multi_filter[8];
u8 config;
};
static const char driver_name[] = "MOSCHIP usb-ethernet driver";
static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_device *xdev = dev->udev;
int ret;
ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
MCS7830_RD_BMREQ, 0x0000, index, data,
size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
return ret;
}
static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_device *xdev = dev->udev;
int ret;
ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
MCS7830_WR_BMREQ, 0x0000, index, data,
size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
return ret;
}
static void mcs7830_async_cmd_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
if (urb->status < 0)
printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
urb->status);
kfree(req);
usb_free_urb(urb);
}
static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_ctrlrequest *req;
int ret;
struct urb *urb;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_dbg(&dev->udev->dev, "Error allocating URB "
"in write_cmd_async!");
return;
}
req = kmalloc(sizeof *req, GFP_ATOMIC);
if (!req) {
dev_err(&dev->udev->dev, "Failed to allocate memory for "
"control request");
goto out;
}
req->bRequestType = MCS7830_WR_BMREQ;
req->bRequest = MCS7830_WR_BREQ;
req->wValue = 0;
req->wIndex = cpu_to_le16(index);
req->wLength = cpu_to_le16(size);
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, data, size,
mcs7830_async_cmd_callback, req);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
dev_err(&dev->udev->dev, "Error submitting the control "
"message: ret=%d", ret);
goto out;
}
return;
out:
kfree(req);
usb_free_urb(urb);
}
static int mcs7830_get_address(struct usbnet *dev)
{
int ret;
ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
dev->net->dev_addr);
if (ret < 0)
return ret;
return 0;
}
static int mcs7830_read_phy(struct usbnet *dev, u8 index)
{
int ret;
int i;
__le16 val;
u8 cmd[2] = {
HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
};
mutex_lock(&dev->phy_mutex);
/* write the MII command */
ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if (ret < 0)
goto out;
/* wait for the data to become valid, should be within < 1ms */
for (i = 0; i < 10; i++) {
ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
break;
ret = -EIO;
msleep(1);
}
if (ret < 0)
goto out;
/* read actual register contents */
ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
if (ret < 0)
goto out;
ret = le16_to_cpu(val);
dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
index, val, i);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
{
int ret;
int i;
__le16 le_val;
u8 cmd[2] = {
HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
};
mutex_lock(&dev->phy_mutex);
/* write the new register contents */
le_val = cpu_to_le16(val);
ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
if (ret < 0)
goto out;
/* write the MII command */
ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if (ret < 0)
goto out;
/* wait for the command to be accepted by the PHY */
for (i = 0; i < 10; i++) {
ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
break;
ret = -EIO;
msleep(1);
}
if (ret < 0)
goto out;
ret = 0;
dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
index, val, i);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
/*
* This algorithm comes from the original mcs7830 version 1.4 driver,
* not sure if it is needed.
*/
static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
{
int ret;
/* Enable all media types */
ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
/* First reset BMCR */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
/* Enable Auto Neg */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
/* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART );
return ret < 0 ? : 0;
}
/*
* if we can read register 22, the chip revision is C or higher
*/
static int mcs7830_get_rev(struct usbnet *dev)
{
u8 dummy[2];
int ret;
ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
if (ret > 0)
return 2; /* Rev C or later */
return 1; /* earlier revision */
}
/*
* On rev. C we need to set the pause threshold
*/
static void mcs7830_rev_C_fixup(struct usbnet *dev)
{
u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
int retry;
for (retry = 0; retry < 2; retry++) {
if (mcs7830_get_rev(dev) == 2) {
dev_info(&dev->udev->dev, "applying rev.C fixup\n");
mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
1, &pause_threshold);
}
msleep(1);
}
}
static int mcs7830_init_dev(struct usbnet *dev)
{
int ret;
int retry;
/* Read MAC address from EEPROM */
ret = -EINVAL;
for (retry = 0; retry < 5 && ret; retry++)
ret = mcs7830_get_address(dev);
if (ret) {
dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
goto out;
}
/* Set up PHY */
ret = mcs7830_set_autoneg(dev, 0);
if (ret) {
dev_info(&dev->udev->dev, "Cannot set autoneg\n");
goto out;
}
mcs7830_rev_C_fixup(dev);
ret = 0;
out:
return ret;
}
static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
int location)
{
struct usbnet *dev = netdev->priv;
return mcs7830_read_phy(dev, location);
}
static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
int location, int val)
{
struct usbnet *dev = netdev->priv;
mcs7830_write_phy(dev, location, val);
}
static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
/* credits go to asix_set_multicast */
static void mcs7830_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
data->config = HIF_REG_CONFIG_TXENABLE;
/* this should not be needed, but it doesn't work otherwise */
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
if (net->flags & IFF_PROMISC) {
data->config |= HIF_REG_CONFIG_PROMISCIOUS;
} else if (net->flags & IFF_ALLMULTI
|| net->mc_count > MCS7830_MAX_MCAST) {
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
} else if (net->mc_count == 0) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
struct dev_mc_list *mc_list = net->mc_list;
u32 crc_bits;
int i;
memset(data->multi_filter, 0, sizeof data->multi_filter);
/* Build the multicast hash filter. */
for (i = 0; i < net->mc_count; i++) {
crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
mc_list = mc_list->next;
}
mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
sizeof data->multi_filter,
data->multi_filter);
}
mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
}
static int mcs7830_get_regs_len(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
switch (mcs7830_get_rev(dev)) {
case 1:
return 21;
case 2:
return 32;
}
return 0;
}
static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
{
usbnet_get_drvinfo(net, drvinfo);
drvinfo->regdump_len = mcs7830_get_regs_len(net);
}
static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
{
struct usbnet *dev = netdev_priv(net);
regs->version = mcs7830_get_rev(dev);
mcs7830_get_reg(dev, 0, regs->len, data);
}
static struct ethtool_ops mcs7830_ethtool_ops = {
.get_drvinfo = mcs7830_get_drvinfo,
.get_regs_len = mcs7830_get_regs_len,
.get_regs = mcs7830_get_regs,
/* common usbnet calls */
.get_link = usbnet_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
{
struct net_device *net = dev->net;
int ret;
ret = mcs7830_init_dev(dev);
if (ret)
goto out;
net->do_ioctl = mcs7830_ioctl;
net->ethtool_ops = &mcs7830_ethtool_ops;
net->set_multicast_list = mcs7830_set_multicast;
mcs7830_set_multicast(net);
/* reserve space for the status byte on rx */
dev->rx_urb_size = ETH_FRAME_LEN + 1;
dev->mii.mdio_read = mcs7830_mdio_read;
dev->mii.mdio_write = mcs7830_mdio_write;
dev->mii.dev = net;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
ret = usbnet_get_endpoints(dev, udev);
out:
return ret;
}
/* The chip always appends a status bytes that we need to strip */
static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
if (skb->len == 0) {
dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
return 0;
}
skb_trim(skb, skb->len - 1);
status = skb->data[skb->len];
if (status != 0x20)
dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
return skb->len > 0;
}
static const struct driver_info moschip_info = {
.description = "MOSCHIP 7830 usb-NET adapter",
.bind = mcs7830_bind,
.rx_fixup = mcs7830_rx_fixup,
.flags = FLAG_ETHER,
.in = 1,
.out = 2,
};
static const struct usb_device_id products[] = {
{
USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
.driver_info = (unsigned long) &moschip_info,
},
{},
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver mcs7830_driver = {
.name = driver_name,
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init mcs7830_init(void)
{
return usb_register(&mcs7830_driver);
}
module_init(mcs7830_init);
static void __exit mcs7830_exit(void)
{
usb_deregister(&mcs7830_driver);
}
module_exit(mcs7830_exit);
MODULE_DESCRIPTION("USB to network adapter MCS7830)");
MODULE_LICENSE("GPL");

View File

@ -669,6 +669,37 @@ done:
* 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);

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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 */
};

View File

@ -1,16 +1,16 @@
/*
* USB FTDI SIO driver
*
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@ -32,7 +32,7 @@
* Changed full name of USB-UIRT device to avoid "/" character.
* Added FTDI's alternate PID (0x6006) for FT232/245 devices.
* Added PID for "ELV USB Module UO100" from Stefan Frings.
*
*
* (21/Oct/2003) Ian Abbott
* Renamed some VID/PID macros for Matrix Orbital and Perle Systems
* devices. Removed Matrix Orbital and Perle Systems devices from the
@ -69,7 +69,7 @@
* does not incure any measurable overhead. This also relies on the fact
* that we have proper reference counting logic for urbs. I nicked this
* from Greg KH's Visor driver.
*
*
* (23/Jun/2003) Ian Abbott
* Reduced flip buffer pushes and corrected a data length test in
* ftdi_read_bulk_callback.
@ -77,7 +77,7 @@
*
* (21/Jun/2003) Erik Nygren
* Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
* See <http://www.home-electro.com/tira1.htm>. Only operates properly
* See <http://www.home-electro.com/tira1.htm>. Only operates properly
* at 100000 and RTS-CTS, so set custom divisor mode on startup.
* Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
*
@ -137,17 +137,17 @@
* (17/Feb/2003) Bill Ryder
* Added write urb buffer pool on a per device basis
* Added more checking for open file on callbacks (fixed OOPS)
* Added CrystalFontz 632 and 634 PIDs
* Added CrystalFontz 632 and 634 PIDs
* (thanx to CrystalFontz for the sample devices - they flushed out
* some driver bugs)
* Minor debugging message changes
* Added throttle, unthrottle and chars_in_buffer functions
* Fixed FTDI_SIO (the original device) bug
* Fixed some shutdown handling
*
*
*
*
*
*
*
*
* (07/Jun/2002) Kuba Ober
* Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
* function. It was getting too complex.
@ -158,7 +158,7 @@
*
* (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
* Not tested by me but it doesn't break anything I use.
*
*
* (04/Jan/2002) Kuba Ober
* Implemented 38400 baudrate kludge, where it can be substituted with other
* values. That's the only way to set custom baudrates.
@ -179,7 +179,7 @@
* (the previous version caused panics)
* Removed port iteration code since the device only has one I/O port and it
* was wrong anyway.
*
*
* (31/May/2001) gkh
* Switched from using spinlock to a semaphore, which fixes lots of problems.
*
@ -188,16 +188,16 @@
* Cleaned up comments for 8U232
* Added parity, framing and overrun error handling
* Added receive break handling.
*
*
* (04/08/2001) gb
* Identify version on module load.
*
*
* (18/March/2001) Bill Ryder
* (Not released)
* Added send break handling. (requires kernel patch too)
* Fixed 8U232AM hardware RTS/CTS etc status reporting.
* Added flipbuf fix copied from generic device
*
*
* (12/3/2000) Bill Ryder
* Added support for 8U232AM device.
* Moved PID and VIDs into header file only.
@ -211,14 +211,14 @@
* Cleaned up comments. Removed multiple PID/VID definitions.
* Factorised cts/dtr code
* Made use of __FUNCTION__ in dbg's
*
*
* (11/01/2000) Adam J. Richter
* usb_device_id table support
*
*
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
*
*
* (09/11/2000) gkh
* Removed DEBUG #ifdefs with call to usb_serial_debug_data
*
@ -226,11 +226,11 @@
* Added module_init and module_exit functions to handle the fact that this
* driver is a loadable module now.
*
* (04/04/2000) Bill Ryder
* (04/04/2000) Bill Ryder
* Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
* handled elsewhere in the tty io driver chain).
*
* (03/30/2000) Bill Ryder
* (03/30/2000) Bill Ryder
* Implemented lots of ioctls
* Fixed a race condition in write
* Changed some dbg's to errs
@ -444,13 +444,13 @@ static struct usb_device_id id_table_combined [] = {
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@ -522,7 +522,7 @@ static struct usb_driver ftdi_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
.no_dynamic_id = 1,
.no_dynamic_id = 1,
};
static const char *ftdi_chip_name[] = {
@ -548,13 +548,13 @@ struct ftdi_private {
int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
__u16 last_set_data_urb_value ;
/* the last data state set - needed for doing a break */
int write_offset; /* This is the offset in the usb data block to write the serial data -
int write_offset; /* This is the offset in the usb data block to write the serial data -
* it is different between devices
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
__u8 rx_flags; /* receive state flags (throttling) */
spinlock_t rx_lock; /* spinlock for receive state */
struct work_struct rx_work;
@ -721,7 +721,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
urb_value |= FTDI_SIO_SET_RTS_HIGH;
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
urb_value, priv->interface,
buf, 0, WDR_TIMEOUT);
@ -768,7 +768,7 @@ static int change_speed(struct usb_serial_port *port)
if (priv->interface) { /* FT2232C */
urb_index = (__u16)((urb_index << 8) | priv->interface);
}
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
@ -827,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
/* 3. Convert baudrate to device-specific divisor */
if (!baud) baud = 9600;
if (!baud) baud = 9600;
switch(priv->chip_type) {
case SIO: /* SIO chip */
switch(baud) {
@ -843,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
div_value = ftdi_sio_b9600;
div_okay = 0;
}
@ -925,7 +925,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
(new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@ -950,7 +950,7 @@ check_and_exit:
(old_priv.custom_divisor != priv->custom_divisor))) {
change_speed(port);
}
return (0);
} /* set_serial_info */
@ -1022,18 +1022,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
struct usb_device *udev;
unsigned short latency = 0;
int rv = 0;
udev = to_usb_device(dev);
dbg("%s",__FUNCTION__);
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
0, priv->interface,
0, priv->interface,
(char*) &latency, 1, WDR_TIMEOUT);
if (rv < 0) {
dev_err(dev, "Unable to read latency timer: %i", rv);
return -EIO;
@ -1051,23 +1051,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
udev = to_usb_device(dev);
dbg("%s: setting latency timer = %i", __FUNCTION__, v);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
v, priv->interface,
v, priv->interface,
buf, 0, WDR_TIMEOUT);
if (rv < 0) {
dev_err(dev, "Unable to write latency timer: %i", rv);
return -EIO;
}
return count;
}
@ -1082,23 +1082,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
udev = to_usb_device(dev);
dbg("%s: setting event char = %i", __FUNCTION__, v);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
v, priv->interface,
v, priv->interface,
buf, 0, WDR_TIMEOUT);
if (rv < 0) {
dbg("Unable to write event character: %i", rv);
return -EIO;
}
return count;
}
@ -1135,11 +1135,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
struct ftdi_private *priv;
struct usb_device *udev;
dbg("%s",__FUNCTION__);
dbg("%s",__FUNCTION__);
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&udev->dev, &dev_attr_event_char);
@ -1147,7 +1147,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
device_remove_file(&udev->dev, &dev_attr_latency_timer);
}
}
}
/*
@ -1258,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
} /* ftdi_HE_TIRA1_setup */
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
* it is called when the usb device is disconnected
*
* usbserial:usb_serial_disconnect
@ -1269,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__);
remove_sysfs_attrs(serial);
/* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close)
/* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close)
*/
if (priv) {
@ -1293,7 +1293,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
@ -1312,8 +1312,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
FTDI_SIO_RESET_SIO,
FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
FTDI_SIO_RESET_SIO,
priv->interface, buf, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change
@ -1350,12 +1350,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/*
/*
* usbserial:__serial_close only calls ftdi_close if the point is open
*
* This only gets called when it is the last close
*
*
*
*
*/
static void ftdi_close (struct usb_serial_port *port, struct file *filp)
@ -1368,14 +1368,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
if (c_cflag & HUPCL){
/* Disable flow control */
if (usb_control_msg(port->serial->dev,
if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
err("error from flowcontrol urb");
}
}
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@ -1384,14 +1384,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* cancel any scheduled reading */
cancel_delayed_work(&priv->rx_work);
flush_scheduled_work();
/* shutdown our bulk read */
if (port->read_urb)
usb_kill_urb(port->read_urb);
} /* ftdi_close */
/* The SIO requires the first byte to have:
* B0 1
* B1 0
@ -1423,7 +1423,7 @@ static int ftdi_write (struct usb_serial_port *port,
return 0;
}
spin_unlock_irqrestore(&priv->tx_lock, flags);
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
@ -1462,7 +1462,7 @@ static int ftdi_write (struct usb_serial_port *port,
user_pktsz = todo;
}
/* Write the control byte at the front of the packet*/
*first_byte = 1 | ((user_pktsz) << 2);
*first_byte = 1 | ((user_pktsz) << 2);
/* Copy data for packet */
memcpy (first_byte + data_offset,
current_position, user_pktsz);
@ -1479,7 +1479,7 @@ static int ftdi_write (struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
/* fill the buffer and send it */
usb_fill_bulk_urb(urb, port->serial->dev,
usb_fill_bulk_urb(urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
buffer, transfer_size,
ftdi_write_bulk_callback, port);
@ -1520,7 +1520,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
@ -1651,7 +1651,7 @@ static void ftdi_process_read (void *param)
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
unsigned char *data;
unsigned char *data;
int i;
int result;
@ -1759,7 +1759,7 @@ static void ftdi_process_read (void *param)
}
if (length > 0) {
for (i = 2; i < length+2; i++) {
/* Note that the error flag is duplicated for
/* Note that the error flag is duplicated for
every character received since we don't know
which character it applied to */
tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
@ -1773,7 +1773,7 @@ static void ftdi_process_read (void *param)
This doesn't work well since the application receives a never
ending stream of bad data - even though new data hasn't been sent.
Therefore I (bill) have taken this out.
However - this might make sense for framing errors and so on
However - this might make sense for framing errors and so on
so I am leaving the code in for now.
*/
else {
@ -1827,7 +1827,7 @@ static void ftdi_process_read (void *param)
/* if the port is closed stop trying to read */
if (port->open_count > 0){
/* Continue trying to always read */
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
@ -1844,9 +1844,9 @@ static void ftdi_process_read (void *param)
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value = 0;
__u16 urb_value = 0;
char buf[1];
/* break_state = -1 to turn on break, and 0 to turn off break */
/* see drivers/char/tty_io.c to see it used */
/* last_set_data_urb_value NEVER has the break bit set in it */
@ -1854,20 +1854,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
if (break_state) {
urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
} else {
urb_value = priv->last_set_data_urb_value;
urb_value = priv->last_set_data_urb_value;
}
if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
}
}
dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
}
@ -1883,12 +1883,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
// Added for xon/xoff support
unsigned int iflag = port->tty->termios->c_iflag;
unsigned char vstop;
unsigned char vstart;
dbg("%s", __FUNCTION__);
/* Force baud rate if this device requires it, unless it is set to B0. */
@ -1906,20 +1906,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
cflag = port->tty->termios->c_cflag;
/* FIXME -For this cut I don't care if the line is really changing or
not - so just do the change regardless - should be able to
/* FIXME -For this cut I don't care if the line is really changing or
not - so just do the change regardless - should be able to
compare old_termios and tty->termios */
/* NOTE These routines can get interrupted by
ftdi_sio_read_bulk_callback - need to examine what this
/* NOTE These routines can get interrupted by
ftdi_sio_read_bulk_callback - need to examine what this
means - don't see any problems yet */
/* Set number of data bits, parity, stop bits */
urb_value = 0;
urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
FTDI_SIO_SET_DATA_STOP_BITS_1);
urb_value |= (cflag & PARENB ?
(cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
urb_value |= (cflag & PARENB ?
(cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
FTDI_SIO_SET_DATA_PARITY_EVEN) :
FTDI_SIO_SET_DATA_PARITY_NONE);
if (cflag & CSIZE) {
@ -1936,25 +1936,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* This is needed by the break command since it uses the same command - but is
* or'ed with this value */
priv->last_set_data_urb_value = urb_value;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) {
err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
}
}
/* Now do the baudrate */
if ((cflag & CBAUD) == B0 ) {
/* Disable flow control */
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s error from disable flowcontrol urb", __FUNCTION__);
}
}
/* Drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
@ -1972,16 +1972,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
if (usb_control_msg(dev,
if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to set to rts/cts flow control");
}
} else {
}
} else {
/*
* Xon/Xoff code
*
@ -2011,16 +2011,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
dbg("%s Turning off hardware flow control", __FUNCTION__);
if (usb_control_msg(dev,
if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to clear flow control");
}
}
}
}
return;
} /* ftdi_termios */
@ -2036,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
switch (priv->chip_type) {
case SIO:
/* Request the status from the device */
if ((ret = usb_control_msg(port->serial->dev,
if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, 0,
0, 0,
buf, 1, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@ -2052,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT2232C:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(port->serial->dev,
if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, priv->interface,
0, priv->interface,
buf, 2, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@ -2067,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
return -EFAULT;
break;
}
return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
priv->last_dtr_rts;
priv->last_dtr_rts;
}
static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
@ -2138,11 +2138,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
break;
default:
break;
}
/* This is not necessarily an error - turns out the higher layers will do
/* This is not necessarily an error - turns out the higher layers will do
* some ioctls itself (see comment above)
*/
dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
@ -2199,7 +2199,7 @@ static int __init ftdi_init (void)
if (retval)
goto failed_sio_register;
retval = usb_register(&ftdi_driver);
if (retval)
if (retval)
goto failed_usb_register;
info(DRIVER_VERSION ":" DRIVER_DESC);

1683
drivers/usb/serial/mos7720.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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) {

View File

@ -1,21 +1,35 @@
/*
* Sierra Wireless CDMA Wireless Serial USB driver
*
* Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
* Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*/
USB Driver for Sierra Wireless
Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
This driver is free software; you can redistribute it and/or modify
it under the terms of Version 2 of the GNU General Public License as
published by the Free Software Foundation.
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
History:
*/
#define DRIVER_VERSION "v.1.0.5"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
@ -23,53 +37,674 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
/* Following devices are supported in the airprime.c driver */
/* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
/* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_device_id id_table_1port [] = {
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
{ }
};
static struct usb_device_id id_table_3port [] = {
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
{ }
};
static struct usb_driver sierra_driver = {
.name = "sierra_wireless",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.name = "sierra",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver sierra_device = {
static int debug;
/* per port private data */
#define N_IN_URB 4
#define N_OUT_URB 1
#define IN_BUFLEN 4096
#define OUT_BUFLEN 128
struct sierra_port_private {
/* Input endpoints and buffer for this port */
struct urb *in_urbs[N_IN_URB];
char in_buffer[N_IN_URB][IN_BUFLEN];
/* Output endpoints and buffer for this port */
struct urb *out_urbs[N_OUT_URB];
char out_buffer[N_OUT_URB][OUT_BUFLEN];
/* Settings for the port */
int rts_state; /* Handshaking pins (outputs) */
int dtr_state;
int cts_state; /* Handshaking pins (inputs) */
int dsr_state;
int dcd_state;
int ri_state;
unsigned long tx_start_time[N_OUT_URB];
};
static int sierra_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
dbg("%s", __FUNCTION__);
portdata = usb_get_serial_port_data(port);
if (port->tty) {
int val = 0;
if (portdata->dtr_state)
val |= 0x01;
if (portdata->rts_state)
val |= 0x02;
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
}
return 0;
}
static void sierra_rx_throttle(struct usb_serial_port *port)
{
dbg("%s", __FUNCTION__);
}
static void sierra_rx_unthrottle(struct usb_serial_port *port)
{
dbg("%s", __FUNCTION__);
}
static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
{
/* Unfortunately, I don't know how to send a break */
dbg("%s", __FUNCTION__);
}
static void sierra_set_termios(struct usb_serial_port *port,
struct termios *old_termios)
{
dbg("%s", __FUNCTION__);
sierra_send_setup(port);
}
static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
{
unsigned int value;
struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port);
value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
((portdata->dtr_state) ? TIOCM_DTR : 0) |
((portdata->cts_state) ? TIOCM_CTS : 0) |
((portdata->dsr_state) ? TIOCM_DSR : 0) |
((portdata->dcd_state) ? TIOCM_CAR : 0) |
((portdata->ri_state) ? TIOCM_RNG : 0);
return value;
}
static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port);
if (set & TIOCM_RTS)
portdata->rts_state = 1;
if (set & TIOCM_DTR)
portdata->dtr_state = 1;
if (clear & TIOCM_RTS)
portdata->rts_state = 0;
if (clear & TIOCM_DTR)
portdata->dtr_state = 0;
return sierra_send_setup(port);
}
static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
}
/* Write */
static int sierra_write(struct usb_serial_port *port,
const unsigned char *buf, int count)
{
struct sierra_port_private *portdata;
int i;
int left, todo;
struct urb *this_urb = NULL; /* spurious */
int err;
portdata = usb_get_serial_port_data(port);
dbg("%s: write (%d chars)", __FUNCTION__, count);
i = 0;
left = count;
for (i=0; left > 0 && i < N_OUT_URB; i++) {
todo = left;
if (todo > OUT_BUFLEN)
todo = OUT_BUFLEN;
this_urb = portdata->out_urbs[i];
if (this_urb->status == -EINPROGRESS) {
if (time_before(jiffies,
portdata->tx_start_time[i] + 10 * HZ))
continue;
usb_unlink_urb(this_urb);
continue;
}
if (this_urb->status != 0)
dbg("usb_write %p failed (err=%d)",
this_urb, this_urb->status);
dbg("%s: endpoint %d buf %d", __FUNCTION__,
usb_pipeendpoint(this_urb->pipe), i);
/* send the data */
memcpy (this_urb->transfer_buffer, buf, todo);
this_urb->transfer_buffer_length = todo;
this_urb->dev = port->serial->dev;
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
dbg("usb_submit_urb %p (write bulk) failed "
"(%d, has %d)", this_urb,
err, this_urb->status);
continue;
}
portdata->tx_start_time[i] = jiffies;
buf += todo;
left -= todo;
}
count -= left;
dbg("%s: wrote (did %d)", __FUNCTION__, count);
return count;
}
static void sierra_indat_callback(struct urb *urb)
{
int err;
int endpoint;
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
dbg("%s: %p", __FUNCTION__, urb);
endpoint = usb_pipeendpoint(urb->pipe);
port = (struct usb_serial_port *) urb->context;
if (urb->status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
__FUNCTION__, urb->status, endpoint);
} else {
tty = port->tty;
if (urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
} else {
dbg("%s: empty read urb received", __FUNCTION__);
}
/* Resubmit urb so we continue receiving */
if (port->open_count && urb->status != -ESHUTDOWN) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
printk(KERN_ERR "%s: resubmit read urb failed. "
"(%d)", __FUNCTION__, err);
}
}
return;
}
static void sierra_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
dbg("%s", __FUNCTION__);
port = (struct usb_serial_port *) urb->context;
usb_serial_port_softint(port);
}
static void sierra_instat_callback(struct urb *urb)
{
int err;
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
dbg("%s", __FUNCTION__);
dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
if (urb->status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
if (!req_pkt) {
dbg("%s: NULL req_pkt\n", __FUNCTION__);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
(req_pkt->bRequest == 0x20)) {
int old_dcd_state;
unsigned char signals = *((unsigned char *)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
dbg("%s: signal x%x", __FUNCTION__, signals);
old_dcd_state = portdata->dcd_state;
portdata->cts_state = 1;
portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
if (port->tty && !C_CLOCAL(port->tty) &&
old_dcd_state && !portdata->dcd_state)
tty_hangup(port->tty);
} else {
dbg("%s: type %x req %x", __FUNCTION__,
req_pkt->bRequestType,req_pkt->bRequest);
}
} else
dbg("%s: error %d", __FUNCTION__, urb->status);
/* Resubmit urb so we continue receiving IRQ data */
if (urb->status != -ESHUTDOWN) {
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dbg("%s: resubmit intr urb failed. (%d)",
__FUNCTION__, err);
}
}
static int sierra_write_room(struct usb_serial_port *port)
{
struct sierra_port_private *portdata;
int i;
int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && this_urb->status != -EINPROGRESS)
data_len += OUT_BUFLEN;
}
dbg("%s: %d", __FUNCTION__, data_len);
return data_len;
}
static int sierra_chars_in_buffer(struct usb_serial_port *port)
{
struct sierra_port_private *portdata;
int i;
int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && this_urb->status == -EINPROGRESS)
data_len += this_urb->transfer_buffer_length;
}
dbg("%s: %d", __FUNCTION__, data_len);
return data_len;
}
static int sierra_open(struct usb_serial_port *port, struct file *filp)
{
struct sierra_port_private *portdata;
struct usb_serial *serial = port->serial;
int i, err;
struct urb *urb;
portdata = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__);
/* Set some sane defaults */
portdata->rts_state = 1;
portdata->dtr_state = 1;
/* Reset low level data toggle and start reading from endpoints */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
if (! urb)
continue;
if (urb->dev != serial->dev) {
dbg("%s: dev %p != %p", __FUNCTION__,
urb->dev, serial->dev);
continue;
}
/*
* make sure endpoint data toggle is synchronized with the
* device
*/
usb_clear_halt(urb->dev, urb->pipe);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
dbg("%s: submit urb %d failed (%d) %d",
__FUNCTION__, i, err,
urb->transfer_buffer_length);
}
}
/* Reset low level data toggle on out endpoints */
for (i = 0; i < N_OUT_URB; i++) {
urb = portdata->out_urbs[i];
if (! urb)
continue;
urb->dev = serial->dev;
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), 0); */
}
port->tty->low_latency = 1;
sierra_send_setup(port);
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;
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
dbg("%s", __FUNCTION__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
portdata->dtr_state = 0;
if (serial->dev) {
sierra_send_setup(port);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
stop_urb(portdata->in_urbs[i]);
for (i = 0; i < N_OUT_URB; i++)
stop_urb(portdata->out_urbs[i]);
}
port->tty = NULL;
}
/* Helper functions used by sierra_setup_urbs */
static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
usb_complete_t callback)
{
struct urb *urb;
if (endpoint == -1)
return NULL; /* endpoint not needed */
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (urb == NULL) {
dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
return NULL;
}
/* Fill URB using supplied data. */
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
return urb;
}
/* Setup urbs */
static void sierra_setup_urbs(struct usb_serial *serial)
{
int i,j;
struct usb_serial_port *port;
struct sierra_port_private *portdata;
dbg("%s", __FUNCTION__);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
/* Do indat endpoints first */
for (j = 0; j < N_IN_URB; ++j) {
portdata->in_urbs[j] = sierra_setup_urb (serial,
port->bulk_in_endpointAddress, USB_DIR_IN, port,
portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
}
/* outdat endpoints */
for (j = 0; j < N_OUT_URB; ++j) {
portdata->out_urbs[j] = sierra_setup_urb (serial,
port->bulk_out_endpointAddress, USB_DIR_OUT, port,
portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
}
}
}
static int sierra_startup(struct usb_serial *serial)
{
int i, err;
struct usb_serial_port *port;
struct sierra_port_private *portdata;
dbg("%s", __FUNCTION__);
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata) {
dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
__FUNCTION__, i);
return (1);
}
usb_set_serial_port_data(port, portdata);
if (! port->interrupt_in_urb)
continue;
err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (err)
dbg("%s: submit irq_in urb failed %d",
__FUNCTION__, err);
}
sierra_setup_urbs(serial);
return (0);
}
static void sierra_shutdown(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;
struct sierra_port_private *portdata;
dbg("%s", __FUNCTION__);
/* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) {
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]);
for (j = 0; j < N_OUT_URB; j++)
stop_urb(portdata->out_urbs[j]);
}
/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
for (j = 0; j < N_IN_URB; j++) {
if (portdata->in_urbs[j]) {
usb_free_urb(portdata->in_urbs[j]);
portdata->in_urbs[j] = NULL;
}
}
for (j = 0; j < N_OUT_URB; j++) {
if (portdata->out_urbs[j]) {
usb_free_urb(portdata->out_urbs[j]);
portdata->out_urbs[j] = NULL;
}
}
}
/* Now free per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
kfree(usb_get_serial_port_data(port));
}
}
static struct usb_serial_driver sierra_1port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "Sierra_Wireless",
.owner = THIS_MODULE,
.name = "sierra1",
},
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 3,
.description = "Sierra USB modem (1 port)",
.id_table = id_table_1port,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = sierra_open,
.close = sierra_close,
.write = sierra_write,
.write_room = sierra_write_room,
.chars_in_buffer = sierra_chars_in_buffer,
.throttle = sierra_rx_throttle,
.unthrottle = sierra_rx_unthrottle,
.ioctl = sierra_ioctl,
.set_termios = sierra_set_termios,
.break_ctl = sierra_break_ctl,
.tiocmget = sierra_tiocmget,
.tiocmset = sierra_tiocmset,
.attach = sierra_startup,
.shutdown = sierra_shutdown,
.read_int_callback = sierra_instat_callback,
};
static struct usb_serial_driver sierra_3port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "sierra3",
},
.description = "Sierra USB modem (3 port)",
.id_table = id_table_3port,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 3,
.num_bulk_out = 3,
.num_ports = 3,
.open = sierra_open,
.close = sierra_close,
.write = sierra_write,
.write_room = sierra_write_room,
.chars_in_buffer = sierra_chars_in_buffer,
.throttle = sierra_rx_throttle,
.unthrottle = sierra_rx_unthrottle,
.ioctl = sierra_ioctl,
.set_termios = sierra_set_termios,
.break_ctl = sierra_break_ctl,
.tiocmget = sierra_tiocmget,
.tiocmset = sierra_tiocmset,
.attach = sierra_startup,
.shutdown = sierra_shutdown,
.read_int_callback = sierra_instat_callback,
};
/* Functions used by new usb-serial code. */
static int __init sierra_init(void)
{
int retval;
retval = usb_serial_register(&sierra_device);
retval = usb_serial_register(&sierra_1port_device);
if (retval)
return retval;
goto failed_1port_device_register;
retval = usb_serial_register(&sierra_3port_device);
if (retval)
goto failed_3port_device_register;
retval = usb_register(&sierra_driver);
if (retval)
usb_serial_deregister(&sierra_device);
goto failed_driver_register;
info(DRIVER_DESC ": " DRIVER_VERSION);
return 0;
failed_driver_register:
usb_serial_deregister(&sierra_3port_device);
failed_3port_device_register:
usb_serial_deregister(&sierra_1port_device);
failed_1port_device_register:
return retval;
}
static void __exit sierra_exit(void)
{
usb_deregister(&sierra_driver);
usb_serial_deregister(&sierra_device);
usb_deregister (&sierra_driver);
usb_serial_deregister(&sierra_1port_device);
usb_serial_deregister(&sierra_3port_device);
}
module_init(sierra_init);
module_exit(sierra_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
#ifdef CONFIG_USB_DEBUG
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug messages");
#endif

View File

@ -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.