diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-17 18:05:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-17 18:05:22 -0400 |
| commit | 699ddda6ecd5751fd05fd5128aa7f93438974468 (patch) | |
| tree | b09b6a347c2e437e9c8bd5cd87f94fe03944a437 | |
| parent | acbb67d51ef0ff942d592d44fb8abb4c931041ff (diff) | |
| parent | ab352c2687a4361aec06a184ddb20deb1e5091eb (diff) | |
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
...
50 files changed, 3894 insertions, 639 deletions
diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt index b9111a703ce0..5427bdf225ed 100644 --- a/Documentation/input/xpad.txt +++ b/Documentation/input/xpad.txt | |||
| @@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepads | |||
| 3 | This is the very first release of a driver for X-Box gamepads. | 3 | This is the very first release of a driver for X-Box gamepads. |
| 4 | Basically, this was hacked away in just a few hours, so don't expect | 4 | Basically, this was hacked away in just a few hours, so don't expect |
| 5 | miracles. | 5 | miracles. |
| 6 | |||
| 6 | In particular, there is currently NO support for the rumble pack. | 7 | In particular, there is currently NO support for the rumble pack. |
| 7 | You won't find many ff-aware linux applications anyway. | 8 | You won't find many ff-aware linux applications anyway. |
| 8 | 9 | ||
| 9 | 10 | ||
| 10 | 0. Status | 11 | 0. Notes |
| 11 | --------- | 12 | -------- |
| 13 | |||
| 14 | Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.) | ||
| 12 | 15 | ||
| 13 | For now, this driver has only been tested on just one Linux-Box. | 16 | The number of buttons/axes reported varies based on 3 things: |
| 14 | This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600. | 17 | - if you are using a known controller |
| 18 | - if you are using a known dance pad | ||
| 19 | - if using an unknown device (one not listed below), what you set in the | ||
| 20 | module configuration for "Map D-PAD to buttons rather than axes for unknown | ||
| 21 | pads" (module option dpad_to_buttons) | ||
| 15 | 22 | ||
| 16 | The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports | 23 | If you set dpad_to_buttons to 0 and you are using an unknown device (one |
| 17 | 8 axes and 10 buttons. | 24 | not listed below), the driver will map the directional pad to axes (X/Y), |
| 25 | if you said N it will map the d-pad to buttons, which is needed for dance | ||
| 26 | style games to function correctly. The default is Y. | ||
| 27 | |||
| 28 | dpad_to_buttons has no effect for known pads. | ||
| 29 | |||
| 30 | 0.1 Normal Controllers | ||
| 31 | ---------------------- | ||
| 32 | With a normal controller, the directional pad is mapped to its own X/Y axes. | ||
| 33 | The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8 | ||
| 34 | axes and 10 buttons. | ||
| 18 | 35 | ||
| 19 | Alls 8 axes work, though they all have the same range (-32768..32767) | 36 | All 8 axes work, though they all have the same range (-32768..32767) |
| 20 | and the zero-setting is not correct for the triggers (I don't know if that | 37 | and the zero-setting is not correct for the triggers (I don't know if that |
| 21 | is some limitation of jstest, since the input device setup should be fine. I | 38 | is some limitation of jstest, since the input device setup should be fine. I |
| 22 | didn't have a look at jstest itself yet). | 39 | 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 | |||
| 30 | play first person shooters with a pad. Your mileage may vary. | 47 | play first person shooters with a pad. Your mileage may vary. |
| 31 | 48 | ||
| 32 | 49 | ||
| 50 | 0.2 Xbox Dance Pads | ||
| 51 | ------------------- | ||
| 52 | When using a known dance pad, jstest will report 6 axes and 14 buttons. | ||
| 53 | |||
| 54 | For dance style pads (like the redoctane pad) several changes | ||
| 55 | have been made. The old driver would map the d-pad to axes, resulting | ||
| 56 | in the driver being unable to report when the user was pressing both | ||
| 57 | left+right or up+down, making DDR style games unplayable. | ||
| 58 | |||
| 59 | Known dance pads automatically map the d-pad to buttons and will work | ||
| 60 | correctly out of the box. | ||
| 61 | |||
| 62 | If your dance pad is recognized by the driver but is using axes instead | ||
| 63 | of buttons, see section 0.3 - Unknown Controllers | ||
| 64 | |||
| 65 | I've tested this with Stepmania, and it works quite well. | ||
| 66 | |||
| 67 | |||
| 68 | 0.3 Unkown Controllers | ||
| 69 | ---------------------- | ||
| 70 | If you have an unkown xbox controller, it should work just fine with | ||
| 71 | the default settings. | ||
| 72 | |||
| 73 | HOWEVER if you have an unknown dance pad not listed below, it will not | ||
| 74 | work UNLESS you set "dpad_to_buttons" to 1 in the module configuration. | ||
| 75 | |||
| 76 | PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with | ||
| 77 | a dump from /proc/bus/usb and a description of the pad (manufacturer, country, | ||
| 78 | whether it is a dance pad or normal controller) so that we can add your pad | ||
| 79 | to the list of supported devices, ensuring that it will work out of the | ||
| 80 | box in the future. | ||
| 81 | |||
| 82 | |||
| 33 | 1. USB adapter | 83 | 1. USB adapter |
| 34 | -------------- | 84 | -------------- |
| 35 | 85 | ||
| 36 | Before you can actually use the driver, you need to get yourself an | 86 | Before you can actually use the driver, you need to get yourself an |
| 37 | adapter cable to connect the X-Box controller to your Linux-Box. | 87 | adapter cable to connect the X-Box controller to your Linux-Box. You |
| 88 | can buy these online fairly cheap, or build your own. | ||
| 38 | 89 | ||
| 39 | Such a cable is pretty easy to build. The Controller itself is a USB compound | 90 | Such a cable is pretty easy to build. The Controller itself is a USB |
| 40 | device (a hub with three ports for two expansion slots and the controller | 91 | compound device (a hub with three ports for two expansion slots and |
| 41 | device) with the only difference in a nonstandard connector (5 pins vs. 4 on | 92 | the controller device) with the only difference in a nonstandard connector |
| 42 | standard USB connector). | 93 | (5 pins vs. 4 on standard USB connector). |
| 43 | 94 | ||
| 44 | You just need to solder a USB connector onto the cable and keep the | 95 | You just need to solder a USB connector onto the cable and keep the |
| 45 | yellow wire unconnected. The other pins have the same order on both | 96 | 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, | |||
| 51 | you can still use the controller with your X-Box, if you have one ;) | 102 | you can still use the controller with your X-Box, if you have one ;) |
| 52 | 103 | ||
| 53 | 104 | ||
| 54 | 2. driver installation | 105 | 2. Driver Installation |
| 55 | ---------------------- | 106 | ---------------------- |
| 56 | 107 | ||
| 57 | Once you have the adapter cable and the controller is connected, you need | 108 | Once you have the adapter cable and the controller is connected, you need |
| 58 | to load your USB subsystem and should cat /proc/bus/usb/devices. | 109 | to load your USB subsystem and should cat /proc/bus/usb/devices. |
| 59 | There should be an entry like the one at the end [4]. | 110 | There should be an entry like the one at the end [4]. |
| 60 | 111 | ||
| 61 | Currently (as of version 0.0.4), the following three devices are included: | 112 | Currently (as of version 0.0.6), the following devices are included: |
| 62 | original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 | 113 | original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 |
| 114 | smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289 | ||
| 63 | original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 | 115 | original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 |
| 64 | InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a | 116 | InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a |
| 117 | RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809 | ||
| 65 | 118 | ||
| 66 | If you have another controller that is not listed above and is not recognized | 119 | The driver should work with xbox pads not listed above as well, however |
| 67 | by the driver, please drop me a line with the appropriate info (that is, include | 120 | you will need to do something extra for dance pads to work. |
| 68 | the name, vendor and product ID, as well as the country where you bought it; | ||
| 69 | sending the whole dump out of /proc/bus/usb/devices along would be even better). | ||
| 70 | 121 | ||
| 71 | In theory, the driver should work with other controllers than mine | 122 | If you have a controller not listed above, see 0.3 - Unknown Controllers |
| 72 | (InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this | ||
| 73 | for I only have this one controller. | ||
| 74 | 123 | ||
| 75 | If you compiled and installed the driver, test the functionality: | 124 | If you compiled and installed the driver, test the functionality: |
| 76 | > modprobe xpad | 125 | > modprobe xpad |
| 77 | > modprobe joydev | 126 | > modprobe joydev |
| 78 | > jstest /dev/js0 | 127 | > jstest /dev/js0 |
| 79 | 128 | ||
| 80 | There should be a single line showing 18 inputs (8 axes, 10 buttons), and | 129 | If you're using a normal controller, there should be a single line showing |
| 81 | it's values should change if you move the sticks and push the buttons. | 130 | 18 inputs (8 axes, 10 buttons), and its values should change if you move |
| 131 | the sticks and push the buttons. If you're using a dance pad, it should | ||
| 132 | show 20 inputs (6 axes, 14 buttons). | ||
| 82 | 133 | ||
| 83 | It works? Voila, your done ;) | 134 | It works? Voila, you're done ;) |
| 84 | 135 | ||
| 85 | 136 | ||
| 86 | 3. Thanks | 137 | 3. Thanks |
| @@ -111,6 +162,22 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none) | |||
| 111 | E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms | 162 | E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms |
| 112 | E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms | 163 | E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms |
| 113 | 164 | ||
| 165 | 5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US): | ||
| 166 | |||
| 167 | T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0 | ||
| 168 | D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 | ||
| 169 | P: Vendor=0c12 ProdID=8809 Rev= 0.01 | ||
| 170 | S: Product=XBOX DDR | ||
| 171 | C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA | ||
| 172 | I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad | ||
| 173 | E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms | ||
| 174 | E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms | ||
| 175 | |||
| 114 | -- | 176 | -- |
| 115 | Marko Friedemann <mfr@bmx-chemnitz.de> | 177 | Marko Friedemann <mfr@bmx-chemnitz.de> |
| 116 | 2002-07-16 | 178 | 2002-07-16 |
| 179 | - original doc | ||
| 180 | |||
| 181 | Dominic Cerquetti <binary1230@yahoo.com> | ||
| 182 | 2005-03-19 | ||
| 183 | - added stuff for dance pads, new d-pad->axes mappings | ||
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 97d57cfc343b..825bf884537a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
| @@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB) += input/ | |||
| 33 | obj-$(CONFIG_USB_MOUSE) += input/ | 33 | obj-$(CONFIG_USB_MOUSE) += input/ |
| 34 | obj-$(CONFIG_USB_MTOUCH) += input/ | 34 | obj-$(CONFIG_USB_MTOUCH) += input/ |
| 35 | obj-$(CONFIG_USB_POWERMATE) += input/ | 35 | obj-$(CONFIG_USB_POWERMATE) += input/ |
| 36 | obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/ | ||
| 37 | obj-$(CONFIG_USB_WACOM) += input/ | 36 | obj-$(CONFIG_USB_WACOM) += input/ |
| 38 | obj-$(CONFIG_USB_XPAD) += input/ | 37 | obj-$(CONFIG_USB_XPAD) += input/ |
| 39 | 38 | ||
| @@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ | |||
| 66 | obj-$(CONFIG_USB_RIO500) += misc/ | 65 | obj-$(CONFIG_USB_RIO500) += misc/ |
| 67 | obj-$(CONFIG_USB_SISUSBVGA) += misc/ | 66 | obj-$(CONFIG_USB_SISUSBVGA) += misc/ |
| 68 | obj-$(CONFIG_USB_TEST) += misc/ | 67 | obj-$(CONFIG_USB_TEST) += misc/ |
| 68 | obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ | ||
| 69 | obj-$(CONFIG_USB_USS720) += misc/ | 69 | obj-$(CONFIG_USB_USS720) += misc/ |
| 70 | 70 | ||
| 71 | obj-$(CONFIG_USB_ATM) += atm/ | 71 | obj-$(CONFIG_USB_ATM) += atm/ |
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 3892a9e9aee3..e6565633ba0f 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c | |||
| @@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { | |||
| 793 | { /* V = Conexant P = ADSL modem */ | 793 | { /* V = Conexant P = ADSL modem */ |
| 794 | USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 | 794 | USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 |
| 795 | }, | 795 | }, |
| 796 | { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */ | ||
| 797 | USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00 | ||
| 798 | }, | ||
| 796 | { /* V = Olitec P = ADSL modem version 2 */ | 799 | { /* V = Olitec P = ADSL modem version 2 */ |
| 797 | USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe | 800 | USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe |
| 798 | }, | 801 | }, |
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7c7b507af29d..c870c804470f 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c | |||
| @@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch"; | |||
| 55 | #define OFFSET_d 9 /* size 4 */ | 55 | #define OFFSET_d 9 /* size 4 */ |
| 56 | #define OFFSET_e 13 /* size 1 */ | 56 | #define OFFSET_e 13 /* size 1 */ |
| 57 | #define OFFSET_f 14 /* size 1 */ | 57 | #define OFFSET_f 14 /* size 1 */ |
| 58 | #define TOTAL 15 | ||
| 59 | 58 | ||
| 60 | #define SIZE_7 1 | 59 | #define SIZE_7 1 |
| 61 | #define SIZE_b 8 | 60 | #define SIZE_b 8 |
| @@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST; | |||
| 79 | static int enable_isoc = DEFAULT_ENABLE_ISOC; | 78 | static int enable_isoc = DEFAULT_ENABLE_ISOC; |
| 80 | static int sw_buffering = DEFAULT_SW_BUFFERING; | 79 | static int sw_buffering = DEFAULT_SW_BUFFERING; |
| 81 | 80 | ||
| 81 | #define DEFAULT_B_MAX_DSL 8128 | ||
| 82 | #define DEFAULT_MODEM_MODE 11 | ||
| 83 | #define MODEM_OPTION_LENGTH 16 | ||
| 84 | static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { | ||
| 85 | 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
| 86 | }; | ||
| 87 | |||
| 88 | static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; | ||
| 89 | static unsigned char ModemMode = DEFAULT_MODEM_MODE; | ||
| 90 | static unsigned char ModemOption[MODEM_OPTION_LENGTH]; | ||
| 91 | static int num_ModemOption; | ||
| 92 | |||
| 82 | module_param(altsetting, uint, S_IRUGO | S_IWUSR); | 93 | module_param(altsetting, uint, S_IRUGO | S_IWUSR); |
| 83 | MODULE_PARM_DESC(altsetting, | 94 | MODULE_PARM_DESC(altsetting, |
| 84 | "Alternative setting for data interface (bulk_default: " | 95 | "Alternative setting for data interface (bulk_default: " |
| @@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering, | |||
| 100 | "Enable software buffering (default: " | 111 | "Enable software buffering (default: " |
| 101 | __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); | 112 | __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); |
| 102 | 113 | ||
| 114 | module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); | ||
| 115 | MODULE_PARM_DESC(BMaxDSL, | ||
| 116 | "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); | ||
| 117 | |||
| 118 | module_param(ModemMode, byte, S_IRUGO | S_IWUSR); | ||
| 119 | MODULE_PARM_DESC(ModemMode, | ||
| 120 | "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); | ||
| 121 | |||
| 122 | module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); | ||
| 123 | MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); | ||
| 124 | |||
| 103 | #define INTERFACE_DATA 1 | 125 | #define INTERFACE_DATA 1 |
| 104 | #define ENDPOINT_INT 0x81 | 126 | #define ENDPOINT_INT 0x81 |
| 105 | #define ENDPOINT_BULK_DATA 0x07 | 127 | #define ENDPOINT_BULK_DATA 0x07 |
| @@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering, | |||
| 108 | 130 | ||
| 109 | #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) | 131 | #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) |
| 110 | 132 | ||
| 133 | struct speedtch_params { | ||
| 134 | unsigned int altsetting; | ||
| 135 | unsigned int BMaxDSL; | ||
| 136 | unsigned char ModemMode; | ||
| 137 | unsigned char ModemOption[MODEM_OPTION_LENGTH]; | ||
| 138 | }; | ||
| 139 | |||
| 111 | struct speedtch_instance_data { | 140 | struct speedtch_instance_data { |
| 112 | struct usbatm_data *usbatm; | 141 | struct usbatm_data *usbatm; |
| 113 | 142 | ||
| 114 | unsigned int altsetting; | 143 | struct speedtch_params params; /* set in probe, constant afterwards */ |
| 115 | 144 | ||
| 116 | struct work_struct status_checker; | 145 | struct work_struct status_checker; |
| 117 | 146 | ||
| @@ -123,7 +152,7 @@ struct speedtch_instance_data { | |||
| 123 | struct urb *int_urb; | 152 | struct urb *int_urb; |
| 124 | unsigned char int_data[16]; | 153 | unsigned char int_data[16]; |
| 125 | 154 | ||
| 126 | unsigned char scratch_buffer[TOTAL]; | 155 | unsigned char scratch_buffer[16]; |
| 127 | }; | 156 | }; |
| 128 | 157 | ||
| 129 | /*************** | 158 | /*************** |
| @@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance) | |||
| 186 | 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); | 215 | 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); |
| 187 | if (ret < 0) | 216 | if (ret < 0) |
| 188 | usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); | 217 | usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); |
| 218 | |||
| 219 | /* Extra initialisation in recent drivers - gives higher speeds */ | ||
| 220 | |||
| 221 | /* URBext1 */ | ||
| 222 | buf[0] = instance->params.ModemMode; | ||
| 223 | ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 224 | 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); | ||
| 225 | if (ret < 0) | ||
| 226 | usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); | ||
| 227 | |||
| 228 | /* URBext2 */ | ||
| 229 | /* This seems to be the one which actually triggers the higher sync | ||
| 230 | rate -- it does require the new firmware too, although it works OK | ||
| 231 | with older firmware */ | ||
| 232 | ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 233 | 0x01, 0x40, 0x14, 0x00, | ||
| 234 | instance->params.ModemOption, | ||
| 235 | MODEM_OPTION_LENGTH, CTRL_TIMEOUT); | ||
| 236 | if (ret < 0) | ||
| 237 | usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); | ||
| 238 | |||
| 239 | /* URBext3 */ | ||
| 240 | buf[0] = instance->params.BMaxDSL & 0xff; | ||
| 241 | buf[1] = instance->params.BMaxDSL >> 8; | ||
| 242 | ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 243 | 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); | ||
| 244 | if (ret < 0) | ||
| 245 | usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); | ||
| 189 | } | 246 | } |
| 190 | 247 | ||
| 191 | static int speedtch_upload_firmware(struct speedtch_instance_data *instance, | 248 | static int speedtch_upload_firmware(struct speedtch_instance_data *instance, |
| @@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, | |||
| 285 | because we're in our own kernel thread anyway. */ | 342 | because we're in our own kernel thread anyway. */ |
| 286 | msleep_interruptible(1000); | 343 | msleep_interruptible(1000); |
| 287 | 344 | ||
| 288 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { | 345 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { |
| 289 | usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret); | 346 | usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); |
| 290 | goto out_free; | 347 | goto out_free; |
| 291 | } | 348 | } |
| 292 | 349 | ||
| @@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance) | |||
| 372 | unsigned char *buf = instance->scratch_buffer; | 429 | unsigned char *buf = instance->scratch_buffer; |
| 373 | int ret; | 430 | int ret; |
| 374 | 431 | ||
| 375 | memset(buf, 0, TOTAL); | 432 | memset(buf, 0, 16); |
| 376 | 433 | ||
| 377 | ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | 434 | ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), |
| 378 | 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, | 435 | 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, |
| @@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
| 746 | 803 | ||
| 747 | instance->usbatm = usbatm; | 804 | instance->usbatm = usbatm; |
| 748 | 805 | ||
| 749 | /* altsetting and enable_isoc may change at any moment, so take a snapshot */ | 806 | /* module parameters may change at any moment, so take a snapshot */ |
| 750 | instance->altsetting = altsetting; | 807 | instance->params.altsetting = altsetting; |
| 808 | instance->params.BMaxDSL = BMaxDSL; | ||
| 809 | instance->params.ModemMode = ModemMode; | ||
| 810 | memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); | ||
| 811 | memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); | ||
| 751 | use_isoc = enable_isoc; | 812 | use_isoc = enable_isoc; |
| 752 | 813 | ||
| 753 | if (instance->altsetting) | 814 | if (instance->params.altsetting) |
| 754 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { | 815 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { |
| 755 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret); | 816 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); |
| 756 | instance->altsetting = 0; /* fall back to default */ | 817 | instance->params.altsetting = 0; /* fall back to default */ |
| 757 | } | 818 | } |
| 758 | 819 | ||
| 759 | if (!instance->altsetting && use_isoc) | 820 | if (!instance->params.altsetting && use_isoc) |
| 760 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { | 821 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { |
| 761 | usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); | 822 | usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); |
| 762 | use_isoc = 0; /* fall back to bulk */ | 823 | use_isoc = 0; /* fall back to bulk */ |
| @@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
| 783 | usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); | 844 | usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); |
| 784 | } | 845 | } |
| 785 | 846 | ||
| 786 | if (!use_isoc && !instance->altsetting) | 847 | if (!use_isoc && !instance->params.altsetting) |
| 787 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { | 848 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { |
| 788 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); | 849 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); |
| 789 | goto fail_free; | 850 | goto fail_free; |
| 790 | } | 851 | } |
| 791 | 852 | ||
| 792 | if (!instance->altsetting) | 853 | if (!instance->params.altsetting) |
| 793 | instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; | 854 | instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; |
| 794 | 855 | ||
| 795 | usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); | 856 | usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); |
| 796 | 857 | ||
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f5434b1cbb1e..f6b9f7e1f716 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c | |||
| @@ -68,7 +68,7 @@ | |||
| 68 | 68 | ||
| 69 | #include "usbatm.h" | 69 | #include "usbatm.h" |
| 70 | 70 | ||
| 71 | #define EAGLEUSBVERSION "ueagle 1.3" | 71 | #define EAGLEUSBVERSION "ueagle 1.4" |
| 72 | 72 | ||
| 73 | 73 | ||
| 74 | /* | 74 | /* |
| @@ -80,14 +80,14 @@ | |||
| 80 | dev_dbg(&(usb_dev)->dev, \ | 80 | dev_dbg(&(usb_dev)->dev, \ |
| 81 | "[ueagle-atm dbg] %s: " format, \ | 81 | "[ueagle-atm dbg] %s: " format, \ |
| 82 | __FUNCTION__, ##args); \ | 82 | __FUNCTION__, ##args); \ |
| 83 | } while (0) | 83 | } while (0) |
| 84 | 84 | ||
| 85 | #define uea_vdbg(usb_dev, format, args...) \ | 85 | #define uea_vdbg(usb_dev, format, args...) \ |
| 86 | do { \ | 86 | do { \ |
| 87 | if (debug >= 2) \ | 87 | if (debug >= 2) \ |
| 88 | dev_dbg(&(usb_dev)->dev, \ | 88 | dev_dbg(&(usb_dev)->dev, \ |
| 89 | "[ueagle-atm vdbg] " format, ##args); \ | 89 | "[ueagle-atm vdbg] " format, ##args); \ |
| 90 | } while (0) | 90 | } while (0) |
| 91 | 91 | ||
| 92 | #define uea_enters(usb_dev) \ | 92 | #define uea_enters(usb_dev) \ |
| 93 | uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__) | 93 | uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__) |
| @@ -218,8 +218,8 @@ enum { | |||
| 218 | #define UEA_CHIP_VERSION(x) \ | 218 | #define UEA_CHIP_VERSION(x) \ |
| 219 | ((x)->driver_info & 0xf) | 219 | ((x)->driver_info & 0xf) |
| 220 | 220 | ||
| 221 | #define IS_ISDN(sc) \ | 221 | #define IS_ISDN(usb_dev) \ |
| 222 | (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80) | 222 | (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) |
| 223 | 223 | ||
| 224 | #define INS_TO_USBDEV(ins) ins->usb_dev | 224 | #define INS_TO_USBDEV(ins) ins->usb_dev |
| 225 | 225 | ||
| @@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc) | |||
| 625 | char *dsp_name; | 625 | char *dsp_name; |
| 626 | 626 | ||
| 627 | if (UEA_CHIP_VERSION(sc) == ADI930) { | 627 | if (UEA_CHIP_VERSION(sc) == ADI930) { |
| 628 | if (IS_ISDN(sc)) | 628 | if (IS_ISDN(sc->usb_dev)) |
| 629 | dsp_name = FW_DIR "DSP9i.bin"; | 629 | dsp_name = FW_DIR "DSP9i.bin"; |
| 630 | else | 630 | else |
| 631 | dsp_name = FW_DIR "DSP9p.bin"; | 631 | dsp_name = FW_DIR "DSP9p.bin"; |
| 632 | } else { | 632 | } else { |
| 633 | if (IS_ISDN(sc)) | 633 | if (IS_ISDN(sc->usb_dev)) |
| 634 | dsp_name = FW_DIR "DSPei.bin"; | 634 | dsp_name = FW_DIR "DSPei.bin"; |
| 635 | else | 635 | else |
| 636 | dsp_name = FW_DIR "DSPep.bin"; | 636 | dsp_name = FW_DIR "DSPep.bin"; |
| @@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) | |||
| 744 | 744 | ||
| 745 | static inline int wait_cmv_ack(struct uea_softc *sc) | 745 | static inline int wait_cmv_ack(struct uea_softc *sc) |
| 746 | { | 746 | { |
| 747 | int ret = wait_event_timeout(sc->cmv_ack_wait, | 747 | int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, |
| 748 | sc->cmv_ack, ACK_TIMEOUT); | 748 | sc->cmv_ack, ACK_TIMEOUT); |
| 749 | sc->cmv_ack = 0; | 749 | sc->cmv_ack = 0; |
| 750 | 750 | ||
| @@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc) | |||
| 885 | break; | 885 | break; |
| 886 | 886 | ||
| 887 | case 3: /* fail ... */ | 887 | case 3: /* fail ... */ |
| 888 | uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n"); | 888 | uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" |
| 889 | " (may be try other cmv/dsp)\n"); | ||
| 889 | return -EAGAIN; | 890 | return -EAGAIN; |
| 890 | 891 | ||
| 891 | case 4 ... 6: /* test state */ | 892 | case 4 ... 6: /* test state */ |
| @@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc) | |||
| 913 | release_firmware(sc->dsp_firm); | 914 | release_firmware(sc->dsp_firm); |
| 914 | sc->dsp_firm = NULL; | 915 | sc->dsp_firm = NULL; |
| 915 | } | 916 | } |
| 916 | |||
| 917 | ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); | ||
| 918 | if (ret < 0) | ||
| 919 | return ret; | ||
| 920 | uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", | ||
| 921 | sc->stats.phy.firmid); | ||
| 922 | } | 917 | } |
| 923 | 918 | ||
| 924 | /* always update it as atm layer could not be init when we switch to | 919 | /* 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, | |||
| 1033 | 1028 | ||
| 1034 | if (cmv_file[sc->modem_index] == NULL) { | 1029 | if (cmv_file[sc->modem_index] == NULL) { |
| 1035 | if (UEA_CHIP_VERSION(sc) == ADI930) | 1030 | if (UEA_CHIP_VERSION(sc) == ADI930) |
| 1036 | file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin"; | 1031 | file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; |
| 1037 | else | 1032 | else |
| 1038 | file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin"; | 1033 | file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; |
| 1039 | } else | 1034 | } else |
| 1040 | file = cmv_file[sc->modem_index]; | 1035 | file = cmv_file[sc->modem_index]; |
| 1041 | 1036 | ||
| @@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc) | |||
| 1131 | if (ret < 0) | 1126 | if (ret < 0) |
| 1132 | return ret; | 1127 | return ret; |
| 1133 | 1128 | ||
| 1129 | /* Dump firmware version */ | ||
| 1130 | ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); | ||
| 1131 | if (ret < 0) | ||
| 1132 | return ret; | ||
| 1133 | uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", | ||
| 1134 | sc->stats.phy.firmid); | ||
| 1135 | |||
| 1134 | /* get options */ | 1136 | /* get options */ |
| 1135 | ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); | 1137 | ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); |
| 1136 | if (ret < 0) | 1138 | if (ret < 0) |
| @@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc) | |||
| 1147 | /* Enter in R-ACT-REQ */ | 1149 | /* Enter in R-ACT-REQ */ |
| 1148 | ret = uea_write_cmv(sc, SA_CNTL, 0, 2); | 1150 | ret = uea_write_cmv(sc, SA_CNTL, 0, 2); |
| 1149 | uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); | 1151 | uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); |
| 1152 | uea_info(INS_TO_USBDEV(sc), "Modem started, " | ||
| 1153 | "waiting synchronization\n"); | ||
| 1150 | out: | 1154 | out: |
| 1151 | release_firmware(cmvs_fw); | 1155 | release_firmware(cmvs_fw); |
| 1152 | sc->reset = 0; | 1156 | sc->reset = 0; |
| @@ -1172,7 +1176,10 @@ static int uea_kthread(void *data) | |||
| 1172 | if (!ret) | 1176 | if (!ret) |
| 1173 | ret = uea_stat(sc); | 1177 | ret = uea_stat(sc); |
| 1174 | if (ret != -EAGAIN) | 1178 | if (ret != -EAGAIN) |
| 1175 | msleep(1000); | 1179 | msleep_interruptible(1000); |
| 1180 | if (try_to_freeze()) | ||
| 1181 | uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " | ||
| 1182 | "please unplug/replug your modem\n"); | ||
| 1176 | } | 1183 | } |
| 1177 | uea_leaves(INS_TO_USBDEV(sc)); | 1184 | uea_leaves(INS_TO_USBDEV(sc)); |
| 1178 | return ret; | 1185 | return ret; |
| @@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0); | |||
| 1566 | UEA_ATTR(dscorr, 0); | 1573 | UEA_ATTR(dscorr, 0); |
| 1567 | UEA_ATTR(usunc, 0); | 1574 | UEA_ATTR(usunc, 0); |
| 1568 | UEA_ATTR(dsunc, 0); | 1575 | UEA_ATTR(dsunc, 0); |
| 1576 | UEA_ATTR(firmid, 0); | ||
| 1569 | 1577 | ||
| 1570 | /* Retrieve the device End System Identifier (MAC) */ | 1578 | /* Retrieve the device End System Identifier (MAC) */ |
| 1571 | 1579 | ||
| @@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf) | |||
| 1597 | { | 1605 | { |
| 1598 | struct uea_softc *sc = usbatm->driver_data; | 1606 | struct uea_softc *sc = usbatm->driver_data; |
| 1599 | 1607 | ||
| 1600 | wait_event(sc->sync_q, IS_OPERATIONAL(sc)); | 1608 | wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc)); |
| 1601 | 1609 | ||
| 1602 | return 0; | 1610 | return 0; |
| 1603 | 1611 | ||
| @@ -1639,16 +1647,13 @@ static struct attribute *attrs[] = { | |||
| 1639 | &dev_attr_stat_dscorr.attr, | 1647 | &dev_attr_stat_dscorr.attr, |
| 1640 | &dev_attr_stat_usunc.attr, | 1648 | &dev_attr_stat_usunc.attr, |
| 1641 | &dev_attr_stat_dsunc.attr, | 1649 | &dev_attr_stat_dsunc.attr, |
| 1650 | &dev_attr_stat_firmid.attr, | ||
| 1651 | NULL, | ||
| 1642 | }; | 1652 | }; |
| 1643 | static struct attribute_group attr_grp = { | 1653 | static struct attribute_group attr_grp = { |
| 1644 | .attrs = attrs, | 1654 | .attrs = attrs, |
| 1645 | }; | 1655 | }; |
| 1646 | 1656 | ||
| 1647 | static int create_fs_entries(struct usb_interface *intf) | ||
| 1648 | { | ||
| 1649 | return sysfs_create_group(&intf->dev.kobj, &attr_grp); | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, | 1657 | static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, |
| 1653 | const struct usb_device_id *id) | 1658 | const struct usb_device_id *id) |
| 1654 | { | 1659 | { |
| @@ -1708,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, | |||
| 1708 | } | 1713 | } |
| 1709 | } | 1714 | } |
| 1710 | 1715 | ||
| 1716 | ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); | ||
| 1717 | if (ret < 0) | ||
| 1718 | goto error; | ||
| 1719 | |||
| 1711 | ret = uea_boot(sc); | 1720 | ret = uea_boot(sc); |
| 1712 | if (ret < 0) { | 1721 | if (ret < 0) |
| 1713 | kfree(sc); | 1722 | goto error; |
| 1714 | return ret; | ||
| 1715 | } | ||
| 1716 | 1723 | ||
| 1717 | ret = create_fs_entries(intf); | ||
| 1718 | if (ret) { | ||
| 1719 | uea_stop(sc); | ||
| 1720 | kfree(sc); | ||
| 1721 | return ret; | ||
| 1722 | } | ||
| 1723 | return 0; | 1724 | return 0; |
| 1724 | } | 1725 | error: |
| 1725 | 1726 | kfree(sc); | |
| 1726 | static void destroy_fs_entries(struct usb_interface *intf) | 1727 | return ret; |
| 1727 | { | ||
| 1728 | sysfs_remove_group(&intf->dev.kobj, &attr_grp); | ||
| 1729 | } | 1728 | } |
| 1730 | 1729 | ||
| 1731 | static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) | 1730 | static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) |
| 1732 | { | 1731 | { |
| 1733 | struct uea_softc *sc = usbatm->driver_data; | 1732 | struct uea_softc *sc = usbatm->driver_data; |
| 1734 | 1733 | ||
| 1735 | destroy_fs_entries(intf); | 1734 | sysfs_remove_group(&intf->dev.kobj, &attr_grp); |
| 1736 | uea_stop(sc); | 1735 | uea_stop(sc); |
| 1737 | kfree(sc); | 1736 | kfree(sc); |
| 1738 | } | 1737 | } |
| @@ -1753,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
| 1753 | struct usb_device *usb = interface_to_usbdev(intf); | 1752 | struct usb_device *usb = interface_to_usbdev(intf); |
| 1754 | 1753 | ||
| 1755 | uea_enters(usb); | 1754 | uea_enters(usb); |
| 1756 | uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n", | 1755 | uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", |
| 1757 | le16_to_cpu(usb->descriptor.idVendor), | 1756 | le16_to_cpu(usb->descriptor.idVendor), |
| 1758 | le16_to_cpu(usb->descriptor.idProduct), | 1757 | le16_to_cpu(usb->descriptor.idProduct), |
| 1759 | chip_name[UEA_CHIP_VERSION(id)]); | 1758 | chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); |
| 1760 | 1759 | ||
| 1761 | usb_reset_device(usb); | 1760 | usb_reset_device(usb); |
| 1762 | 1761 | ||
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 309073f6433a..ec63b0ee0743 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c | |||
| @@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg) | |||
| 1001 | 1001 | ||
| 1002 | daemonize(instance->driver->driver_name); | 1002 | daemonize(instance->driver->driver_name); |
| 1003 | allow_signal(SIGTERM); | 1003 | allow_signal(SIGTERM); |
| 1004 | instance->thread_pid = current->pid; | ||
| 1004 | 1005 | ||
| 1005 | complete(&instance->thread_started); | 1006 | complete(&instance->thread_started); |
| 1006 | 1007 | ||
| @@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance) | |||
| 1025 | return ret; | 1026 | return ret; |
| 1026 | } | 1027 | } |
| 1027 | 1028 | ||
| 1028 | mutex_lock(&instance->serialize); | ||
| 1029 | instance->thread_pid = ret; | ||
| 1030 | mutex_unlock(&instance->serialize); | ||
| 1031 | |||
| 1032 | wait_for_completion(&instance->thread_started); | 1029 | wait_for_completion(&instance->thread_started); |
| 1033 | 1030 | ||
| 1034 | return 0; | 1031 | return 0; |
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec4d1d756725..9a9012fd284b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
| 325 | struct acm_rb *buf; | 325 | struct acm_rb *buf; |
| 326 | struct tty_struct *tty = acm->tty; | 326 | struct tty_struct *tty = acm->tty; |
| 327 | struct acm_ru *rcv; | 327 | struct acm_ru *rcv; |
| 328 | //unsigned long flags; | 328 | unsigned long flags; |
| 329 | int i = 0; | 329 | int i = 0; |
| 330 | dbg("Entering acm_rx_tasklet"); | 330 | dbg("Entering acm_rx_tasklet"); |
| 331 | 331 | ||
| @@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
| 333 | return; | 333 | return; |
| 334 | 334 | ||
| 335 | next_buffer: | 335 | next_buffer: |
| 336 | spin_lock(&acm->read_lock); | 336 | spin_lock_irqsave(&acm->read_lock, flags); |
| 337 | if (list_empty(&acm->filled_read_bufs)) { | 337 | if (list_empty(&acm->filled_read_bufs)) { |
| 338 | spin_unlock(&acm->read_lock); | 338 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 339 | goto urbs; | 339 | goto urbs; |
| 340 | } | 340 | } |
| 341 | buf = list_entry(acm->filled_read_bufs.next, | 341 | buf = list_entry(acm->filled_read_bufs.next, |
| 342 | struct acm_rb, list); | 342 | struct acm_rb, list); |
| 343 | list_del(&buf->list); | 343 | list_del(&buf->list); |
| 344 | spin_unlock(&acm->read_lock); | 344 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 345 | 345 | ||
| 346 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); | 346 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
| 347 | 347 | ||
| @@ -356,29 +356,29 @@ next_buffer: | |||
| 356 | memmove(buf->base, buf->base + i, buf->size - i); | 356 | memmove(buf->base, buf->base + i, buf->size - i); |
| 357 | buf->size -= i; | 357 | buf->size -= i; |
| 358 | spin_unlock(&acm->throttle_lock); | 358 | spin_unlock(&acm->throttle_lock); |
| 359 | spin_lock(&acm->read_lock); | 359 | spin_lock_irqsave(&acm->read_lock, flags); |
| 360 | list_add(&buf->list, &acm->filled_read_bufs); | 360 | list_add(&buf->list, &acm->filled_read_bufs); |
| 361 | spin_unlock(&acm->read_lock); | 361 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 362 | return; | 362 | return; |
| 363 | } | 363 | } |
| 364 | spin_unlock(&acm->throttle_lock); | 364 | spin_unlock(&acm->throttle_lock); |
| 365 | 365 | ||
| 366 | spin_lock(&acm->read_lock); | 366 | spin_lock_irqsave(&acm->read_lock, flags); |
| 367 | list_add(&buf->list, &acm->spare_read_bufs); | 367 | list_add(&buf->list, &acm->spare_read_bufs); |
| 368 | spin_unlock(&acm->read_lock); | 368 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 369 | goto next_buffer; | 369 | goto next_buffer; |
| 370 | 370 | ||
| 371 | urbs: | 371 | urbs: |
| 372 | while (!list_empty(&acm->spare_read_bufs)) { | 372 | while (!list_empty(&acm->spare_read_bufs)) { |
| 373 | spin_lock(&acm->read_lock); | 373 | spin_lock_irqsave(&acm->read_lock, flags); |
| 374 | if (list_empty(&acm->spare_read_urbs)) { | 374 | if (list_empty(&acm->spare_read_urbs)) { |
| 375 | spin_unlock(&acm->read_lock); | 375 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 376 | return; | 376 | return; |
| 377 | } | 377 | } |
| 378 | rcv = list_entry(acm->spare_read_urbs.next, | 378 | rcv = list_entry(acm->spare_read_urbs.next, |
| 379 | struct acm_ru, list); | 379 | struct acm_ru, list); |
| 380 | list_del(&rcv->list); | 380 | list_del(&rcv->list); |
| 381 | spin_unlock(&acm->read_lock); | 381 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 382 | 382 | ||
| 383 | buf = list_entry(acm->spare_read_bufs.next, | 383 | buf = list_entry(acm->spare_read_bufs.next, |
| 384 | struct acm_rb, list); | 384 | struct acm_rb, list); |
| @@ -400,9 +400,9 @@ urbs: | |||
| 400 | free-urbs-pool and resubmited ASAP */ | 400 | free-urbs-pool and resubmited ASAP */ |
| 401 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | 401 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { |
| 402 | list_add(&buf->list, &acm->spare_read_bufs); | 402 | list_add(&buf->list, &acm->spare_read_bufs); |
| 403 | spin_lock(&acm->read_lock); | 403 | spin_lock_irqsave(&acm->read_lock, flags); |
| 404 | list_add(&rcv->list, &acm->spare_read_urbs); | 404 | list_add(&rcv->list, &acm->spare_read_urbs); |
| 405 | spin_unlock(&acm->read_lock); | 405 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 406 | return; | 406 | return; |
| 407 | } | 407 | } |
| 408 | } | 408 | } |
| @@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = { | |||
| 1083 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ | 1083 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ |
| 1084 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1084 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
| 1085 | }, | 1085 | }, |
| 1086 | { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ | ||
| 1087 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | ||
| 1088 | }, | ||
| 1086 | { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ | 1089 | { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ |
| 1087 | .driver_info = SINGLE_RX_URB, /* firmware bug */ | 1090 | .driver_info = SINGLE_RX_URB, /* firmware bug */ |
| 1088 | }, | 1091 | }, |
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index a161d70e1e42..809d465eb257 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c | |||
| @@ -154,6 +154,7 @@ struct usblp { | |||
| 154 | unsigned char used; /* True if open */ | 154 | unsigned char used; /* True if open */ |
| 155 | unsigned char present; /* True if not disconnected */ | 155 | unsigned char present; /* True if not disconnected */ |
| 156 | unsigned char bidir; /* interface is bidirectional */ | 156 | unsigned char bidir; /* interface is bidirectional */ |
| 157 | unsigned char sleeping; /* interface is suspended */ | ||
| 157 | unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ | 158 | unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ |
| 158 | /* first 2 bytes are (big-endian) length */ | 159 | /* first 2 bytes are (big-endian) length */ |
| 159 | }; | 160 | }; |
| @@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) { | |||
| 183 | dbg("quirks=%d", usblp->quirks); | 184 | dbg("quirks=%d", usblp->quirks); |
| 184 | dbg("used=%d", usblp->used); | 185 | dbg("used=%d", usblp->used); |
| 185 | dbg("bidir=%d", usblp->bidir); | 186 | dbg("bidir=%d", usblp->bidir); |
| 187 | dbg("sleeping=%d", usblp->sleeping); | ||
| 186 | dbg("device_id_string=\"%s\"", | 188 | dbg("device_id_string=\"%s\"", |
| 187 | usblp->device_id_string ? | 189 | usblp->device_id_string ? |
| 188 | usblp->device_id_string + 2 : | 190 | usblp->device_id_string + 2 : |
| @@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err) | |||
| 338 | return newerr; | 340 | return newerr; |
| 339 | } | 341 | } |
| 340 | 342 | ||
| 343 | static int handle_bidir (struct usblp *usblp) | ||
| 344 | { | ||
| 345 | if (usblp->bidir && usblp->used && !usblp->sleeping) { | ||
| 346 | usblp->readcount = 0; | ||
| 347 | usblp->readurb->dev = usblp->dev; | ||
| 348 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { | ||
| 349 | usblp->used = 0; | ||
| 350 | return -EIO; | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 341 | /* | 357 | /* |
| 342 | * File op functions. | 358 | * File op functions. |
| 343 | */ | 359 | */ |
| @@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file) | |||
| 390 | usblp->writeurb->status = 0; | 406 | usblp->writeurb->status = 0; |
| 391 | usblp->readurb->status = 0; | 407 | usblp->readurb->status = 0; |
| 392 | 408 | ||
| 393 | if (usblp->bidir) { | 409 | if (handle_bidir(usblp) < 0) { |
| 394 | usblp->readcount = 0; | 410 | file->private_data = NULL; |
| 395 | usblp->readurb->dev = usblp->dev; | 411 | retval = -EIO; |
| 396 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { | ||
| 397 | retval = -EIO; | ||
| 398 | usblp->used = 0; | ||
| 399 | file->private_data = NULL; | ||
| 400 | } | ||
| 401 | } | 412 | } |
| 402 | out: | 413 | out: |
| 403 | mutex_unlock (&usblp_mutex); | 414 | mutex_unlock (&usblp_mutex); |
| @@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 460 | goto done; | 471 | goto done; |
| 461 | } | 472 | } |
| 462 | 473 | ||
| 474 | if (usblp->sleeping) { | ||
| 475 | retval = -ENODEV; | ||
| 476 | goto done; | ||
| 477 | } | ||
| 478 | |||
| 463 | dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), | 479 | dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), |
| 464 | _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); | 480 | _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); |
| 465 | 481 | ||
| @@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t | |||
| 658 | return -ENODEV; | 674 | return -ENODEV; |
| 659 | } | 675 | } |
| 660 | 676 | ||
| 677 | if (usblp->sleeping) { | ||
| 678 | up (&usblp->sem); | ||
| 679 | return writecount ? writecount : -ENODEV; | ||
| 680 | } | ||
| 681 | |||
| 661 | if (usblp->writeurb->status != 0) { | 682 | if (usblp->writeurb->status != 0) { |
| 662 | if (usblp->quirks & USBLP_QUIRK_BIDIR) { | 683 | if (usblp->quirks & USBLP_QUIRK_BIDIR) { |
| 663 | if (!usblp->wcomplete) | 684 | if (!usblp->wcomplete) |
| @@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, | |||
| 749 | goto done; | 770 | goto done; |
| 750 | } | 771 | } |
| 751 | 772 | ||
| 773 | if (usblp->sleeping) { | ||
| 774 | count = -ENODEV; | ||
| 775 | goto done; | ||
| 776 | } | ||
| 777 | |||
| 752 | if (usblp->readurb->status) { | 778 | if (usblp->readurb->status) { |
| 753 | err("usblp%d: error %d reading from printer", | 779 | err("usblp%d: error %d reading from printer", |
| 754 | usblp->minor, usblp->readurb->status); | 780 | usblp->minor, usblp->readurb->status); |
| @@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf) | |||
| 1167 | mutex_unlock (&usblp_mutex); | 1193 | mutex_unlock (&usblp_mutex); |
| 1168 | } | 1194 | } |
| 1169 | 1195 | ||
| 1196 | static int usblp_suspend (struct usb_interface *intf, pm_message_t message) | ||
| 1197 | { | ||
| 1198 | struct usblp *usblp = usb_get_intfdata (intf); | ||
| 1199 | |||
| 1200 | /* this races against normal access and open */ | ||
| 1201 | mutex_lock (&usblp_mutex); | ||
| 1202 | down (&usblp->sem); | ||
| 1203 | /* we take no more IO */ | ||
| 1204 | usblp->sleeping = 1; | ||
| 1205 | /* we wait for anything printing */ | ||
| 1206 | wait_event (usblp->wait, usblp->wcomplete || !usblp->present); | ||
| 1207 | usblp_unlink_urbs(usblp); | ||
| 1208 | up (&usblp->sem); | ||
| 1209 | mutex_unlock (&usblp_mutex); | ||
| 1210 | |||
| 1211 | return 0; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | static int usblp_resume (struct usb_interface *intf) | ||
| 1215 | { | ||
| 1216 | struct usblp *usblp = usb_get_intfdata (intf); | ||
| 1217 | int r; | ||
| 1218 | |||
| 1219 | mutex_lock (&usblp_mutex); | ||
| 1220 | down (&usblp->sem); | ||
| 1221 | |||
| 1222 | usblp->sleeping = 0; | ||
| 1223 | r = handle_bidir (usblp); | ||
| 1224 | |||
| 1225 | up (&usblp->sem); | ||
| 1226 | mutex_unlock (&usblp_mutex); | ||
| 1227 | |||
| 1228 | return r; | ||
| 1229 | } | ||
| 1230 | |||
| 1170 | static struct usb_device_id usblp_ids [] = { | 1231 | static struct usb_device_id usblp_ids [] = { |
| 1171 | { USB_DEVICE_INFO(7, 1, 1) }, | 1232 | { USB_DEVICE_INFO(7, 1, 1) }, |
| 1172 | { USB_DEVICE_INFO(7, 1, 2) }, | 1233 | { USB_DEVICE_INFO(7, 1, 2) }, |
| @@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = { | |||
| 1183 | .name = "usblp", | 1244 | .name = "usblp", |
| 1184 | .probe = usblp_probe, | 1245 | .probe = usblp_probe, |
| 1185 | .disconnect = usblp_disconnect, | 1246 | .disconnect = usblp_disconnect, |
| 1247 | .suspend = usblp_suspend, | ||
| 1248 | .resume = usblp_resume, | ||
| 1186 | .id_table = usblp_ids, | 1249 | .id_table = usblp_ids, |
| 1187 | }; | 1250 | }; |
| 1188 | 1251 | ||
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 724822cac2b1..fed92be63b5e 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
| @@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = { | |||
| 1588 | .release = usbdev_release, | 1588 | .release = usbdev_release, |
| 1589 | }; | 1589 | }; |
| 1590 | 1590 | ||
| 1591 | static void usbdev_add(struct usb_device *dev) | 1591 | static int usbdev_add(struct usb_device *dev) |
| 1592 | { | 1592 | { |
| 1593 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); | 1593 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); |
| 1594 | 1594 | ||
| 1595 | dev->class_dev = class_device_create(usb_device_class, NULL, | 1595 | dev->class_dev = class_device_create(usb_device_class, NULL, |
| 1596 | MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, | 1596 | MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, |
| 1597 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); | 1597 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); |
| 1598 | if (IS_ERR(dev->class_dev)) | ||
| 1599 | return PTR_ERR(dev->class_dev); | ||
| 1598 | 1600 | ||
| 1599 | dev->class_dev->class_data = dev; | 1601 | dev->class_dev->class_data = dev; |
| 1602 | return 0; | ||
| 1600 | } | 1603 | } |
| 1601 | 1604 | ||
| 1602 | static void usbdev_remove(struct usb_device *dev) | 1605 | static void usbdev_remove(struct usb_device *dev) |
| @@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action, | |||
| 1609 | { | 1612 | { |
| 1610 | switch (action) { | 1613 | switch (action) { |
| 1611 | case USB_DEVICE_ADD: | 1614 | case USB_DEVICE_ADD: |
| 1612 | usbdev_add(dev); | 1615 | if (usbdev_add(dev)) |
| 1616 | return NOTIFY_BAD; | ||
| 1613 | break; | 1617 | break; |
| 1614 | case USB_DEVICE_REMOVE: | 1618 | case USB_DEVICE_REMOVE: |
| 1615 | usbdev_remove(dev); | 1619 | usbdev_remove(dev); |
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 3ebb90149e93..3b2d137912be 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c | |||
| @@ -223,7 +223,7 @@ int usb_create_ep_files(struct device *parent, | |||
| 223 | ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); | 223 | ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); |
| 224 | if (!ep_dev) { | 224 | if (!ep_dev) { |
| 225 | retval = -ENOMEM; | 225 | retval = -ENOMEM; |
| 226 | goto exit; | 226 | goto error_alloc; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | /* fun calculation to determine the minor of this endpoint */ | 229 | /* fun calculation to determine the minor of this endpoint */ |
| @@ -241,33 +241,31 @@ int usb_create_ep_files(struct device *parent, | |||
| 241 | 241 | ||
| 242 | retval = device_register(&ep_dev->dev); | 242 | retval = device_register(&ep_dev->dev); |
| 243 | if (retval) | 243 | if (retval) |
| 244 | goto error; | 244 | goto error_register; |
| 245 | retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); | 245 | retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); |
| 246 | if (retval) | 246 | if (retval) |
| 247 | goto error_group; | 247 | goto error_group; |
| 248 | 248 | ||
| 249 | endpoint->ep_dev = ep_dev; | ||
| 250 | |||
| 251 | /* create the symlink to the old-style "ep_XX" directory */ | 249 | /* create the symlink to the old-style "ep_XX" directory */ |
| 252 | sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); | 250 | sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); |
| 253 | retval = sysfs_create_link(&parent->kobj, | 251 | retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name); |
| 254 | &endpoint->ep_dev->dev.kobj, name); | ||
| 255 | if (retval) | 252 | if (retval) |
| 256 | goto error_link; | 253 | goto error_link; |
| 257 | exit: | 254 | endpoint->ep_dev = ep_dev; |
| 258 | return retval; | 255 | return retval; |
| 259 | 256 | ||
| 260 | error_link: | 257 | error_link: |
| 261 | sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); | 258 | sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); |
| 262 | |||
| 263 | error_group: | 259 | error_group: |
| 264 | device_unregister(&ep_dev->dev); | 260 | device_unregister(&ep_dev->dev); |
| 265 | endpoint->ep_dev = NULL; | ||
| 266 | destroy_endpoint_class(); | 261 | destroy_endpoint_class(); |
| 267 | return retval; | 262 | return retval; |
| 268 | error: | 263 | |
| 264 | error_register: | ||
| 269 | kfree(ep_dev); | 265 | kfree(ep_dev); |
| 266 | error_alloc: | ||
| 270 | destroy_endpoint_class(); | 267 | destroy_endpoint_class(); |
| 268 | exit: | ||
| 271 | return retval; | 269 | return retval; |
| 272 | } | 270 | } |
| 273 | 271 | ||
| @@ -282,8 +280,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint) | |||
| 282 | sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); | 280 | sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); |
| 283 | device_unregister(&endpoint->ep_dev->dev); | 281 | device_unregister(&endpoint->ep_dev->dev); |
| 284 | endpoint->ep_dev = NULL; | 282 | endpoint->ep_dev = NULL; |
| 283 | destroy_endpoint_class(); | ||
| 285 | } | 284 | } |
| 286 | destroy_endpoint_class(); | ||
| 287 | } | 285 | } |
| 288 | |||
| 289 | |||
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d954daa8e9e0..7cfe0e5cf670 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c | |||
| @@ -2044,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
| 2044 | return retval; | 2044 | return retval; |
| 2045 | } | 2045 | } |
| 2046 | 2046 | ||
| 2047 | device_create_file (&dev->pdev->dev, &dev_attr_function); | 2047 | retval = device_create_file (&dev->pdev->dev, &dev_attr_function); |
| 2048 | device_create_file (&dev->pdev->dev, &dev_attr_queues); | 2048 | if (retval) goto err_unbind; |
| 2049 | retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); | ||
| 2050 | if (retval) goto err_func; | ||
| 2049 | 2051 | ||
| 2050 | /* ... then enable host detection and ep0; and we're ready | 2052 | /* ... then enable host detection and ep0; and we're ready |
| 2051 | * for set_configuration as well as eventual disconnect. | 2053 | * for set_configuration as well as eventual disconnect. |
| @@ -2060,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
| 2060 | 2062 | ||
| 2061 | /* pci writes may still be posted */ | 2063 | /* pci writes may still be posted */ |
| 2062 | return 0; | 2064 | return 0; |
| 2065 | |||
| 2066 | err_func: | ||
| 2067 | device_remove_file (&dev->pdev->dev, &dev_attr_function); | ||
| 2068 | err_unbind: | ||
| 2069 | driver->unbind (&dev->gadget); | ||
| 2070 | dev->gadget.dev.driver = NULL; | ||
| 2071 | dev->driver = NULL; | ||
| 2072 | return retval; | ||
| 2063 | } | 2073 | } |
| 2064 | EXPORT_SYMBOL (usb_gadget_register_driver); | 2074 | EXPORT_SYMBOL (usb_gadget_register_driver); |
| 2065 | 2075 | ||
| @@ -2974,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2974 | : "disabled"); | 2984 | : "disabled"); |
| 2975 | the_controller = dev; | 2985 | the_controller = dev; |
| 2976 | 2986 | ||
| 2977 | device_register (&dev->gadget.dev); | 2987 | retval = device_register (&dev->gadget.dev); |
| 2978 | device_create_file (&pdev->dev, &dev_attr_registers); | 2988 | if (retval) goto done; |
| 2989 | retval = device_create_file (&pdev->dev, &dev_attr_registers); | ||
| 2990 | if (retval) goto done; | ||
| 2979 | 2991 | ||
| 2980 | return 0; | 2992 | return 0; |
| 2981 | 2993 | ||
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 23b95b2bfe15..34b7a31cd85b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c | |||
| @@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf) | |||
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | if (ehci->reclaim) { | 756 | if (ehci->reclaim) { |
| 757 | temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim); | 757 | temp = scnprintf (next, size, "reclaim qh %p%s\n", |
| 758 | ehci->reclaim, | ||
| 759 | ehci->reclaim_ready ? " ready" : ""); | ||
| 758 | size -= temp; | 760 | size -= temp; |
| 759 | next += temp; | 761 | next += temp; |
| 760 | } | 762 | } |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index aac6ec5dd7cf..9030994aba98 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
| @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; | |||
| 111 | #define EHCI_TUNE_MULT_TT 1 | 111 | #define EHCI_TUNE_MULT_TT 1 |
| 112 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ | 112 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ |
| 113 | 113 | ||
| 114 | #define EHCI_IAA_MSECS 10 /* arbitrary */ | 114 | #define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ |
| 115 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 115 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
| 116 | #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ | 116 | #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ |
| 117 | #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ | 117 | #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ |
| @@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
| 254 | 254 | ||
| 255 | /*-------------------------------------------------------------------------*/ | 255 | /*-------------------------------------------------------------------------*/ |
| 256 | 256 | ||
| 257 | static void end_unlink_async (struct ehci_hcd *ehci); | ||
| 258 | static void ehci_work(struct ehci_hcd *ehci); | 257 | static void ehci_work(struct ehci_hcd *ehci); |
| 259 | 258 | ||
| 260 | #include "ehci-hub.c" | 259 | #include "ehci-hub.c" |
| @@ -264,37 +263,25 @@ static void ehci_work(struct ehci_hcd *ehci); | |||
| 264 | 263 | ||
| 265 | /*-------------------------------------------------------------------------*/ | 264 | /*-------------------------------------------------------------------------*/ |
| 266 | 265 | ||
| 267 | static void ehci_iaa_watchdog (unsigned long param) | 266 | static void ehci_watchdog (unsigned long param) |
| 268 | { | 267 | { |
| 269 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | 268 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; |
| 270 | unsigned long flags; | 269 | unsigned long flags; |
| 271 | u32 status; | ||
| 272 | 270 | ||
| 273 | spin_lock_irqsave (&ehci->lock, flags); | 271 | spin_lock_irqsave (&ehci->lock, flags); |
| 274 | WARN_ON(!ehci->reclaim); | ||
| 275 | 272 | ||
| 276 | /* lost IAA irqs wedge things badly; seen first with a vt8235 */ | 273 | /* lost IAA irqs wedge things badly; seen with a vt8235 */ |
| 277 | if (ehci->reclaim) { | 274 | if (ehci->reclaim) { |
| 278 | status = readl (&ehci->regs->status); | 275 | u32 status = readl (&ehci->regs->status); |
| 279 | if (status & STS_IAA) { | 276 | if (status & STS_IAA) { |
| 280 | ehci_vdbg (ehci, "lost IAA\n"); | 277 | ehci_vdbg (ehci, "lost IAA\n"); |
| 281 | COUNT (ehci->stats.lost_iaa); | 278 | COUNT (ehci->stats.lost_iaa); |
| 282 | writel (STS_IAA, &ehci->regs->status); | 279 | writel (STS_IAA, &ehci->regs->status); |
| 283 | end_unlink_async (ehci); | 280 | ehci->reclaim_ready = 1; |
| 284 | } | 281 | } |
| 285 | } | 282 | } |
| 286 | 283 | ||
| 287 | spin_unlock_irqrestore (&ehci->lock, flags); | 284 | /* stop async processing after it's idled a bit */ |
| 288 | } | ||
| 289 | |||
| 290 | static void ehci_watchdog (unsigned long param) | ||
| 291 | { | ||
| 292 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | ||
| 293 | unsigned long flags; | ||
| 294 | |||
| 295 | spin_lock_irqsave (&ehci->lock, flags); | ||
| 296 | |||
| 297 | /* stop async processing after it's idled a bit */ | ||
| 298 | if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) | 285 | if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) |
| 299 | start_unlink_async (ehci, ehci->async); | 286 | start_unlink_async (ehci, ehci->async); |
| 300 | 287 | ||
| @@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) | |||
| 345 | static void ehci_work (struct ehci_hcd *ehci) | 332 | static void ehci_work (struct ehci_hcd *ehci) |
| 346 | { | 333 | { |
| 347 | timer_action_done (ehci, TIMER_IO_WATCHDOG); | 334 | timer_action_done (ehci, TIMER_IO_WATCHDOG); |
| 335 | if (ehci->reclaim_ready) | ||
| 336 | end_unlink_async (ehci); | ||
| 348 | 337 | ||
| 349 | /* another CPU may drop ehci->lock during a schedule scan while | 338 | /* another CPU may drop ehci->lock during a schedule scan while |
| 350 | * it reports urb completions. this flag guards against bogus | 339 | * it reports urb completions. this flag guards against bogus |
| @@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
| 379 | 368 | ||
| 380 | /* no more interrupts ... */ | 369 | /* no more interrupts ... */ |
| 381 | del_timer_sync (&ehci->watchdog); | 370 | del_timer_sync (&ehci->watchdog); |
| 382 | del_timer_sync (&ehci->iaa_watchdog); | ||
| 383 | 371 | ||
| 384 | spin_lock_irq(&ehci->lock); | 372 | spin_lock_irq(&ehci->lock); |
| 385 | if (HC_IS_RUNNING (hcd->state)) | 373 | if (HC_IS_RUNNING (hcd->state)) |
| @@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd) | |||
| 426 | ehci->watchdog.function = ehci_watchdog; | 414 | ehci->watchdog.function = ehci_watchdog; |
| 427 | ehci->watchdog.data = (unsigned long) ehci; | 415 | ehci->watchdog.data = (unsigned long) ehci; |
| 428 | 416 | ||
| 429 | init_timer(&ehci->iaa_watchdog); | ||
| 430 | ehci->iaa_watchdog.function = ehci_iaa_watchdog; | ||
| 431 | ehci->iaa_watchdog.data = (unsigned long) ehci; | ||
| 432 | |||
| 433 | /* | 417 | /* |
| 434 | * hw default: 1K periodic list heads, one per frame. | 418 | * hw default: 1K periodic list heads, one per frame. |
| 435 | * periodic_size can shrink by USBCMD update if hcc_params allows. | 419 | * periodic_size can shrink by USBCMD update if hcc_params allows. |
| @@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd) | |||
| 446 | ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); | 430 | ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); |
| 447 | 431 | ||
| 448 | ehci->reclaim = NULL; | 432 | ehci->reclaim = NULL; |
| 433 | ehci->reclaim_ready = 0; | ||
| 449 | ehci->next_uframe = -1; | 434 | ehci->next_uframe = -1; |
| 450 | 435 | ||
| 451 | /* | 436 | /* |
| @@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
| 619 | /* complete the unlinking of some qh [4.15.2.3] */ | 604 | /* complete the unlinking of some qh [4.15.2.3] */ |
| 620 | if (status & STS_IAA) { | 605 | if (status & STS_IAA) { |
| 621 | COUNT (ehci->stats.reclaim); | 606 | COUNT (ehci->stats.reclaim); |
| 622 | end_unlink_async (ehci); | 607 | ehci->reclaim_ready = 1; |
| 623 | bh = 1; | 608 | bh = 1; |
| 624 | } | 609 | } |
| 625 | 610 | ||
| @@ -723,14 +708,10 @@ static int ehci_urb_enqueue ( | |||
| 723 | 708 | ||
| 724 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | 709 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) |
| 725 | { | 710 | { |
| 726 | // BUG_ON(qh->qh_state != QH_STATE_LINKED); | 711 | /* if we need to use IAA and it's busy, defer */ |
| 727 | 712 | if (qh->qh_state == QH_STATE_LINKED | |
| 728 | /* failfast */ | 713 | && ehci->reclaim |
| 729 | if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) | 714 | && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { |
| 730 | end_unlink_async (ehci); | ||
| 731 | |||
| 732 | /* defer till later if busy */ | ||
| 733 | else if (ehci->reclaim) { | ||
| 734 | struct ehci_qh *last; | 715 | struct ehci_qh *last; |
| 735 | 716 | ||
| 736 | for (last = ehci->reclaim; | 717 | for (last = ehci->reclaim; |
| @@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 740 | qh->qh_state = QH_STATE_UNLINK_WAIT; | 721 | qh->qh_state = QH_STATE_UNLINK_WAIT; |
| 741 | last->reclaim = qh; | 722 | last->reclaim = qh; |
| 742 | 723 | ||
| 743 | /* start IAA cycle */ | 724 | /* bypass IAA if the hc can't care */ |
| 744 | } else | 725 | } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) |
| 726 | end_unlink_async (ehci); | ||
| 727 | |||
| 728 | /* something else might have unlinked the qh by now */ | ||
| 729 | if (qh->qh_state == QH_STATE_LINKED) | ||
| 745 | start_unlink_async (ehci, qh); | 730 | start_unlink_async (ehci, qh); |
| 746 | } | 731 | } |
| 747 | 732 | ||
| @@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) | |||
| 763 | qh = (struct ehci_qh *) urb->hcpriv; | 748 | qh = (struct ehci_qh *) urb->hcpriv; |
| 764 | if (!qh) | 749 | if (!qh) |
| 765 | break; | 750 | break; |
| 766 | switch (qh->qh_state) { | 751 | unlink_async (ehci, qh); |
| 767 | case QH_STATE_LINKED: | ||
| 768 | case QH_STATE_COMPLETING: | ||
| 769 | unlink_async (ehci, qh); | ||
| 770 | break; | ||
| 771 | case QH_STATE_UNLINK: | ||
| 772 | case QH_STATE_UNLINK_WAIT: | ||
| 773 | /* already started */ | ||
| 774 | break; | ||
| 775 | case QH_STATE_IDLE: | ||
| 776 | WARN_ON(1); | ||
| 777 | break; | ||
| 778 | } | ||
| 779 | break; | 752 | break; |
| 780 | 753 | ||
| 781 | case PIPE_INTERRUPT: | 754 | case PIPE_INTERRUPT: |
| @@ -867,7 +840,6 @@ rescan: | |||
| 867 | unlink_async (ehci, qh); | 840 | unlink_async (ehci, qh); |
| 868 | /* FALL THROUGH */ | 841 | /* FALL THROUGH */ |
| 869 | case QH_STATE_UNLINK: /* wait for hw to finish? */ | 842 | case QH_STATE_UNLINK: /* wait for hw to finish? */ |
| 870 | case QH_STATE_UNLINK_WAIT: | ||
| 871 | idle_timeout: | 843 | idle_timeout: |
| 872 | spin_unlock_irqrestore (&ehci->lock, flags); | 844 | spin_unlock_irqrestore (&ehci->lock, flags); |
| 873 | schedule_timeout_uninterruptible(1); | 845 | schedule_timeout_uninterruptible(1); |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2012213c0a25..1b20722c102b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
| @@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
| 48 | } | 48 | } |
| 49 | ehci->command = readl (&ehci->regs->command); | 49 | ehci->command = readl (&ehci->regs->command); |
| 50 | if (ehci->reclaim) | 50 | if (ehci->reclaim) |
| 51 | end_unlink_async (ehci); | 51 | ehci->reclaim_ready = 1; |
| 52 | ehci_work(ehci); | 52 | ehci_work(ehci); |
| 53 | 53 | ||
| 54 | /* suspend any active/unsuspended ports, maybe allow wakeup */ | 54 | /* suspend any active/unsuspended ports, maybe allow wakeup */ |
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 35e3fab6fc4e..e51c1ed81ac4 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
| @@ -303,7 +303,7 @@ restart: | |||
| 303 | /* emptying the schedule aborts any urbs */ | 303 | /* emptying the schedule aborts any urbs */ |
| 304 | spin_lock_irq(&ehci->lock); | 304 | spin_lock_irq(&ehci->lock); |
| 305 | if (ehci->reclaim) | 305 | if (ehci->reclaim) |
| 306 | end_unlink_async (ehci); | 306 | ehci->reclaim_ready = 1; |
| 307 | ehci_work(ehci); | 307 | ehci_work(ehci); |
| 308 | spin_unlock_irq(&ehci->lock); | 308 | spin_unlock_irq(&ehci->lock); |
| 309 | 309 | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 46327272f614..62e46dc60e86 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
| @@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) | |||
| 967 | struct ehci_qh *qh = ehci->reclaim; | 967 | struct ehci_qh *qh = ehci->reclaim; |
| 968 | struct ehci_qh *next; | 968 | struct ehci_qh *next; |
| 969 | 969 | ||
| 970 | iaa_watchdog_done (ehci); | 970 | timer_action_done (ehci, TIMER_IAA_WATCHDOG); |
| 971 | 971 | ||
| 972 | // qh->hw_next = cpu_to_le32 (qh->qh_dma); | 972 | // qh->hw_next = cpu_to_le32 (qh->qh_dma); |
| 973 | qh->qh_state = QH_STATE_IDLE; | 973 | qh->qh_state = QH_STATE_IDLE; |
| @@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) | |||
| 977 | /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ | 977 | /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ |
| 978 | next = qh->reclaim; | 978 | next = qh->reclaim; |
| 979 | ehci->reclaim = next; | 979 | ehci->reclaim = next; |
| 980 | ehci->reclaim_ready = 0; | ||
| 980 | qh->reclaim = NULL; | 981 | qh->reclaim = NULL; |
| 981 | 982 | ||
| 982 | qh_completions (ehci, qh); | 983 | qh_completions (ehci, qh); |
| @@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 1051 | return; | 1052 | return; |
| 1052 | } | 1053 | } |
| 1053 | 1054 | ||
| 1055 | ehci->reclaim_ready = 0; | ||
| 1054 | cmd |= CMD_IAAD; | 1056 | cmd |= CMD_IAAD; |
| 1055 | writel (cmd, &ehci->regs->command); | 1057 | writel (cmd, &ehci->regs->command); |
| 1056 | (void) readl (&ehci->regs->command); | 1058 | (void) readl (&ehci->regs->command); |
| 1057 | iaa_watchdog_start (ehci); | 1059 | timer_action (ehci, TIMER_IAA_WATCHDOG); |
| 1058 | } | 1060 | } |
| 1059 | 1061 | ||
| 1060 | /*-------------------------------------------------------------------------*/ | 1062 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6aac39f50e07..bbc3082a73d7 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
| @@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */ | |||
| 58 | /* async schedule support */ | 58 | /* async schedule support */ |
| 59 | struct ehci_qh *async; | 59 | struct ehci_qh *async; |
| 60 | struct ehci_qh *reclaim; | 60 | struct ehci_qh *reclaim; |
| 61 | unsigned reclaim_ready : 1; | ||
| 61 | unsigned scanning : 1; | 62 | unsigned scanning : 1; |
| 62 | 63 | ||
| 63 | /* periodic schedule support */ | 64 | /* periodic schedule support */ |
| @@ -80,7 +81,6 @@ struct ehci_hcd { /* one per controller */ | |||
| 80 | struct dma_pool *itd_pool; /* itd per iso urb */ | 81 | struct dma_pool *itd_pool; /* itd per iso urb */ |
| 81 | struct dma_pool *sitd_pool; /* sitd per split iso urb */ | 82 | struct dma_pool *sitd_pool; /* sitd per split iso urb */ |
| 82 | 83 | ||
| 83 | struct timer_list iaa_watchdog; | ||
| 84 | struct timer_list watchdog; | 84 | struct timer_list watchdog; |
| 85 | unsigned long actions; | 85 | unsigned long actions; |
| 86 | unsigned stamp; | 86 | unsigned stamp; |
| @@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | 116 | ||
| 117 | static inline void | ||
| 118 | iaa_watchdog_start (struct ehci_hcd *ehci) | ||
| 119 | { | ||
| 120 | WARN_ON(timer_pending(&ehci->iaa_watchdog)); | ||
| 121 | mod_timer (&ehci->iaa_watchdog, | ||
| 122 | jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); | ||
| 123 | } | ||
| 124 | |||
| 125 | static inline void iaa_watchdog_done (struct ehci_hcd *ehci) | ||
| 126 | { | ||
| 127 | del_timer (&ehci->iaa_watchdog); | ||
| 128 | } | ||
| 129 | |||
| 130 | enum ehci_timer_action { | 117 | enum ehci_timer_action { |
| 131 | TIMER_IO_WATCHDOG, | 118 | TIMER_IO_WATCHDOG, |
| 119 | TIMER_IAA_WATCHDOG, | ||
| 132 | TIMER_ASYNC_SHRINK, | 120 | TIMER_ASYNC_SHRINK, |
| 133 | TIMER_ASYNC_OFF, | 121 | TIMER_ASYNC_OFF, |
| 134 | }; | 122 | }; |
| @@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) | |||
| 146 | unsigned long t; | 134 | unsigned long t; |
| 147 | 135 | ||
| 148 | switch (action) { | 136 | switch (action) { |
| 137 | case TIMER_IAA_WATCHDOG: | ||
| 138 | t = EHCI_IAA_JIFFIES; | ||
| 139 | break; | ||
| 149 | case TIMER_IO_WATCHDOG: | 140 | case TIMER_IO_WATCHDOG: |
| 150 | t = EHCI_IO_JIFFIES; | 141 | t = EHCI_IO_JIFFIES; |
| 151 | break; | 142 | break; |
| @@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) | |||
| 162 | // async queue SHRINK often precedes IAA. while it's ready | 153 | // async queue SHRINK often precedes IAA. while it's ready |
| 163 | // to go OFF neither can matter, and afterwards the IO | 154 | // to go OFF neither can matter, and afterwards the IO |
| 164 | // watchdog stops unless there's still periodic traffic. | 155 | // watchdog stops unless there's still periodic traffic. |
| 165 | if (time_before_eq(t, ehci->watchdog.expires) | 156 | if (action != TIMER_IAA_WATCHDOG |
| 157 | && t > ehci->watchdog.expires | ||
| 166 | && timer_pending (&ehci->watchdog)) | 158 | && timer_pending (&ehci->watchdog)) |
| 167 | return; | 159 | return; |
| 168 | mod_timer (&ehci->watchdog, t); | 160 | mod_timer (&ehci->watchdog, t); |
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 82cb22f002e7..2dbb77414905 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c | |||
| @@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { | |||
| 262 | */ | 262 | */ |
| 263 | .start = ohci_pnx4008_start, | 263 | .start = ohci_pnx4008_start, |
| 264 | .stop = ohci_stop, | 264 | .stop = ohci_stop, |
| 265 | .shutdown = ohci_shutdown, | ||
| 265 | 266 | ||
| 266 | /* | 267 | /* |
| 267 | * managing i/o requests and associated device resources | 268 | * managing i/o requests and associated device resources |
| @@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { | |||
| 280 | */ | 281 | */ |
| 281 | .hub_status_data = ohci_hub_status_data, | 282 | .hub_status_data = ohci_hub_status_data, |
| 282 | .hub_control = ohci_hub_control, | 283 | .hub_control = ohci_hub_control, |
| 283 | 284 | .hub_irq_enable = ohci_rhsc_enable, | |
| 285 | #ifdef CONFIG_PM | ||
| 286 | .bus_suspend = ohci_bus_suspend, | ||
| 287 | .bus_resume = ohci_bus_resume, | ||
| 288 | #endif | ||
| 284 | .start_port_reset = ohci_start_port_reset, | 289 | .start_port_reset = ohci_start_port_reset, |
| 285 | }; | 290 | }; |
| 286 | 291 | ||
| @@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) | |||
| 410 | goto out4; | 415 | goto out4; |
| 411 | } | 416 | } |
| 412 | 417 | ||
| 413 | hcd->self.hcpriv = (void *)hcd; | ||
| 414 | |||
| 415 | pnx4008_start_hc(); | 418 | pnx4008_start_hc(); |
| 416 | platform_set_drvdata(pdev, hcd); | 419 | platform_set_drvdata(pdev, hcd); |
| 417 | ohci = hcd_to_ohci(hcd); | 420 | ohci = hcd_to_ohci(hcd); |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 45ee6920a850..226bf3de8edd 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
| 41 | #include <linux/usb.h> | 41 | #include <linux/usb.h> |
| 42 | #include <linux/bitops.h> | 42 | #include <linux/bitops.h> |
| 43 | #include <linux/dmi.h> | ||
| 43 | 44 | ||
| 44 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
| 45 | #include <asm/io.h> | 46 | #include <asm/io.h> |
| @@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) | |||
| 196 | return 0; | 197 | return 0; |
| 197 | } | 198 | } |
| 198 | 199 | ||
| 200 | static int remote_wakeup_is_broken(struct uhci_hcd *uhci) | ||
| 201 | { | ||
| 202 | static struct dmi_system_id broken_wakeup_table[] = { | ||
| 203 | { | ||
| 204 | .ident = "Asus A7V8X", | ||
| 205 | .matches = { | ||
| 206 | DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), | ||
| 207 | DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), | ||
| 208 | DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), | ||
| 209 | } | ||
| 210 | }, | ||
| 211 | { } | ||
| 212 | }; | ||
| 213 | int port; | ||
| 214 | |||
| 215 | /* One of Asus's motherboards has a bug which causes it to | ||
| 216 | * wake up immediately from suspend-to-RAM if any of the ports | ||
| 217 | * are connected. In such cases we will not set EGSM. | ||
| 218 | */ | ||
| 219 | if (dmi_check_system(broken_wakeup_table)) { | ||
| 220 | for (port = 0; port < uhci->rh_numports; ++port) { | ||
| 221 | if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & | ||
| 222 | USBPORTSC_CCS) | ||
| 223 | return 1; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 199 | static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) | 230 | static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) |
| 200 | __releases(uhci->lock) | 231 | __releases(uhci->lock) |
| 201 | __acquires(uhci->lock) | 232 | __acquires(uhci->lock) |
| 202 | { | 233 | { |
| 203 | int auto_stop; | 234 | int auto_stop; |
| 204 | int int_enable; | 235 | int int_enable, egsm_enable; |
| 205 | 236 | ||
| 206 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); | 237 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); |
| 207 | dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, | 238 | dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, |
| @@ -217,15 +248,18 @@ __acquires(uhci->lock) | |||
| 217 | } | 248 | } |
| 218 | 249 | ||
| 219 | /* Enable resume-detect interrupts if they work. | 250 | /* Enable resume-detect interrupts if they work. |
| 220 | * Then enter Global Suspend mode, still configured. | 251 | * Then enter Global Suspend mode if _it_ works, still configured. |
| 221 | */ | 252 | */ |
| 253 | egsm_enable = USBCMD_EGSM; | ||
| 222 | uhci->working_RD = 1; | 254 | uhci->working_RD = 1; |
| 223 | int_enable = USBINTR_RESUME; | 255 | int_enable = USBINTR_RESUME; |
| 224 | if (resume_detect_interrupts_are_broken(uhci)) { | 256 | if (remote_wakeup_is_broken(uhci)) |
| 257 | egsm_enable = 0; | ||
| 258 | if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) | ||
| 225 | uhci->working_RD = int_enable = 0; | 259 | uhci->working_RD = int_enable = 0; |
| 226 | } | 260 | |
| 227 | outw(int_enable, uhci->io_addr + USBINTR); | 261 | outw(int_enable, uhci->io_addr + USBINTR); |
| 228 | outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); | 262 | outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); |
| 229 | mb(); | 263 | mb(); |
| 230 | udelay(5); | 264 | udelay(5); |
| 231 | 265 | ||
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 21cd22640080..20db36448ab3 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig | |||
| @@ -348,13 +348,3 @@ config USB_APPLETOUCH | |||
| 348 | 348 | ||
| 349 | To compile this driver as a module, choose M here: the | 349 | To compile this driver as a module, choose M here: the |
| 350 | module will be called appletouch. | 350 | module will be called appletouch. |
| 351 | |||
| 352 | config USB_TRANCEVIBRATOR | ||
| 353 | tristate "PlayStation 2 Trance Vibrator driver support" | ||
| 354 | depends on USB | ||
| 355 | help | ||
| 356 | Say Y here if you want to connect a PlayStation 2 Trance Vibrator | ||
| 357 | device to your computer's USB port. | ||
| 358 | |||
| 359 | To compile this driver as a module, choose M here: the | ||
| 360 | module will be called trancevibrator. | ||
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 295f459d1079..d946d5213b30 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | # Multipart objects. | 5 | # Multipart objects. |
| 6 | wacom-objs := wacom_sys.o wacom_wac.o | 6 | wacom-objs := wacom_wac.o wacom_sys.o |
| 7 | usbhid-objs := hid-core.o | 7 | usbhid-objs := hid-core.o |
| 8 | 8 | ||
| 9 | # Optional parts of multipart objects. | 9 | # Optional parts of multipart objects. |
| @@ -48,7 +48,6 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o | |||
| 48 | obj-$(CONFIG_USB_YEALINK) += yealink.o | 48 | obj-$(CONFIG_USB_YEALINK) += yealink.o |
| 49 | obj-$(CONFIG_USB_XPAD) += xpad.o | 49 | obj-$(CONFIG_USB_XPAD) += xpad.o |
| 50 | obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o | 50 | obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o |
| 51 | obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o | ||
| 52 | 51 | ||
| 53 | ifeq ($(CONFIG_USB_DEBUG),y) | 52 | ifeq ($(CONFIG_USB_DEBUG),y) |
| 54 | EXTRA_CFLAGS += -DDEBUG | 53 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a6738a83ff5b..feabda73a6f9 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
| @@ -750,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) | |||
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | /* | 752 | /* |
| 753 | * Extract/implement a data field from/to a report. | 753 | * Extract/implement a data field from/to a little endian report (bit array). |
| 754 | */ | 754 | */ |
| 755 | 755 | ||
| 756 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) | 756 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) |
| 757 | { | 757 | { |
| 758 | report += (offset >> 5) << 2; offset &= 31; | 758 | u32 x; |
| 759 | return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); | 759 | |
| 760 | report += offset >> 3; /* adjust byte index */ | ||
| 761 | offset &= 8 - 1; | ||
| 762 | x = get_unaligned((u32 *) report); | ||
| 763 | x = le32_to_cpu(x); | ||
| 764 | x = (x >> offset) & ((1 << n) - 1); | ||
| 765 | return x; | ||
| 760 | } | 766 | } |
| 761 | 767 | ||
| 762 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) | 768 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) |
| 763 | { | 769 | { |
| 764 | report += (offset >> 5) << 2; offset &= 31; | 770 | u32 x; |
| 765 | put_unaligned((get_unaligned((__le64*)report) | 771 | |
| 766 | & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) | 772 | report += offset >> 3; |
| 767 | | cpu_to_le64((__u64)value << offset), (__le64*)report); | 773 | offset &= 8 - 1; |
| 774 | x = get_unaligned((u32 *)report); | ||
| 775 | x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset)); | ||
| 776 | x |= cpu_to_le32(value << offset); | ||
| 777 | put_unaligned(x,(u32 *)report); | ||
| 768 | } | 778 | } |
| 769 | 779 | ||
| 770 | /* | 780 | /* |
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index f26c1cd1129f..2902742895ad 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c | |||
| @@ -256,10 +256,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr | |||
| 256 | { | 256 | { |
| 257 | *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); | 257 | *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); |
| 258 | *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); | 258 | *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); |
| 259 | *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); | 259 | *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); |
| 260 | *touch = ~pkt[7] & 0x20; | 260 | *touch = ~pkt[7] & 0x20; |
| 261 | 261 | ||
| 262 | return 1; | 262 | return *touch; |
| 263 | } | 263 | } |
| 264 | #endif | 264 | #endif |
| 265 | 265 | ||
diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h index 7b3840e378a8..1cf08f02c50e 100644 --- a/drivers/usb/input/wacom.h +++ b/drivers/usb/input/wacom.h | |||
| @@ -63,6 +63,7 @@ | |||
| 63 | * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, | 63 | * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, |
| 64 | * - where wacom_sys.c deals with system specific code, | 64 | * - where wacom_sys.c deals with system specific code, |
| 65 | * - and wacom_wac.c deals with Wacom specific code | 65 | * - and wacom_wac.c deals with Wacom specific code |
| 66 | * - Support Intuos3 4x6 | ||
| 66 | */ | 67 | */ |
| 67 | 68 | ||
| 68 | /* | 69 | /* |
| @@ -118,6 +119,7 @@ extern void wacom_input_sync(void *wcombo); | |||
| 118 | extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 119 | extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
| 119 | extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 120 | extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
| 120 | extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 121 | extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
| 122 | extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
| 121 | extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 123 | extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
| 122 | extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 124 | extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
| 123 | extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 125 | extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index d233c37bd533..3498b893b53b 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c | |||
| @@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data) | |||
| 110 | __u16 wacom_le16_to_cpu(unsigned char *data) | 110 | __u16 wacom_le16_to_cpu(unsigned char *data) |
| 111 | { | 111 | { |
| 112 | __u16 value; | 112 | __u16 value; |
| 113 | value = be16_to_cpu(*(__be16 *) data); | 113 | value = le16_to_cpu(*(__le16 *) data); |
| 114 | return value; | 114 | return value; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| @@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | |||
| 143 | input_dev->evbit[0] |= BIT(EV_MSC); | 143 | input_dev->evbit[0] |= BIT(EV_MSC); |
| 144 | input_dev->mscbit[0] |= BIT(MSC_SERIAL); | 144 | input_dev->mscbit[0] |= BIT(MSC_SERIAL); |
| 145 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); | 145 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); |
| 146 | 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); | 146 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 149 | 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) | |||
| 155 | input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); | 155 | input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 158 | void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) |
| 159 | { | 159 | { |
| 160 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); | 160 | input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); |
| 161 | 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); | 161 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); |
| 162 | input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); | 162 | input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); |
| 163 | } | ||
| 164 | |||
| 165 | void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
| 166 | { | ||
| 167 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); | ||
| 163 | input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); | 168 | input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); |
| 164 | } | 169 | } |
| 165 | 170 | ||
| @@ -218,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
| 218 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); | 223 | strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); |
| 219 | 224 | ||
| 220 | wacom_wac->features = get_wacom_feature(id); | 225 | wacom_wac->features = get_wacom_feature(id); |
| 221 | if (wacom_wac->features->pktlen > 10) | 226 | BUG_ON(wacom_wac->features->pktlen > 10); |
| 222 | BUG(); | ||
| 223 | 227 | ||
| 224 | input_dev->name = wacom_wac->features->name; | 228 | input_dev->name = wacom_wac->features->name; |
| 225 | wacom->wacom_wac = wacom_wac; | 229 | wacom->wacom_wac = wacom_wac; |
| @@ -244,7 +248,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i | |||
| 244 | usb_fill_int_urb(wacom->irq, dev, | 248 | usb_fill_int_urb(wacom->irq, dev, |
| 245 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), | 249 | usb_rcvintpipe(dev, endpoint->bEndpointAddress), |
| 246 | wacom_wac->data, wacom_wac->features->pktlen, | 250 | wacom_wac->data, wacom_wac->features->pktlen, |
| 247 | wacom_wac->features->irq, wacom, endpoint->bInterval); | 251 | wacom_sys_irq, wacom, endpoint->bInterval); |
| 248 | wacom->irq->transfer_dma = wacom->data_dma; | 252 | wacom->irq->transfer_dma = wacom->data_dma; |
| 249 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 253 | wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| 250 | 254 | ||
| @@ -278,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf) | |||
| 278 | input_unregister_device(wacom->dev); | 282 | input_unregister_device(wacom->dev); |
| 279 | usb_free_urb(wacom->irq); | 283 | usb_free_urb(wacom->irq); |
| 280 | usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); | 284 | usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); |
| 281 | kfree(wacom); | ||
| 282 | kfree(wacom->wacom_wac); | 285 | kfree(wacom->wacom_wac); |
| 286 | kfree(wacom); | ||
| 283 | } | 287 | } |
| 284 | } | 288 | } |
| 285 | 289 | ||
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index aa31d22d4f05..92726fe89379 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c | |||
| @@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
| 191 | wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); | 191 | wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); |
| 192 | wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); | 192 | wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); |
| 193 | if (wacom->features->type == WACOM_G4) | 193 | if (wacom->features->type == WACOM_G4) |
| 194 | wacom_report_abs(wcombo, ABS_DISTANCE, data[6]); | 194 | wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); |
| 195 | else | 195 | else |
| 196 | wacom_report_abs(wcombo, ABS_DISTANCE, data[7]); | 196 | wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); |
| 197 | break; | 197 | break; |
| 198 | } | 198 | } |
| 199 | } | 199 | } |
| @@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) | |||
| 303 | wacom->tool[idx] = BTN_TOOL_PEN; | 303 | wacom->tool[idx] = BTN_TOOL_PEN; |
| 304 | } | 304 | } |
| 305 | /* only large I3 support Lens Cursor */ | 305 | /* only large I3 support Lens Cursor */ |
| 306 | if(!((wacom->tool[idx] == BTN_TOOL_LENS) && | 306 | if(!((wacom->tool[idx] == BTN_TOOL_LENS) |
| 307 | (wacom->features->type == INTUOS3))) { | 307 | && ((wacom->features->type == INTUOS3) |
| 308 | || (wacom->features->type == INTUOS3S)))) { | ||
| 308 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ | 309 | wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ |
| 309 | wacom_report_key(wcombo, wacom->tool[idx], 1); | 310 | wacom_report_key(wcombo, wacom->tool[idx], 1); |
| 310 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); | 311 | 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) | |||
| 315 | 316 | ||
| 316 | /* Exit report */ | 317 | /* Exit report */ |
| 317 | if ((data[1] & 0xfe) == 0x80) { | 318 | if ((data[1] & 0xfe) == 0x80) { |
| 318 | wacom_report_key(wcombo, wacom->tool[idx], 0); | 319 | if(!((wacom->tool[idx] == BTN_TOOL_LENS) |
| 319 | wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ | 320 | && ((wacom->features->type == INTUOS3) |
| 320 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); | 321 | || (wacom->features->type == INTUOS3S)))) { |
| 321 | return 2; | 322 | wacom_report_key(wcombo, wacom->tool[idx], 0); |
| 323 | wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ | ||
| 324 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); | ||
| 325 | return 2; | ||
| 326 | } | ||
| 322 | } | 327 | } |
| 323 | return 0; | 328 | return 0; |
| 324 | } | 329 | } |
| @@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
| 382 | wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); | 387 | wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); |
| 383 | wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); | 388 | wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); |
| 384 | 389 | ||
| 385 | if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) | 390 | if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | |
| 391 | data[2] | (data[3] & 0x1f) | data[4]) | ||
| 386 | wacom_report_key(wcombo, wacom->tool[1], 1); | 392 | wacom_report_key(wcombo, wacom->tool[1], 1); |
| 387 | else | 393 | else |
| 388 | wacom_report_key(wcombo, wacom->tool[1], 0); | 394 | wacom_report_key(wcombo, wacom->tool[1], 0); |
| @@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
| 432 | ((t - 1) / 2) : -t / 2); | 438 | ((t - 1) / 2) : -t / 2); |
| 433 | } | 439 | } |
| 434 | 440 | ||
| 435 | } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) { | 441 | } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) { |
| 436 | /* 4D mouse packet */ | 442 | /* 4D mouse packet */ |
| 437 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); | 443 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); |
| 438 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); | 444 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); |
| @@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
| 452 | - ((data[8] & 0x02) >> 1)); | 458 | - ((data[8] & 0x02) >> 1)); |
| 453 | 459 | ||
| 454 | /* I3 2D mouse side buttons */ | 460 | /* I3 2D mouse side buttons */ |
| 455 | if (wacom->features->type == INTUOS3) { | 461 | if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { |
| 456 | wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); | 462 | wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); |
| 457 | wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); | 463 | wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); |
| 458 | } | 464 | } |
| 459 | 465 | ||
| 460 | } else if (wacom->features->type < INTUOS3) { | 466 | } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { |
| 461 | /* Lens cursor packets */ | 467 | /* Lens cursor packets */ |
| 462 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); | 468 | wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); |
| 463 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); | 469 | wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); |
| @@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) | |||
| 490 | return (wacom_ptu_irq(wacom_wac, wcombo)); | 496 | return (wacom_ptu_irq(wacom_wac, wcombo)); |
| 491 | break; | 497 | break; |
| 492 | case INTUOS: | 498 | case INTUOS: |
| 499 | case INTUOS3S: | ||
| 493 | case INTUOS3: | 500 | case INTUOS3: |
| 494 | case INTUOS3L: | 501 | case INTUOS3L: |
| 495 | case CINTIQ: | 502 | case CINTIQ: |
| @@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w | |||
| 515 | case CINTIQ: | 522 | case CINTIQ: |
| 516 | input_dev_i3(input_dev, wacom_wac); | 523 | input_dev_i3(input_dev, wacom_wac); |
| 517 | /* fall through */ | 524 | /* fall through */ |
| 525 | case INTUOS3S: | ||
| 526 | input_dev_i3s(input_dev, wacom_wac); | ||
| 518 | case INTUOS: | 527 | case INTUOS: |
| 519 | input_dev_i(input_dev, wacom_wac); | 528 | input_dev_i(input_dev, wacom_wac); |
| 520 | break; | 529 | break; |
| @@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w | |||
| 530 | } | 539 | } |
| 531 | 540 | ||
| 532 | static struct wacom_features wacom_features[] = { | 541 | static struct wacom_features wacom_features[] = { |
| 533 | { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq }, | 542 | { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER }, |
| 534 | { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, | 543 | { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE }, |
| 535 | { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, | 544 | { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE }, |
| 536 | { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq }, | 545 | { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE }, |
| 537 | { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq }, | 546 | { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE }, |
| 538 | { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq }, | 547 | { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, |
| 539 | { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq }, | 548 | { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, |
| 540 | { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq }, | 549 | { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, |
| 541 | { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, | 550 | { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, |
| 542 | { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, | 551 | { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, |
| 543 | { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, | 552 | { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, |
| 544 | { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq }, | 553 | { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, |
| 545 | { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, | 554 | { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, |
| 546 | { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq}, | 555 | { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, |
| 547 | { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, | 556 | { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, |
| 548 | { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, | 557 | { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, |
| 549 | { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, | 558 | { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, |
| 550 | { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq}, | 559 | { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, |
| 551 | { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq }, | 560 | { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, |
| 552 | { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq }, | 561 | { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, |
| 553 | { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq }, | 562 | { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, |
| 554 | { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq }, | 563 | { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL }, |
| 555 | { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq }, | 564 | { "Wacom PL550", 8, 6144, 4608, 511, 0, PL }, |
| 556 | { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq }, | 565 | { "Wacom PL800", 8, 7220, 5780, 511, 0, PL }, |
| 557 | { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq }, | 566 | { "Wacom PL700", 8, 6758, 5406, 511, 0, PL }, |
| 558 | { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, | 567 | { "Wacom PL510", 8, 6282, 4762, 511, 0, PL }, |
| 559 | { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq }, | 568 | { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL }, |
| 560 | { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, | 569 | { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, |
| 561 | { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq }, | 570 | { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, |
| 562 | { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq }, | 571 | { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, |
| 563 | { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq }, | 572 | { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, |
| 564 | { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, | 573 | { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, |
| 565 | { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, | 574 | { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, |
| 566 | { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, | 575 | { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, |
| 567 | { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq }, | 576 | { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, |
| 568 | { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq }, | 577 | { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, |
| 569 | { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq }, | 578 | { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, |
| 570 | { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq }, | 579 | { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, |
| 571 | { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, | 580 | { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, |
| 572 | { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, | 581 | { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, |
| 573 | { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq }, | 582 | { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, |
| 574 | { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq }, | 583 | { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, |
| 575 | { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, | 584 | { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, |
| 585 | { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, | ||
| 576 | { } | 586 | { } |
| 577 | }; | 587 | }; |
| 578 | 588 | ||
| @@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = { | |||
| 618 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, | 628 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, |
| 619 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, | 629 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, |
| 620 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, | 630 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, |
| 631 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, | ||
| 621 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, | 632 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, |
| 622 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, | 633 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, |
| 623 | { } | 634 | { } |
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h index ceae7bf59d9f..a1d9ce007970 100644 --- a/drivers/usb/input/wacom_wac.h +++ b/drivers/usb/input/wacom_wac.h | |||
| @@ -20,6 +20,7 @@ enum { | |||
| 20 | PTU, | 20 | PTU, |
| 21 | PL, | 21 | PL, |
| 22 | INTUOS, | 22 | INTUOS, |
| 23 | INTUOS3S, | ||
| 23 | INTUOS3, | 24 | INTUOS3, |
| 24 | INTUOS3L, | 25 | INTUOS3L, |
| 25 | CINTIQ, | 26 | CINTIQ, |
| @@ -34,7 +35,6 @@ struct wacom_features { | |||
| 34 | int pressure_max; | 35 | int pressure_max; |
| 35 | int distance_max; | 36 | int distance_max; |
| 36 | int type; | 37 | int type; |
| 37 | usb_complete_t irq; | ||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct wacom_wac { | 40 | struct wacom_wac { |
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index cebb6c463bfb..6a12a943b938 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * X-Box gamepad - v0.0.5 | 2 | * X-Box gamepad - v0.0.6 |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> | 4 | * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> |
| 5 | * | 5 | * 2005 Dominic Cerquetti <binary1230@yahoo.com> |
| 6 | * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> | ||
| 6 | * | 7 | * |
| 7 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License as | 9 | * modify it under the terms of the GNU General Public License as |
| @@ -30,9 +31,10 @@ | |||
| 30 | * - Greg Kroah-Hartman - usb-skeleton driver | 31 | * - Greg Kroah-Hartman - usb-skeleton driver |
| 31 | * | 32 | * |
| 32 | * TODO: | 33 | * TODO: |
| 33 | * - fine tune axes | 34 | * - fine tune axes (especially trigger axes) |
| 34 | * - fix "analog" buttons (reported as digital now) | 35 | * - fix "analog" buttons (reported as digital now) |
| 35 | * - get rumble working | 36 | * - get rumble working |
| 37 | * - need USB IDs for other dance pads | ||
| 36 | * | 38 | * |
| 37 | * History: | 39 | * History: |
| 38 | * | 40 | * |
| @@ -57,25 +59,40 @@ | |||
| 57 | #include <linux/kernel.h> | 59 | #include <linux/kernel.h> |
| 58 | #include <linux/init.h> | 60 | #include <linux/init.h> |
| 59 | #include <linux/slab.h> | 61 | #include <linux/slab.h> |
| 62 | #include <linux/stat.h> | ||
| 60 | #include <linux/module.h> | 63 | #include <linux/module.h> |
| 64 | #include <linux/moduleparam.h> | ||
| 61 | #include <linux/smp_lock.h> | 65 | #include <linux/smp_lock.h> |
| 62 | #include <linux/usb/input.h> | 66 | #include <linux/usb/input.h> |
| 63 | 67 | ||
| 64 | #define DRIVER_VERSION "v0.0.5" | 68 | #define DRIVER_VERSION "v0.0.6" |
| 65 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" | 69 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" |
| 66 | #define DRIVER_DESC "X-Box pad driver" | 70 | #define DRIVER_DESC "X-Box pad driver" |
| 67 | 71 | ||
| 68 | #define XPAD_PKT_LEN 32 | 72 | #define XPAD_PKT_LEN 32 |
| 69 | 73 | ||
| 74 | /* xbox d-pads should map to buttons, as is required for DDR pads | ||
| 75 | but we map them to axes when possible to simplify things */ | ||
| 76 | #define MAP_DPAD_TO_BUTTONS 0 | ||
| 77 | #define MAP_DPAD_TO_AXES 1 | ||
| 78 | #define MAP_DPAD_UNKNOWN -1 | ||
| 79 | |||
| 80 | static int dpad_to_buttons; | ||
| 81 | module_param(dpad_to_buttons, bool, S_IRUGO); | ||
| 82 | MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); | ||
| 83 | |||
| 70 | static const struct xpad_device { | 84 | static const struct xpad_device { |
| 71 | u16 idVendor; | 85 | u16 idVendor; |
| 72 | u16 idProduct; | 86 | u16 idProduct; |
| 73 | char *name; | 87 | char *name; |
| 88 | u8 dpad_mapping; | ||
| 74 | } xpad_device[] = { | 89 | } xpad_device[] = { |
| 75 | { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, | 90 | { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, |
| 76 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, | 91 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, |
| 77 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, | 92 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, |
| 78 | { 0x0000, 0x0000, "X-Box pad" } | 93 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, |
| 94 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, | ||
| 95 | { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } | ||
| 79 | }; | 96 | }; |
| 80 | 97 | ||
| 81 | static const signed short xpad_btn[] = { | 98 | static const signed short xpad_btn[] = { |
| @@ -84,11 +101,23 @@ static const signed short xpad_btn[] = { | |||
| 84 | -1 /* terminating entry */ | 101 | -1 /* terminating entry */ |
| 85 | }; | 102 | }; |
| 86 | 103 | ||
| 104 | /* only used if MAP_DPAD_TO_BUTTONS */ | ||
| 105 | static const signed short xpad_btn_pad[] = { | ||
| 106 | BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ | ||
| 107 | BTN_0, BTN_1, /* d-pad up, down (XXX names??) */ | ||
| 108 | -1 /* terminating entry */ | ||
| 109 | }; | ||
| 110 | |||
| 87 | static const signed short xpad_abs[] = { | 111 | static const signed short xpad_abs[] = { |
| 88 | ABS_X, ABS_Y, /* left stick */ | 112 | ABS_X, ABS_Y, /* left stick */ |
| 89 | ABS_RX, ABS_RY, /* right stick */ | 113 | ABS_RX, ABS_RY, /* right stick */ |
| 90 | ABS_Z, ABS_RZ, /* triggers left/right */ | 114 | ABS_Z, ABS_RZ, /* triggers left/right */ |
| 91 | ABS_HAT0X, ABS_HAT0Y, /* digital pad */ | 115 | -1 /* terminating entry */ |
| 116 | }; | ||
| 117 | |||
| 118 | /* only used if MAP_DPAD_TO_AXES */ | ||
| 119 | static const signed short xpad_abs_pad[] = { | ||
| 120 | ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ | ||
| 92 | -1 /* terminating entry */ | 121 | -1 /* terminating entry */ |
| 93 | }; | 122 | }; |
| 94 | 123 | ||
| @@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = { | |||
| 100 | MODULE_DEVICE_TABLE (usb, xpad_table); | 129 | MODULE_DEVICE_TABLE (usb, xpad_table); |
| 101 | 130 | ||
| 102 | struct usb_xpad { | 131 | struct usb_xpad { |
| 103 | struct input_dev *dev; /* input device interface */ | 132 | struct input_dev *dev; /* input device interface */ |
| 104 | struct usb_device *udev; /* usb device */ | 133 | struct usb_device *udev; /* usb device */ |
| 105 | 134 | ||
| 106 | struct urb *irq_in; /* urb for interrupt in report */ | 135 | struct urb *irq_in; /* urb for interrupt in report */ |
| 107 | unsigned char *idata; /* input data */ | 136 | unsigned char *idata; /* input data */ |
| 108 | dma_addr_t idata_dma; | 137 | dma_addr_t idata_dma; |
| 109 | 138 | ||
| 110 | char phys[65]; /* physical device path */ | 139 | char phys[65]; /* physical device path */ |
| 140 | |||
| 141 | int dpad_mapping; /* map d-pad to buttons or to axes */ | ||
| 111 | }; | 142 | }; |
| 112 | 143 | ||
| 113 | /* | 144 | /* |
| @@ -137,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
| 137 | input_report_abs(dev, ABS_RZ, data[11]); | 168 | input_report_abs(dev, ABS_RZ, data[11]); |
| 138 | 169 | ||
| 139 | /* digital pad */ | 170 | /* digital pad */ |
| 140 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); | 171 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { |
| 141 | input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); | 172 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); |
| 173 | input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); | ||
| 174 | } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { | ||
| 175 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); | ||
| 176 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); | ||
| 177 | input_report_key(dev, BTN_0, data[2] & 0x01); // up | ||
| 178 | input_report_key(dev, BTN_1, data[2] & 0x02); // down | ||
| 179 | } | ||
| 142 | 180 | ||
| 143 | /* start/back buttons and stick press left/right */ | 181 | /* start/back buttons and stick press left/right */ |
| 144 | input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); | 182 | input_report_key(dev, BTN_START, data[2] & 0x10); |
| 145 | input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); | 183 | input_report_key(dev, BTN_BACK, data[2] & 0x20); |
| 146 | input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); | 184 | input_report_key(dev, BTN_THUMBL, data[2] & 0x40); |
| 147 | input_report_key(dev, BTN_THUMBR, data[2] >> 7); | 185 | input_report_key(dev, BTN_THUMBR, data[2] & 0x80); |
| 148 | 186 | ||
| 149 | /* "analog" buttons A, B, X, Y */ | 187 | /* "analog" buttons A, B, X, Y */ |
| 150 | input_report_key(dev, BTN_A, data[4]); | 188 | input_report_key(dev, BTN_A, data[4]); |
| @@ -206,6 +244,28 @@ static void xpad_close (struct input_dev *dev) | |||
| 206 | usb_kill_urb(xpad->irq_in); | 244 | usb_kill_urb(xpad->irq_in); |
| 207 | } | 245 | } |
| 208 | 246 | ||
| 247 | static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) | ||
| 248 | { | ||
| 249 | set_bit(abs, input_dev->absbit); | ||
| 250 | |||
| 251 | switch (abs) { | ||
| 252 | case ABS_X: | ||
| 253 | case ABS_Y: | ||
| 254 | case ABS_RX: | ||
| 255 | case ABS_RY: /* the two sticks */ | ||
| 256 | input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); | ||
| 257 | break; | ||
| 258 | case ABS_Z: | ||
| 259 | case ABS_RZ: /* the triggers */ | ||
| 260 | input_set_abs_params(input_dev, abs, 0, 255, 0, 0); | ||
| 261 | break; | ||
| 262 | case ABS_HAT0X: | ||
| 263 | case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */ | ||
| 264 | input_set_abs_params(input_dev, abs, -1, 1, 0, 0); | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 209 | static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) | 269 | static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) |
| 210 | { | 270 | { |
| 211 | struct usb_device *udev = interface_to_usbdev (intf); | 271 | 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 | |||
| 235 | goto fail2; | 295 | goto fail2; |
| 236 | 296 | ||
| 237 | xpad->udev = udev; | 297 | xpad->udev = udev; |
| 298 | xpad->dpad_mapping = xpad_device[i].dpad_mapping; | ||
| 299 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) | ||
| 300 | xpad->dpad_mapping = dpad_to_buttons; | ||
| 238 | xpad->dev = input_dev; | 301 | xpad->dev = input_dev; |
| 239 | usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); | 302 | usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); |
| 240 | strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); | 303 | 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 | |||
| 249 | 312 | ||
| 250 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 313 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
| 251 | 314 | ||
| 315 | /* set up buttons */ | ||
| 252 | for (i = 0; xpad_btn[i] >= 0; i++) | 316 | for (i = 0; xpad_btn[i] >= 0; i++) |
| 253 | set_bit(xpad_btn[i], input_dev->keybit); | 317 | set_bit(xpad_btn[i], input_dev->keybit); |
| 318 | if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) | ||
| 319 | for (i = 0; xpad_btn_pad[i] >= 0; i++) | ||
| 320 | set_bit(xpad_btn_pad[i], input_dev->keybit); | ||
| 254 | 321 | ||
| 255 | for (i = 0; xpad_abs[i] >= 0; i++) { | 322 | /* set up axes */ |
| 256 | 323 | for (i = 0; xpad_abs[i] >= 0; i++) | |
| 257 | signed short t = xpad_abs[i]; | 324 | xpad_set_up_abs(input_dev, xpad_abs[i]); |
| 258 | 325 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) | |
| 259 | set_bit(t, input_dev->absbit); | 326 | for (i = 0; xpad_abs_pad[i] >= 0; i++) |
| 260 | 327 | xpad_set_up_abs(input_dev, xpad_abs_pad[i]); | |
| 261 | switch (t) { | ||
| 262 | case ABS_X: | ||
| 263 | case ABS_Y: | ||
| 264 | case ABS_RX: | ||
| 265 | case ABS_RY: /* the two sticks */ | ||
| 266 | input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); | ||
| 267 | break; | ||
| 268 | case ABS_Z: | ||
| 269 | case ABS_RZ: /* the triggers */ | ||
| 270 | input_set_abs_params(input_dev, t, 0, 255, 0, 0); | ||
| 271 | break; | ||
| 272 | case ABS_HAT0X: | ||
| 273 | case ABS_HAT0Y: /* the d-pad */ | ||
| 274 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | 328 | ||
| 279 | ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; | 329 | ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; |
| 280 | usb_fill_int_urb(xpad->irq_in, udev, | 330 | usb_fill_int_urb(xpad->irq_in, udev, |
| @@ -305,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf) | |||
| 305 | usb_kill_urb(xpad->irq_in); | 355 | usb_kill_urb(xpad->irq_in); |
| 306 | input_unregister_device(xpad->dev); | 356 | input_unregister_device(xpad->dev); |
| 307 | usb_free_urb(xpad->irq_in); | 357 | usb_free_urb(xpad->irq_in); |
| 308 | usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); | 358 | usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, |
| 359 | xpad->idata, xpad->idata_dma); | ||
| 309 | kfree(xpad); | 360 | kfree(xpad); |
| 310 | } | 361 | } |
| 311 | } | 362 | } |
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c29658f69e2a..a74bf8617e7f 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig | |||
| @@ -223,6 +223,16 @@ config USB_LD | |||
| 223 | To compile this driver as a module, choose M here: the | 223 | To compile this driver as a module, choose M here: the |
| 224 | module will be called ldusb. | 224 | module will be called ldusb. |
| 225 | 225 | ||
| 226 | config USB_TRANCEVIBRATOR | ||
| 227 | tristate "PlayStation 2 Trance Vibrator driver support" | ||
| 228 | depends on USB | ||
| 229 | help | ||
| 230 | Say Y here if you want to connect a PlayStation 2 Trance Vibrator | ||
| 231 | device to your computer's USB port. | ||
| 232 | |||
| 233 | To compile this driver as a module, choose M here: the | ||
| 234 | module will be called trancevibrator. | ||
| 235 | |||
| 226 | config USB_TEST | 236 | config USB_TEST |
| 227 | tristate "USB testing driver (DEVELOPMENT)" | 237 | tristate "USB testing driver (DEVELOPMENT)" |
| 228 | depends on USB && USB_DEVICEFS && EXPERIMENTAL | 238 | depends on USB && USB_DEVICEFS && EXPERIMENTAL |
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2be70fa259bf..11dc59540cda 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile | |||
| @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o | |||
| 21 | obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o | 21 | obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o |
| 22 | obj-$(CONFIG_USB_RIO500) += rio500.o | 22 | obj-$(CONFIG_USB_RIO500) += rio500.o |
| 23 | obj-$(CONFIG_USB_TEST) += usbtest.o | 23 | obj-$(CONFIG_USB_TEST) += usbtest.o |
| 24 | obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o | ||
| 24 | obj-$(CONFIG_USB_USS720) += uss720.o | 25 | obj-$(CONFIG_USB_USS720) += uss720.o |
| 25 | 26 | ||
| 26 | obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ | 27 | obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ |
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index aecd633fe9f6..af2934e016a7 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c | |||
| @@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file) | |||
| 370 | retval = adu_release_internal(dev); | 370 | retval = adu_release_internal(dev); |
| 371 | 371 | ||
| 372 | exit: | 372 | exit: |
| 373 | up(&dev->sem); | 373 | if (dev) |
| 374 | up(&dev->sem); | ||
| 374 | dbg(2," %s : leave, return value %d", __FUNCTION__, retval); | 375 | dbg(2," %s : leave, return value %d", __FUNCTION__, retval); |
| 375 | return retval; | 376 | return retval; |
| 376 | } | 377 | } |
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 0eb26a26115b..9b591b8b9369 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c | |||
| @@ -513,8 +513,6 @@ static void ftdi_elan_respond_work(void *data) | |||
| 513 | ftdi->disconnected += 1; | 513 | ftdi->disconnected += 1; |
| 514 | } else if (retval == -ENODEV) { | 514 | } else if (retval == -ENODEV) { |
| 515 | ftdi->disconnected += 1; | 515 | ftdi->disconnected += 1; |
| 516 | } else if (retval == -ENODEV) { | ||
| 517 | ftdi->disconnected += 1; | ||
| 518 | } else if (retval == -EILSEQ) { | 516 | } else if (retval == -EILSEQ) { |
| 519 | ftdi->disconnected += 1; | 517 | ftdi->disconnected += 1; |
| 520 | } else { | 518 | } else { |
| @@ -1186,11 +1184,8 @@ static ssize_t ftdi_elan_write(struct file *file, | |||
| 1186 | int retval = 0; | 1184 | int retval = 0; |
| 1187 | struct urb *urb; | 1185 | struct urb *urb; |
| 1188 | char *buf; | 1186 | char *buf; |
| 1189 | char data[30 *3 + 4]; | 1187 | struct usb_ftdi *ftdi = file->private_data; |
| 1190 | char *d = data; | 1188 | |
| 1191 | const char __user *s = user_buffer; | ||
| 1192 | int m = (sizeof(data) - 1) / 3; | ||
| 1193 | struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; | ||
| 1194 | if (ftdi->disconnected > 0) { | 1189 | if (ftdi->disconnected > 0) { |
| 1195 | return -ENODEV; | 1190 | return -ENODEV; |
| 1196 | } | 1191 | } |
| @@ -1220,27 +1215,18 @@ static ssize_t ftdi_elan_write(struct file *file, | |||
| 1220 | if (retval) { | 1215 | if (retval) { |
| 1221 | dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" | 1216 | dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" |
| 1222 | "d\n", retval); | 1217 | "d\n", retval); |
| 1223 | goto error_4; | 1218 | goto error_3; |
| 1224 | } | 1219 | } |
| 1225 | usb_free_urb(urb); | 1220 | usb_free_urb(urb); |
| 1226 | exit:; | 1221 | |
| 1227 | if (count > m) { | 1222 | exit: |
| 1228 | int I = m - 1; | ||
| 1229 | while (I-- > 0) { | ||
| 1230 | d += sprintf(d, " %02X", 0x000000FF & *s++); | ||
| 1231 | } | ||
| 1232 | d += sprintf(d, " .."); | ||
| 1233 | } else { | ||
| 1234 | int I = count; | ||
| 1235 | while (I-- > 0) { | ||
| 1236 | d += sprintf(d, " %02X", 0x000000FF & *s++); | ||
| 1237 | } | ||
| 1238 | } | ||
| 1239 | return count; | 1223 | return count; |
| 1240 | error_4: error_3:usb_buffer_free(ftdi->udev, count, buf, | 1224 | error_3: |
| 1241 | urb->transfer_dma); | 1225 | usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); |
| 1242 | error_2:usb_free_urb(urb); | 1226 | error_2: |
| 1243 | error_1:return retval; | 1227 | usb_free_urb(urb); |
| 1228 | error_1: | ||
| 1229 | return retval; | ||
| 1244 | } | 1230 | } |
| 1245 | 1231 | ||
| 1246 | static struct file_operations ftdi_elan_fops = { | 1232 | static struct file_operations ftdi_elan_fops = { |
diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 33cd91d11eca..33cd91d11eca 100644 --- a/drivers/usb/input/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c | |||
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 054059632a21..454a186b64ad 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig | |||
| @@ -207,6 +207,14 @@ config USB_NET_PLUSB | |||
| 207 | Choose this option if you're using a host-to-host cable | 207 | Choose this option if you're using a host-to-host cable |
| 208 | with one of these chips. | 208 | with one of these chips. |
| 209 | 209 | ||
| 210 | config USB_NET_MCS7830 | ||
| 211 | tristate "MosChip MCS7830 based Ethernet adapters" | ||
| 212 | depends on USB_USBNET | ||
| 213 | help | ||
| 214 | Choose this option if you're using a 10/100 Ethernet USB2 | ||
| 215 | adapter based on the MosChip 7830 controller. This includes | ||
| 216 | adapters marketed under the DeLOCK brand. | ||
| 217 | |||
| 210 | config USB_NET_RNDIS_HOST | 218 | config USB_NET_RNDIS_HOST |
| 211 | tristate "Host for RNDIS devices (EXPERIMENTAL)" | 219 | tristate "Host for RNDIS devices (EXPERIMENTAL)" |
| 212 | depends on USB_USBNET && EXPERIMENTAL | 220 | depends on USB_USBNET && EXPERIMENTAL |
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 160f19dbdf12..7b51964de171 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile | |||
| @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o | |||
| 14 | obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o | 14 | obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o |
| 15 | obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o | 15 | obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o |
| 16 | obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o | 16 | obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o |
| 17 | obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o | ||
| 17 | obj-$(CONFIG_USB_USBNET) += usbnet.o | 18 | obj-$(CONFIG_USB_USBNET) += usbnet.o |
| 18 | 19 | ||
| 19 | ifeq ($(CONFIG_USB_DEBUG),y) | 20 | ifeq ($(CONFIG_USB_DEBUG),y) |
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index c73dd224aa76..881841e600de 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c | |||
| @@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | |||
| 569 | struct usbnet *dev = netdev_priv(netdev); | 569 | struct usbnet *dev = netdev_priv(netdev); |
| 570 | u16 res; | 570 | u16 res; |
| 571 | 571 | ||
| 572 | mutex_lock(&dev->phy_mutex); | ||
| 572 | asix_set_sw_mii(dev); | 573 | asix_set_sw_mii(dev); |
| 573 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | 574 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, |
| 574 | (__u16)loc, 2, (u16 *)&res); | 575 | (__u16)loc, 2, (u16 *)&res); |
| 575 | asix_set_hw_mii(dev); | 576 | asix_set_hw_mii(dev); |
| 577 | mutex_unlock(&dev->phy_mutex); | ||
| 576 | 578 | ||
| 577 | devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); | 579 | devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); |
| 578 | 580 | ||
| @@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | |||
| 586 | u16 res = cpu_to_le16(val); | 588 | u16 res = cpu_to_le16(val); |
| 587 | 589 | ||
| 588 | devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); | 590 | devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); |
| 591 | mutex_lock(&dev->phy_mutex); | ||
| 589 | asix_set_sw_mii(dev); | 592 | asix_set_sw_mii(dev); |
| 590 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, | 593 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
| 591 | (__u16)loc, 2, (u16 *)&res); | 594 | (__u16)loc, 2, (u16 *)&res); |
| 592 | asix_set_hw_mii(dev); | 595 | asix_set_hw_mii(dev); |
| 596 | mutex_unlock(&dev->phy_mutex); | ||
| 593 | } | 597 | } |
| 594 | 598 | ||
| 595 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | 599 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ |
| @@ -700,32 +704,6 @@ static void asix_get_drvinfo (struct net_device *net, | |||
| 700 | info->eedump_len = data->eeprom_len; | 704 | info->eedump_len = data->eeprom_len; |
| 701 | } | 705 | } |
| 702 | 706 | ||
| 703 | static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) | ||
| 704 | { | ||
| 705 | struct usbnet *dev = netdev_priv(net); | ||
| 706 | |||
| 707 | return mii_ethtool_gset(&dev->mii,cmd); | ||
| 708 | } | ||
| 709 | |||
| 710 | static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) | ||
| 711 | { | ||
| 712 | struct usbnet *dev = netdev_priv(net); | ||
| 713 | int res = mii_ethtool_sset(&dev->mii,cmd); | ||
| 714 | |||
| 715 | /* link speed/duplex might have changed */ | ||
| 716 | if (dev->driver_info->link_reset) | ||
| 717 | dev->driver_info->link_reset(dev); | ||
| 718 | |||
| 719 | return res; | ||
| 720 | } | ||
| 721 | |||
| 722 | static int asix_nway_reset(struct net_device *net) | ||
| 723 | { | ||
| 724 | struct usbnet *dev = netdev_priv(net); | ||
| 725 | |||
| 726 | return mii_nway_restart(&dev->mii); | ||
| 727 | } | ||
| 728 | |||
| 729 | static u32 asix_get_link(struct net_device *net) | 707 | static u32 asix_get_link(struct net_device *net) |
| 730 | { | 708 | { |
| 731 | struct usbnet *dev = netdev_priv(net); | 709 | struct usbnet *dev = netdev_priv(net); |
| @@ -746,15 +724,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | |||
| 746 | static struct ethtool_ops ax88172_ethtool_ops = { | 724 | static struct ethtool_ops ax88172_ethtool_ops = { |
| 747 | .get_drvinfo = asix_get_drvinfo, | 725 | .get_drvinfo = asix_get_drvinfo, |
| 748 | .get_link = asix_get_link, | 726 | .get_link = asix_get_link, |
| 749 | .nway_reset = asix_nway_reset, | ||
| 750 | .get_msglevel = usbnet_get_msglevel, | 727 | .get_msglevel = usbnet_get_msglevel, |
| 751 | .set_msglevel = usbnet_set_msglevel, | 728 | .set_msglevel = usbnet_set_msglevel, |
| 752 | .get_wol = asix_get_wol, | 729 | .get_wol = asix_get_wol, |
| 753 | .set_wol = asix_set_wol, | 730 | .set_wol = asix_set_wol, |
| 754 | .get_eeprom_len = asix_get_eeprom_len, | 731 | .get_eeprom_len = asix_get_eeprom_len, |
| 755 | .get_eeprom = asix_get_eeprom, | 732 | .get_eeprom = asix_get_eeprom, |
| 756 | .get_settings = asix_get_settings, | 733 | .get_settings = usbnet_get_settings, |
| 757 | .set_settings = asix_set_settings, | 734 | .set_settings = usbnet_set_settings, |
| 735 | .nway_reset = usbnet_nway_reset, | ||
| 758 | }; | 736 | }; |
| 759 | 737 | ||
| 760 | static void ax88172_set_multicast(struct net_device *net) | 738 | static void ax88172_set_multicast(struct net_device *net) |
| @@ -885,15 +863,15 @@ out1: | |||
| 885 | static struct ethtool_ops ax88772_ethtool_ops = { | 863 | static struct ethtool_ops ax88772_ethtool_ops = { |
| 886 | .get_drvinfo = asix_get_drvinfo, | 864 | .get_drvinfo = asix_get_drvinfo, |
| 887 | .get_link = asix_get_link, | 865 | .get_link = asix_get_link, |
| 888 | .nway_reset = asix_nway_reset, | ||
| 889 | .get_msglevel = usbnet_get_msglevel, | 866 | .get_msglevel = usbnet_get_msglevel, |
| 890 | .set_msglevel = usbnet_set_msglevel, | 867 | .set_msglevel = usbnet_set_msglevel, |
| 891 | .get_wol = asix_get_wol, | 868 | .get_wol = asix_get_wol, |
| 892 | .set_wol = asix_set_wol, | 869 | .set_wol = asix_set_wol, |
| 893 | .get_eeprom_len = asix_get_eeprom_len, | 870 | .get_eeprom_len = asix_get_eeprom_len, |
| 894 | .get_eeprom = asix_get_eeprom, | 871 | .get_eeprom = asix_get_eeprom, |
| 895 | .get_settings = asix_get_settings, | 872 | .get_settings = usbnet_get_settings, |
| 896 | .set_settings = asix_set_settings, | 873 | .set_settings = usbnet_set_settings, |
| 874 | .nway_reset = usbnet_nway_reset, | ||
| 897 | }; | 875 | }; |
| 898 | 876 | ||
| 899 | static int ax88772_link_reset(struct usbnet *dev) | 877 | static int ax88772_link_reset(struct usbnet *dev) |
| @@ -1046,15 +1024,15 @@ out1: | |||
| 1046 | static struct ethtool_ops ax88178_ethtool_ops = { | 1024 | static struct ethtool_ops ax88178_ethtool_ops = { |
| 1047 | .get_drvinfo = asix_get_drvinfo, | 1025 | .get_drvinfo = asix_get_drvinfo, |
| 1048 | .get_link = asix_get_link, | 1026 | .get_link = asix_get_link, |
| 1049 | .nway_reset = asix_nway_reset, | ||
| 1050 | .get_msglevel = usbnet_get_msglevel, | 1027 | .get_msglevel = usbnet_get_msglevel, |
| 1051 | .set_msglevel = usbnet_set_msglevel, | 1028 | .set_msglevel = usbnet_set_msglevel, |
| 1052 | .get_wol = asix_get_wol, | 1029 | .get_wol = asix_get_wol, |
| 1053 | .set_wol = asix_set_wol, | 1030 | .set_wol = asix_set_wol, |
| 1054 | .get_eeprom_len = asix_get_eeprom_len, | 1031 | .get_eeprom_len = asix_get_eeprom_len, |
| 1055 | .get_eeprom = asix_get_eeprom, | 1032 | .get_eeprom = asix_get_eeprom, |
| 1056 | .get_settings = asix_get_settings, | 1033 | .get_settings = usbnet_get_settings, |
| 1057 | .set_settings = asix_set_settings, | 1034 | .set_settings = usbnet_set_settings, |
| 1035 | .nway_reset = usbnet_nway_reset, | ||
| 1058 | }; | 1036 | }; |
| 1059 | 1037 | ||
| 1060 | static int marvell_phy_init(struct usbnet *dev) | 1038 | static int marvell_phy_init(struct usbnet *dev) |
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 82ce0358d9a3..f6971b88349d 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c | |||
| @@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = { | |||
| 498 | 498 | ||
| 499 | static int __init cdc_init(void) | 499 | static int __init cdc_init(void) |
| 500 | { | 500 | { |
| 501 | BUG_ON((sizeof(((struct usbnet *)0)->data) | 501 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) |
| 502 | < sizeof(struct cdc_state))); | 502 | < sizeof(struct cdc_state))); |
| 503 | 503 | ||
| 504 | return usb_register(&cdc_driver); | 504 | return usb_register(&cdc_driver); |
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 957d4ad316f9..7c906a43e497 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c | |||
| @@ -65,16 +65,6 @@ | |||
| 65 | 65 | ||
| 66 | #undef DEBUG | 66 | #undef DEBUG |
| 67 | 67 | ||
| 68 | #ifdef DEBUG | ||
| 69 | #define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) | ||
| 70 | #else | ||
| 71 | #define kaweth_dbg(format, arg...) do {} while (0) | ||
| 72 | #endif | ||
| 73 | #define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) | ||
| 74 | #define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) | ||
| 75 | #define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) | ||
| 76 | |||
| 77 | |||
| 78 | #include "kawethfw.h" | 68 | #include "kawethfw.h" |
| 79 | 69 | ||
| 80 | #define KAWETH_MTU 1514 | 70 | #define KAWETH_MTU 1514 |
| @@ -86,6 +76,9 @@ | |||
| 86 | 76 | ||
| 87 | #define KAWETH_STATUS_BROKEN 0x0000001 | 77 | #define KAWETH_STATUS_BROKEN 0x0000001 |
| 88 | #define KAWETH_STATUS_CLOSING 0x0000002 | 78 | #define KAWETH_STATUS_CLOSING 0x0000002 |
| 79 | #define KAWETH_STATUS_SUSPENDING 0x0000004 | ||
| 80 | |||
| 81 | #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) | ||
| 89 | 82 | ||
| 90 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 | 83 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 |
| 91 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 | 84 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 |
| @@ -112,6 +105,8 @@ | |||
| 112 | #define STATE_MASK 0x40 | 105 | #define STATE_MASK 0x40 |
| 113 | #define STATE_SHIFT 5 | 106 | #define STATE_SHIFT 5 |
| 114 | 107 | ||
| 108 | #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) | ||
| 109 | |||
| 115 | 110 | ||
| 116 | 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>"); | 111 | 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>"); |
| 117 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); | 112 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); |
| @@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |||
| 128 | unsigned int pipe, | 123 | unsigned int pipe, |
| 129 | struct usb_ctrlrequest *cmd, void *data, | 124 | struct usb_ctrlrequest *cmd, void *data, |
| 130 | int len, int timeout); | 125 | int len, int timeout); |
| 126 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); | ||
| 127 | static int kaweth_resume(struct usb_interface *intf); | ||
| 131 | 128 | ||
| 132 | /**************************************************************** | 129 | /**************************************************************** |
| 133 | * usb_device_id | 130 | * usb_device_id |
| @@ -179,6 +176,8 @@ static struct usb_driver kaweth_driver = { | |||
| 179 | .name = driver_name, | 176 | .name = driver_name, |
| 180 | .probe = kaweth_probe, | 177 | .probe = kaweth_probe, |
| 181 | .disconnect = kaweth_disconnect, | 178 | .disconnect = kaweth_disconnect, |
| 179 | .suspend = kaweth_suspend, | ||
| 180 | .resume = kaweth_resume, | ||
| 182 | .id_table = usb_klsi_table, | 181 | .id_table = usb_klsi_table, |
| 183 | }; | 182 | }; |
| 184 | 183 | ||
| @@ -222,6 +221,7 @@ struct kaweth_device | |||
| 222 | int suspend_lowmem_rx; | 221 | int suspend_lowmem_rx; |
| 223 | int suspend_lowmem_ctrl; | 222 | int suspend_lowmem_ctrl; |
| 224 | int linkstate; | 223 | int linkstate; |
| 224 | int opened; | ||
| 225 | struct work_struct lowmem_work; | 225 | struct work_struct lowmem_work; |
| 226 | 226 | ||
| 227 | struct usb_device *dev; | 227 | struct usb_device *dev; |
| @@ -265,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth, | |||
| 265 | { | 265 | { |
| 266 | struct usb_ctrlrequest *dr; | 266 | struct usb_ctrlrequest *dr; |
| 267 | 267 | ||
| 268 | kaweth_dbg("kaweth_control()"); | 268 | dbg("kaweth_control()"); |
| 269 | 269 | ||
| 270 | if(in_interrupt()) { | 270 | if(in_interrupt()) { |
| 271 | kaweth_dbg("in_interrupt()"); | 271 | dbg("in_interrupt()"); |
| 272 | return -EBUSY; | 272 | return -EBUSY; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | 275 | dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); |
| 276 | 276 | ||
| 277 | if (!dr) { | 277 | if (!dr) { |
| 278 | kaweth_dbg("kmalloc() failed"); | 278 | dbg("kmalloc() failed"); |
| 279 | return -ENOMEM; | 279 | return -ENOMEM; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| @@ -300,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth) | |||
| 300 | { | 300 | { |
| 301 | int retval; | 301 | int retval; |
| 302 | 302 | ||
| 303 | kaweth_dbg("Reading kaweth configuration"); | 303 | dbg("Reading kaweth configuration"); |
| 304 | 304 | ||
| 305 | retval = kaweth_control(kaweth, | 305 | retval = kaweth_control(kaweth, |
| 306 | usb_rcvctrlpipe(kaweth->dev, 0), | 306 | usb_rcvctrlpipe(kaweth->dev, 0), |
| @@ -322,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) | |||
| 322 | { | 322 | { |
| 323 | int retval; | 323 | int retval; |
| 324 | 324 | ||
| 325 | kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); | 325 | dbg("Setting URB size to %d", (unsigned)urb_size); |
| 326 | 326 | ||
| 327 | retval = kaweth_control(kaweth, | 327 | retval = kaweth_control(kaweth, |
| 328 | usb_sndctrlpipe(kaweth->dev, 0), | 328 | usb_sndctrlpipe(kaweth->dev, 0), |
| @@ -344,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) | |||
| 344 | { | 344 | { |
| 345 | int retval; | 345 | int retval; |
| 346 | 346 | ||
| 347 | kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); | 347 | dbg("Set SOFS wait to %d", (unsigned)sofs_wait); |
| 348 | 348 | ||
| 349 | retval = kaweth_control(kaweth, | 349 | retval = kaweth_control(kaweth, |
| 350 | usb_sndctrlpipe(kaweth->dev, 0), | 350 | usb_sndctrlpipe(kaweth->dev, 0), |
| @@ -367,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth, | |||
| 367 | { | 367 | { |
| 368 | int retval; | 368 | int retval; |
| 369 | 369 | ||
| 370 | kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); | 370 | dbg("Set receive filter to %d", (unsigned)receive_filter); |
| 371 | 371 | ||
| 372 | retval = kaweth_control(kaweth, | 372 | retval = kaweth_control(kaweth, |
| 373 | usb_sndctrlpipe(kaweth->dev, 0), | 373 | usb_sndctrlpipe(kaweth->dev, 0), |
| @@ -392,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, | |||
| 392 | __u8 type) | 392 | __u8 type) |
| 393 | { | 393 | { |
| 394 | if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { | 394 | if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { |
| 395 | kaweth_err("Firmware too big: %d", data_len); | 395 | err("Firmware too big: %d", data_len); |
| 396 | return -ENOSPC; | 396 | return -ENOSPC; |
| 397 | } | 397 | } |
| 398 | 398 | ||
| @@ -403,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, | |||
| 403 | kaweth->firmware_buf[4] = type; | 403 | kaweth->firmware_buf[4] = type; |
| 404 | kaweth->firmware_buf[5] = interrupt; | 404 | kaweth->firmware_buf[5] = interrupt; |
| 405 | 405 | ||
| 406 | kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3], | 406 | dbg("High: %i, Low:%i", kaweth->firmware_buf[3], |
| 407 | kaweth->firmware_buf[2]); | 407 | kaweth->firmware_buf[2]); |
| 408 | 408 | ||
| 409 | kaweth_dbg("Downloading firmware at %p to kaweth device at %p", | 409 | dbg("Downloading firmware at %p to kaweth device at %p", |
| 410 | data, | 410 | data, |
| 411 | kaweth); | 411 | kaweth); |
| 412 | kaweth_dbg("Firmware length: %d", data_len); | 412 | dbg("Firmware length: %d", data_len); |
| 413 | 413 | ||
| 414 | return kaweth_control(kaweth, | 414 | return kaweth_control(kaweth, |
| 415 | usb_sndctrlpipe(kaweth->dev, 0), | 415 | usb_sndctrlpipe(kaweth->dev, 0), |
| @@ -437,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth, | |||
| 437 | kaweth->firmware_buf[6] = 0x00; | 437 | kaweth->firmware_buf[6] = 0x00; |
| 438 | kaweth->firmware_buf[7] = 0x00; | 438 | kaweth->firmware_buf[7] = 0x00; |
| 439 | 439 | ||
| 440 | kaweth_dbg("Triggering firmware"); | 440 | dbg("Triggering firmware"); |
| 441 | 441 | ||
| 442 | return kaweth_control(kaweth, | 442 | return kaweth_control(kaweth, |
| 443 | usb_sndctrlpipe(kaweth->dev, 0), | 443 | usb_sndctrlpipe(kaweth->dev, 0), |
| @@ -457,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) | |||
| 457 | { | 457 | { |
| 458 | int result; | 458 | int result; |
| 459 | 459 | ||
| 460 | kaweth_dbg("kaweth_reset(%p)", kaweth); | 460 | dbg("kaweth_reset(%p)", kaweth); |
| 461 | result = kaweth_control(kaweth, | 461 | result = kaweth_control(kaweth, |
| 462 | usb_sndctrlpipe(kaweth->dev, 0), | 462 | usb_sndctrlpipe(kaweth->dev, 0), |
| 463 | USB_REQ_SET_CONFIGURATION, | 463 | USB_REQ_SET_CONFIGURATION, |
| @@ -470,7 +470,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) | |||
| 470 | 470 | ||
| 471 | mdelay(10); | 471 | mdelay(10); |
| 472 | 472 | ||
| 473 | kaweth_dbg("kaweth_reset() returns %d.",result); | 473 | dbg("kaweth_reset() returns %d.",result); |
| 474 | 474 | ||
| 475 | return result; | 475 | return result; |
| 476 | } | 476 | } |
| @@ -534,7 +534,7 @@ static void kaweth_resubmit_tl(void *d) | |||
| 534 | { | 534 | { |
| 535 | struct kaweth_device *kaweth = (struct kaweth_device *)d; | 535 | struct kaweth_device *kaweth = (struct kaweth_device *)d; |
| 536 | 536 | ||
| 537 | if (kaweth->status | KAWETH_STATUS_CLOSING) | 537 | if (IS_BLOCKED(kaweth->status)) |
| 538 | return; | 538 | return; |
| 539 | 539 | ||
| 540 | if (kaweth->suspend_lowmem_rx) | 540 | if (kaweth->suspend_lowmem_rx) |
| @@ -568,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, | |||
| 568 | kaweth->suspend_lowmem_rx = 1; | 568 | kaweth->suspend_lowmem_rx = 1; |
| 569 | schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | 569 | schedule_delayed_work(&kaweth->lowmem_work, HZ/4); |
| 570 | } | 570 | } |
| 571 | kaweth_err("resubmitting rx_urb %d failed", result); | 571 | err("resubmitting rx_urb %d failed", result); |
| 572 | } else { | 572 | } else { |
| 573 | kaweth->suspend_lowmem_rx = 0; | 573 | kaweth->suspend_lowmem_rx = 0; |
| 574 | } | 574 | } |
| @@ -601,11 +601,15 @@ static void kaweth_usb_receive(struct urb *urb) | |||
| 601 | return; | 601 | return; |
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | if (kaweth->status & KAWETH_STATUS_CLOSING) | 604 | spin_lock(&kaweth->device_lock); |
| 605 | if (IS_BLOCKED(kaweth->status)) { | ||
| 606 | spin_unlock(&kaweth->device_lock); | ||
| 605 | return; | 607 | return; |
| 608 | } | ||
| 609 | spin_unlock(&kaweth->device_lock); | ||
| 606 | 610 | ||
| 607 | if(urb->status && urb->status != -EREMOTEIO && count != 1) { | 611 | if(urb->status && urb->status != -EREMOTEIO && count != 1) { |
| 608 | kaweth_err("%s RX status: %d count: %d packet_len: %d", | 612 | err("%s RX status: %d count: %d packet_len: %d", |
| 609 | net->name, | 613 | net->name, |
| 610 | urb->status, | 614 | urb->status, |
| 611 | count, | 615 | count, |
| @@ -616,9 +620,9 @@ static void kaweth_usb_receive(struct urb *urb) | |||
| 616 | 620 | ||
| 617 | if(kaweth->net && (count > 2)) { | 621 | if(kaweth->net && (count > 2)) { |
| 618 | if(pkt_len > (count - 2)) { | 622 | if(pkt_len > (count - 2)) { |
| 619 | kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); | 623 | err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); |
| 620 | kaweth_err("Packet len & 2047: %x", pkt_len & 2047); | 624 | err("Packet len & 2047: %x", pkt_len & 2047); |
| 621 | kaweth_err("Count 2: %x", count2); | 625 | err("Count 2: %x", count2); |
| 622 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | 626 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); |
| 623 | return; | 627 | return; |
| 624 | } | 628 | } |
| @@ -655,7 +659,7 @@ static int kaweth_open(struct net_device *net) | |||
| 655 | struct kaweth_device *kaweth = netdev_priv(net); | 659 | struct kaweth_device *kaweth = netdev_priv(net); |
| 656 | int res; | 660 | int res; |
| 657 | 661 | ||
| 658 | kaweth_dbg("Opening network device."); | 662 | dbg("Opening network device."); |
| 659 | 663 | ||
| 660 | res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); | 664 | res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); |
| 661 | if (res) | 665 | if (res) |
| @@ -678,6 +682,7 @@ static int kaweth_open(struct net_device *net) | |||
| 678 | usb_kill_urb(kaweth->rx_urb); | 682 | usb_kill_urb(kaweth->rx_urb); |
| 679 | return -EIO; | 683 | return -EIO; |
| 680 | } | 684 | } |
| 685 | kaweth->opened = 1; | ||
| 681 | 686 | ||
| 682 | netif_start_queue(net); | 687 | netif_start_queue(net); |
| 683 | 688 | ||
| @@ -688,14 +693,8 @@ static int kaweth_open(struct net_device *net) | |||
| 688 | /**************************************************************** | 693 | /**************************************************************** |
| 689 | * kaweth_close | 694 | * kaweth_close |
| 690 | ****************************************************************/ | 695 | ****************************************************************/ |
| 691 | static int kaweth_close(struct net_device *net) | 696 | static void kaweth_kill_urbs(struct kaweth_device *kaweth) |
| 692 | { | 697 | { |
| 693 | struct kaweth_device *kaweth = netdev_priv(net); | ||
| 694 | |||
| 695 | netif_stop_queue(net); | ||
| 696 | |||
| 697 | kaweth->status |= KAWETH_STATUS_CLOSING; | ||
| 698 | |||
| 699 | usb_kill_urb(kaweth->irq_urb); | 698 | usb_kill_urb(kaweth->irq_urb); |
| 700 | usb_kill_urb(kaweth->rx_urb); | 699 | usb_kill_urb(kaweth->rx_urb); |
| 701 | usb_kill_urb(kaweth->tx_urb); | 700 | usb_kill_urb(kaweth->tx_urb); |
| @@ -706,6 +705,21 @@ static int kaweth_close(struct net_device *net) | |||
| 706 | we hit them again */ | 705 | we hit them again */ |
| 707 | usb_kill_urb(kaweth->irq_urb); | 706 | usb_kill_urb(kaweth->irq_urb); |
| 708 | usb_kill_urb(kaweth->rx_urb); | 707 | usb_kill_urb(kaweth->rx_urb); |
| 708 | } | ||
| 709 | |||
| 710 | /**************************************************************** | ||
| 711 | * kaweth_close | ||
| 712 | ****************************************************************/ | ||
| 713 | static int kaweth_close(struct net_device *net) | ||
| 714 | { | ||
| 715 | struct kaweth_device *kaweth = netdev_priv(net); | ||
| 716 | |||
| 717 | netif_stop_queue(net); | ||
| 718 | kaweth->opened = 0; | ||
| 719 | |||
| 720 | kaweth->status |= KAWETH_STATUS_CLOSING; | ||
| 721 | |||
| 722 | kaweth_kill_urbs(kaweth); | ||
| 709 | 723 | ||
| 710 | kaweth->status &= ~KAWETH_STATUS_CLOSING; | 724 | kaweth->status &= ~KAWETH_STATUS_CLOSING; |
| 711 | 725 | ||
| @@ -732,7 +746,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb) | |||
| 732 | 746 | ||
| 733 | if (unlikely(urb->status != 0)) | 747 | if (unlikely(urb->status != 0)) |
| 734 | if (urb->status != -ENOENT) | 748 | if (urb->status != -ENOENT) |
| 735 | kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); | 749 | dbg("%s: TX status %d.", kaweth->net->name, urb->status); |
| 736 | 750 | ||
| 737 | netif_wake_queue(kaweth->net); | 751 | netif_wake_queue(kaweth->net); |
| 738 | dev_kfree_skb_irq(skb); | 752 | dev_kfree_skb_irq(skb); |
| @@ -752,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 752 | 766 | ||
| 753 | kaweth_async_set_rx_mode(kaweth); | 767 | kaweth_async_set_rx_mode(kaweth); |
| 754 | netif_stop_queue(net); | 768 | netif_stop_queue(net); |
| 769 | if (IS_BLOCKED(kaweth->status)) { | ||
| 770 | goto skip; | ||
| 771 | } | ||
| 755 | 772 | ||
| 756 | /* We now decide whether we can put our special header into the sk_buff */ | 773 | /* We now decide whether we can put our special header into the sk_buff */ |
| 757 | if (skb_cloned(skb) || skb_headroom(skb) < 2) { | 774 | 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) | |||
| 783 | 800 | ||
| 784 | if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) | 801 | if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) |
| 785 | { | 802 | { |
| 786 | kaweth_warn("kaweth failed tx_urb %d", res); | 803 | warn("kaweth failed tx_urb %d", res); |
| 804 | skip: | ||
| 787 | kaweth->stats.tx_errors++; | 805 | kaweth->stats.tx_errors++; |
| 788 | 806 | ||
| 789 | netif_start_queue(net); | 807 | netif_start_queue(net); |
| @@ -812,7 +830,7 @@ static void kaweth_set_rx_mode(struct net_device *net) | |||
| 812 | KAWETH_PACKET_FILTER_BROADCAST | | 830 | KAWETH_PACKET_FILTER_BROADCAST | |
| 813 | KAWETH_PACKET_FILTER_MULTICAST; | 831 | KAWETH_PACKET_FILTER_MULTICAST; |
| 814 | 832 | ||
| 815 | kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); | 833 | dbg("Setting Rx mode to %d", packet_filter_bitmap); |
| 816 | 834 | ||
| 817 | netif_stop_queue(net); | 835 | netif_stop_queue(net); |
| 818 | 836 | ||
| @@ -850,10 +868,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) | |||
| 850 | KAWETH_CONTROL_TIMEOUT); | 868 | KAWETH_CONTROL_TIMEOUT); |
| 851 | 869 | ||
| 852 | if(result < 0) { | 870 | if(result < 0) { |
| 853 | kaweth_err("Failed to set Rx mode: %d", result); | 871 | err("Failed to set Rx mode: %d", result); |
| 854 | } | 872 | } |
| 855 | else { | 873 | else { |
| 856 | kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); | 874 | dbg("Set Rx mode to %d", packet_filter_bitmap); |
| 857 | } | 875 | } |
| 858 | } | 876 | } |
| 859 | } | 877 | } |
| @@ -874,7 +892,7 @@ static void kaweth_tx_timeout(struct net_device *net) | |||
| 874 | { | 892 | { |
| 875 | struct kaweth_device *kaweth = netdev_priv(net); | 893 | struct kaweth_device *kaweth = netdev_priv(net); |
| 876 | 894 | ||
| 877 | kaweth_warn("%s: Tx timed out. Resetting.", net->name); | 895 | warn("%s: Tx timed out. Resetting.", net->name); |
| 878 | kaweth->stats.tx_errors++; | 896 | kaweth->stats.tx_errors++; |
| 879 | net->trans_start = jiffies; | 897 | net->trans_start = jiffies; |
| 880 | 898 | ||
| @@ -882,6 +900,42 @@ static void kaweth_tx_timeout(struct net_device *net) | |||
| 882 | } | 900 | } |
| 883 | 901 | ||
| 884 | /**************************************************************** | 902 | /**************************************************************** |
| 903 | * kaweth_suspend | ||
| 904 | ****************************************************************/ | ||
| 905 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 906 | { | ||
| 907 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
| 908 | unsigned long flags; | ||
| 909 | |||
| 910 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
| 911 | kaweth->status |= KAWETH_STATUS_SUSPENDING; | ||
| 912 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
| 913 | |||
| 914 | kaweth_kill_urbs(kaweth); | ||
| 915 | return 0; | ||
| 916 | } | ||
| 917 | |||
| 918 | /**************************************************************** | ||
| 919 | * kaweth_resume | ||
| 920 | ****************************************************************/ | ||
| 921 | static int kaweth_resume(struct usb_interface *intf) | ||
| 922 | { | ||
| 923 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | ||
| 924 | unsigned long flags; | ||
| 925 | |||
| 926 | spin_lock_irqsave(&kaweth->device_lock, flags); | ||
| 927 | kaweth->status &= ~KAWETH_STATUS_SUSPENDING; | ||
| 928 | spin_unlock_irqrestore(&kaweth->device_lock, flags); | ||
| 929 | |||
| 930 | if (!kaweth->opened) | ||
| 931 | return 0; | ||
| 932 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | ||
| 933 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | ||
| 934 | |||
| 935 | return 0; | ||
| 936 | } | ||
| 937 | |||
| 938 | /**************************************************************** | ||
| 885 | * kaweth_probe | 939 | * kaweth_probe |
| 886 | ****************************************************************/ | 940 | ****************************************************************/ |
| 887 | static int kaweth_probe( | 941 | static int kaweth_probe( |
| @@ -895,15 +949,15 @@ static int kaweth_probe( | |||
| 895 | const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 949 | const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
| 896 | int result = 0; | 950 | int result = 0; |
| 897 | 951 | ||
| 898 | kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", | 952 | dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", |
| 899 | dev->devnum, | 953 | dev->devnum, |
| 900 | le16_to_cpu(dev->descriptor.idVendor), | 954 | le16_to_cpu(dev->descriptor.idVendor), |
| 901 | le16_to_cpu(dev->descriptor.idProduct), | 955 | le16_to_cpu(dev->descriptor.idProduct), |
| 902 | le16_to_cpu(dev->descriptor.bcdDevice)); | 956 | le16_to_cpu(dev->descriptor.bcdDevice)); |
| 903 | 957 | ||
| 904 | kaweth_dbg("Device at %p", dev); | 958 | dbg("Device at %p", dev); |
| 905 | 959 | ||
| 906 | kaweth_dbg("Descriptor length: %x type: %x", | 960 | dbg("Descriptor length: %x type: %x", |
| 907 | (int)dev->descriptor.bLength, | 961 | (int)dev->descriptor.bLength, |
| 908 | (int)dev->descriptor.bDescriptorType); | 962 | (int)dev->descriptor.bDescriptorType); |
| 909 | 963 | ||
| @@ -918,7 +972,7 @@ static int kaweth_probe( | |||
| 918 | spin_lock_init(&kaweth->device_lock); | 972 | spin_lock_init(&kaweth->device_lock); |
| 919 | init_waitqueue_head(&kaweth->term_wait); | 973 | init_waitqueue_head(&kaweth->term_wait); |
| 920 | 974 | ||
| 921 | kaweth_dbg("Resetting."); | 975 | dbg("Resetting."); |
| 922 | 976 | ||
| 923 | kaweth_reset(kaweth); | 977 | kaweth_reset(kaweth); |
| 924 | 978 | ||
| @@ -928,17 +982,17 @@ static int kaweth_probe( | |||
| 928 | */ | 982 | */ |
| 929 | 983 | ||
| 930 | if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { | 984 | if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { |
| 931 | kaweth_info("Firmware present in device."); | 985 | info("Firmware present in device."); |
| 932 | } else { | 986 | } else { |
| 933 | /* Download the firmware */ | 987 | /* Download the firmware */ |
| 934 | kaweth_info("Downloading firmware..."); | 988 | info("Downloading firmware..."); |
| 935 | kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); | 989 | kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); |
| 936 | if ((result = kaweth_download_firmware(kaweth, | 990 | if ((result = kaweth_download_firmware(kaweth, |
| 937 | kaweth_new_code, | 991 | kaweth_new_code, |
| 938 | len_kaweth_new_code, | 992 | len_kaweth_new_code, |
| 939 | 100, | 993 | 100, |
| 940 | 2)) < 0) { | 994 | 2)) < 0) { |
| 941 | kaweth_err("Error downloading firmware (%d)", result); | 995 | err("Error downloading firmware (%d)", result); |
| 942 | goto err_fw; | 996 | goto err_fw; |
| 943 | } | 997 | } |
| 944 | 998 | ||
| @@ -947,7 +1001,7 @@ static int kaweth_probe( | |||
| 947 | len_kaweth_new_code_fix, | 1001 | len_kaweth_new_code_fix, |
| 948 | 100, | 1002 | 100, |
| 949 | 3)) < 0) { | 1003 | 3)) < 0) { |
| 950 | kaweth_err("Error downloading firmware fix (%d)", result); | 1004 | err("Error downloading firmware fix (%d)", result); |
| 951 | goto err_fw; | 1005 | goto err_fw; |
| 952 | } | 1006 | } |
| 953 | 1007 | ||
| @@ -956,7 +1010,7 @@ static int kaweth_probe( | |||
| 956 | len_kaweth_trigger_code, | 1010 | len_kaweth_trigger_code, |
| 957 | 126, | 1011 | 126, |
| 958 | 2)) < 0) { | 1012 | 2)) < 0) { |
| 959 | kaweth_err("Error downloading trigger code (%d)", result); | 1013 | err("Error downloading trigger code (%d)", result); |
| 960 | goto err_fw; | 1014 | goto err_fw; |
| 961 | 1015 | ||
| 962 | } | 1016 | } |
| @@ -966,18 +1020,18 @@ static int kaweth_probe( | |||
| 966 | len_kaweth_trigger_code_fix, | 1020 | len_kaweth_trigger_code_fix, |
| 967 | 126, | 1021 | 126, |
| 968 | 3)) < 0) { | 1022 | 3)) < 0) { |
| 969 | kaweth_err("Error downloading trigger code fix (%d)", result); | 1023 | err("Error downloading trigger code fix (%d)", result); |
| 970 | goto err_fw; | 1024 | goto err_fw; |
| 971 | } | 1025 | } |
| 972 | 1026 | ||
| 973 | 1027 | ||
| 974 | if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { | 1028 | if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { |
| 975 | kaweth_err("Error triggering firmware (%d)", result); | 1029 | err("Error triggering firmware (%d)", result); |
| 976 | goto err_fw; | 1030 | goto err_fw; |
| 977 | } | 1031 | } |
| 978 | 1032 | ||
| 979 | /* Device will now disappear for a moment... */ | 1033 | /* Device will now disappear for a moment... */ |
| 980 | kaweth_info("Firmware loaded. I'll be back..."); | 1034 | info("Firmware loaded. I'll be back..."); |
| 981 | err_fw: | 1035 | err_fw: |
| 982 | free_page((unsigned long)kaweth->firmware_buf); | 1036 | free_page((unsigned long)kaweth->firmware_buf); |
| 983 | free_netdev(netdev); | 1037 | free_netdev(netdev); |
| @@ -987,14 +1041,14 @@ err_fw: | |||
| 987 | result = kaweth_read_configuration(kaweth); | 1041 | result = kaweth_read_configuration(kaweth); |
| 988 | 1042 | ||
| 989 | if(result < 0) { | 1043 | if(result < 0) { |
| 990 | kaweth_err("Error reading configuration (%d), no net device created", result); | 1044 | err("Error reading configuration (%d), no net device created", result); |
| 991 | goto err_free_netdev; | 1045 | goto err_free_netdev; |
| 992 | } | 1046 | } |
| 993 | 1047 | ||
| 994 | kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); | 1048 | info("Statistics collection: %x", kaweth->configuration.statistics_mask); |
| 995 | kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); | 1049 | info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); |
| 996 | kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); | 1050 | info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); |
| 997 | kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", | 1051 | info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", |
| 998 | (int)kaweth->configuration.hw_addr[0], | 1052 | (int)kaweth->configuration.hw_addr[0], |
| 999 | (int)kaweth->configuration.hw_addr[1], | 1053 | (int)kaweth->configuration.hw_addr[1], |
| 1000 | (int)kaweth->configuration.hw_addr[2], | 1054 | (int)kaweth->configuration.hw_addr[2], |
| @@ -1005,17 +1059,17 @@ err_fw: | |||
| 1005 | if(!memcmp(&kaweth->configuration.hw_addr, | 1059 | if(!memcmp(&kaweth->configuration.hw_addr, |
| 1006 | &bcast_addr, | 1060 | &bcast_addr, |
| 1007 | sizeof(bcast_addr))) { | 1061 | sizeof(bcast_addr))) { |
| 1008 | kaweth_err("Firmware not functioning properly, no net device created"); | 1062 | err("Firmware not functioning properly, no net device created"); |
| 1009 | goto err_free_netdev; | 1063 | goto err_free_netdev; |
| 1010 | } | 1064 | } |
| 1011 | 1065 | ||
| 1012 | if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { | 1066 | if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { |
| 1013 | kaweth_dbg("Error setting URB size"); | 1067 | dbg("Error setting URB size"); |
| 1014 | goto err_free_netdev; | 1068 | goto err_free_netdev; |
| 1015 | } | 1069 | } |
| 1016 | 1070 | ||
| 1017 | if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { | 1071 | if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { |
| 1018 | kaweth_err("Error setting SOFS wait"); | 1072 | err("Error setting SOFS wait"); |
| 1019 | goto err_free_netdev; | 1073 | goto err_free_netdev; |
| 1020 | } | 1074 | } |
| 1021 | 1075 | ||
| @@ -1025,11 +1079,11 @@ err_fw: | |||
| 1025 | KAWETH_PACKET_FILTER_MULTICAST); | 1079 | KAWETH_PACKET_FILTER_MULTICAST); |
| 1026 | 1080 | ||
| 1027 | if(result < 0) { | 1081 | if(result < 0) { |
| 1028 | kaweth_err("Error setting receive filter"); | 1082 | err("Error setting receive filter"); |
| 1029 | goto err_free_netdev; | 1083 | goto err_free_netdev; |
| 1030 | } | 1084 | } |
| 1031 | 1085 | ||
| 1032 | kaweth_dbg("Initializing net device."); | 1086 | dbg("Initializing net device."); |
| 1033 | 1087 | ||
| 1034 | kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | 1088 | kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 1035 | if (!kaweth->tx_urb) | 1089 | if (!kaweth->tx_urb) |
| @@ -1086,13 +1140,13 @@ err_fw: | |||
| 1086 | 1140 | ||
| 1087 | SET_NETDEV_DEV(netdev, &intf->dev); | 1141 | SET_NETDEV_DEV(netdev, &intf->dev); |
| 1088 | if (register_netdev(netdev) != 0) { | 1142 | if (register_netdev(netdev) != 0) { |
| 1089 | kaweth_err("Error registering netdev."); | 1143 | err("Error registering netdev."); |
| 1090 | goto err_intfdata; | 1144 | goto err_intfdata; |
| 1091 | } | 1145 | } |
| 1092 | 1146 | ||
| 1093 | kaweth_info("kaweth interface created at %s", kaweth->net->name); | 1147 | info("kaweth interface created at %s", kaweth->net->name); |
| 1094 | 1148 | ||
| 1095 | kaweth_dbg("Kaweth probe returning."); | 1149 | dbg("Kaweth probe returning."); |
| 1096 | 1150 | ||
| 1097 | return 0; | 1151 | return 0; |
| 1098 | 1152 | ||
| @@ -1121,16 +1175,16 @@ static void kaweth_disconnect(struct usb_interface *intf) | |||
| 1121 | struct kaweth_device *kaweth = usb_get_intfdata(intf); | 1175 | struct kaweth_device *kaweth = usb_get_intfdata(intf); |
| 1122 | struct net_device *netdev; | 1176 | struct net_device *netdev; |
| 1123 | 1177 | ||
| 1124 | kaweth_info("Unregistering"); | 1178 | info("Unregistering"); |
| 1125 | 1179 | ||
| 1126 | usb_set_intfdata(intf, NULL); | 1180 | usb_set_intfdata(intf, NULL); |
| 1127 | if (!kaweth) { | 1181 | if (!kaweth) { |
| 1128 | kaweth_warn("unregistering non-existant device"); | 1182 | warn("unregistering non-existant device"); |
| 1129 | return; | 1183 | return; |
| 1130 | } | 1184 | } |
| 1131 | netdev = kaweth->net; | 1185 | netdev = kaweth->net; |
| 1132 | 1186 | ||
| 1133 | kaweth_dbg("Unregistering net device"); | 1187 | dbg("Unregistering net device"); |
| 1134 | unregister_netdev(netdev); | 1188 | unregister_netdev(netdev); |
| 1135 | 1189 | ||
| 1136 | usb_free_urb(kaweth->rx_urb); | 1190 | usb_free_urb(kaweth->rx_urb); |
| @@ -1185,7 +1239,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) | |||
| 1185 | 1239 | ||
| 1186 | if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { | 1240 | if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { |
| 1187 | // timeout | 1241 | // timeout |
| 1188 | kaweth_warn("usb_control/bulk_msg: timeout"); | 1242 | warn("usb_control/bulk_msg: timeout"); |
| 1189 | usb_kill_urb(urb); // remove urb safely | 1243 | usb_kill_urb(urb); // remove urb safely |
| 1190 | status = -ETIMEDOUT; | 1244 | status = -ETIMEDOUT; |
| 1191 | } | 1245 | } |
| @@ -1234,7 +1288,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |||
| 1234 | ****************************************************************/ | 1288 | ****************************************************************/ |
| 1235 | static int __init kaweth_init(void) | 1289 | static int __init kaweth_init(void) |
| 1236 | { | 1290 | { |
| 1237 | kaweth_dbg("Driver loading"); | 1291 | dbg("Driver loading"); |
| 1238 | return usb_register(&kaweth_driver); | 1292 | return usb_register(&kaweth_driver); |
| 1239 | } | 1293 | } |
| 1240 | 1294 | ||
diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c new file mode 100644 index 000000000000..6240b978fe3d --- /dev/null +++ b/drivers/usb/net/mcs7830.c | |||
| @@ -0,0 +1,534 @@ | |||
| 1 | /* | ||
| 2 | * MosChips MCS7830 based USB 2.0 Ethernet Devices | ||
| 3 | * | ||
| 4 | * based on usbnet.c, asix.c and the vendor provided mcs7830 driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> | ||
| 7 | * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> | ||
| 8 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
| 9 | * Copyright (c) 2002-2003 TiVo Inc. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/crc32.h> | ||
| 27 | #include <linux/etherdevice.h> | ||
| 28 | #include <linux/ethtool.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/mii.h> | ||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/netdevice.h> | ||
| 33 | #include <linux/usb.h> | ||
| 34 | |||
| 35 | #include "usbnet.h" | ||
| 36 | |||
| 37 | /* requests */ | ||
| 38 | #define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ | ||
| 39 | USB_RECIP_DEVICE) | ||
| 40 | #define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ | ||
| 41 | USB_RECIP_DEVICE) | ||
| 42 | #define MCS7830_RD_BREQ 0x0E | ||
| 43 | #define MCS7830_WR_BREQ 0x0D | ||
| 44 | |||
| 45 | #define MCS7830_CTRL_TIMEOUT 1000 | ||
| 46 | #define MCS7830_MAX_MCAST 64 | ||
| 47 | |||
| 48 | #define MCS7830_VENDOR_ID 0x9710 | ||
| 49 | #define MCS7830_PRODUCT_ID 0x7830 | ||
| 50 | |||
| 51 | #define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ | ||
| 52 | ADVERTISE_100HALF | ADVERTISE_10FULL | \ | ||
| 53 | ADVERTISE_10HALF | ADVERTISE_CSMA) | ||
| 54 | |||
| 55 | /* HIF_REG_XX coressponding index value */ | ||
| 56 | enum { | ||
| 57 | HIF_REG_MULTICAST_HASH = 0x00, | ||
| 58 | HIF_REG_PACKET_GAP1 = 0x08, | ||
| 59 | HIF_REG_PACKET_GAP2 = 0x09, | ||
| 60 | HIF_REG_PHY_DATA = 0x0a, | ||
| 61 | HIF_REG_PHY_CMD1 = 0x0c, | ||
| 62 | HIF_REG_PHY_CMD1_READ = 0x40, | ||
| 63 | HIF_REG_PHY_CMD1_WRITE = 0x20, | ||
| 64 | HIF_REG_PHY_CMD1_PHYADDR = 0x01, | ||
| 65 | HIF_REG_PHY_CMD2 = 0x0d, | ||
| 66 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, | ||
| 67 | HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, | ||
| 68 | HIF_REG_CONFIG = 0x0e, | ||
| 69 | HIF_REG_CONFIG_CFG = 0x80, | ||
| 70 | HIF_REG_CONFIG_SPEED100 = 0x40, | ||
| 71 | HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, | ||
| 72 | HIF_REG_CONFIG_RXENABLE = 0x10, | ||
| 73 | HIF_REG_CONFIG_TXENABLE = 0x08, | ||
| 74 | HIF_REG_CONFIG_SLEEPMODE = 0x04, | ||
| 75 | HIF_REG_CONFIG_ALLMULTICAST = 0x02, | ||
| 76 | HIF_REG_CONFIG_PROMISCIOUS = 0x01, | ||
| 77 | HIF_REG_ETHERNET_ADDR = 0x0f, | ||
| 78 | HIF_REG_22 = 0x15, | ||
| 79 | HIF_REG_PAUSE_THRESHOLD = 0x16, | ||
| 80 | HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct mcs7830_data { | ||
| 84 | u8 multi_filter[8]; | ||
| 85 | u8 config; | ||
| 86 | }; | ||
| 87 | |||
| 88 | static const char driver_name[] = "MOSCHIP usb-ethernet driver"; | ||
| 89 | |||
| 90 | static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) | ||
| 91 | { | ||
| 92 | struct usb_device *xdev = dev->udev; | ||
| 93 | int ret; | ||
| 94 | |||
| 95 | ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, | ||
| 96 | MCS7830_RD_BMREQ, 0x0000, index, data, | ||
| 97 | size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); | ||
| 98 | return ret; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) | ||
| 102 | { | ||
| 103 | struct usb_device *xdev = dev->udev; | ||
| 104 | int ret; | ||
| 105 | |||
| 106 | ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, | ||
| 107 | MCS7830_WR_BMREQ, 0x0000, index, data, | ||
| 108 | size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); | ||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void mcs7830_async_cmd_callback(struct urb *urb) | ||
| 113 | { | ||
| 114 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
| 115 | |||
| 116 | if (urb->status < 0) | ||
| 117 | printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", | ||
| 118 | urb->status); | ||
| 119 | |||
| 120 | kfree(req); | ||
| 121 | usb_free_urb(urb); | ||
| 122 | } | ||
| 123 | |||
| 124 | static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) | ||
| 125 | { | ||
| 126 | struct usb_ctrlrequest *req; | ||
| 127 | int ret; | ||
| 128 | struct urb *urb; | ||
| 129 | |||
| 130 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 131 | if (!urb) { | ||
| 132 | dev_dbg(&dev->udev->dev, "Error allocating URB " | ||
| 133 | "in write_cmd_async!"); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | |||
| 137 | req = kmalloc(sizeof *req, GFP_ATOMIC); | ||
| 138 | if (!req) { | ||
| 139 | dev_err(&dev->udev->dev, "Failed to allocate memory for " | ||
| 140 | "control request"); | ||
| 141 | goto out; | ||
| 142 | } | ||
| 143 | req->bRequestType = MCS7830_WR_BMREQ; | ||
| 144 | req->bRequest = MCS7830_WR_BREQ; | ||
| 145 | req->wValue = 0; | ||
| 146 | req->wIndex = cpu_to_le16(index); | ||
| 147 | req->wLength = cpu_to_le16(size); | ||
| 148 | |||
| 149 | usb_fill_control_urb(urb, dev->udev, | ||
| 150 | usb_sndctrlpipe(dev->udev, 0), | ||
| 151 | (void *)req, data, size, | ||
| 152 | mcs7830_async_cmd_callback, req); | ||
| 153 | |||
| 154 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 155 | if (ret < 0) { | ||
| 156 | dev_err(&dev->udev->dev, "Error submitting the control " | ||
| 157 | "message: ret=%d", ret); | ||
| 158 | goto out; | ||
| 159 | } | ||
| 160 | return; | ||
| 161 | out: | ||
| 162 | kfree(req); | ||
| 163 | usb_free_urb(urb); | ||
| 164 | } | ||
| 165 | |||
| 166 | static int mcs7830_get_address(struct usbnet *dev) | ||
| 167 | { | ||
| 168 | int ret; | ||
| 169 | ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, | ||
| 170 | dev->net->dev_addr); | ||
| 171 | if (ret < 0) | ||
| 172 | return ret; | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static int mcs7830_read_phy(struct usbnet *dev, u8 index) | ||
| 177 | { | ||
| 178 | int ret; | ||
| 179 | int i; | ||
| 180 | __le16 val; | ||
| 181 | |||
| 182 | u8 cmd[2] = { | ||
| 183 | HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, | ||
| 184 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, | ||
| 185 | }; | ||
| 186 | |||
| 187 | mutex_lock(&dev->phy_mutex); | ||
| 188 | /* write the MII command */ | ||
| 189 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
| 190 | if (ret < 0) | ||
| 191 | goto out; | ||
| 192 | |||
| 193 | /* wait for the data to become valid, should be within < 1ms */ | ||
| 194 | for (i = 0; i < 10; i++) { | ||
| 195 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
| 196 | if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | ||
| 197 | break; | ||
| 198 | ret = -EIO; | ||
| 199 | msleep(1); | ||
| 200 | } | ||
| 201 | if (ret < 0) | ||
| 202 | goto out; | ||
| 203 | |||
| 204 | /* read actual register contents */ | ||
| 205 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); | ||
| 206 | if (ret < 0) | ||
| 207 | goto out; | ||
| 208 | ret = le16_to_cpu(val); | ||
| 209 | dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", | ||
| 210 | index, val, i); | ||
| 211 | out: | ||
| 212 | mutex_unlock(&dev->phy_mutex); | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) | ||
| 217 | { | ||
| 218 | int ret; | ||
| 219 | int i; | ||
| 220 | __le16 le_val; | ||
| 221 | |||
| 222 | u8 cmd[2] = { | ||
| 223 | HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, | ||
| 224 | HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), | ||
| 225 | }; | ||
| 226 | |||
| 227 | mutex_lock(&dev->phy_mutex); | ||
| 228 | |||
| 229 | /* write the new register contents */ | ||
| 230 | le_val = cpu_to_le16(val); | ||
| 231 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); | ||
| 232 | if (ret < 0) | ||
| 233 | goto out; | ||
| 234 | |||
| 235 | /* write the MII command */ | ||
| 236 | ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
| 237 | if (ret < 0) | ||
| 238 | goto out; | ||
| 239 | |||
| 240 | /* wait for the command to be accepted by the PHY */ | ||
| 241 | for (i = 0; i < 10; i++) { | ||
| 242 | ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | ||
| 243 | if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | ||
| 244 | break; | ||
| 245 | ret = -EIO; | ||
| 246 | msleep(1); | ||
| 247 | } | ||
| 248 | if (ret < 0) | ||
| 249 | goto out; | ||
| 250 | |||
| 251 | ret = 0; | ||
| 252 | dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", | ||
| 253 | index, val, i); | ||
| 254 | out: | ||
| 255 | mutex_unlock(&dev->phy_mutex); | ||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | |||
| 259 | /* | ||
| 260 | * This algorithm comes from the original mcs7830 version 1.4 driver, | ||
| 261 | * not sure if it is needed. | ||
| 262 | */ | ||
| 263 | static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) | ||
| 264 | { | ||
| 265 | int ret; | ||
| 266 | /* Enable all media types */ | ||
| 267 | ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); | ||
| 268 | |||
| 269 | /* First reset BMCR */ | ||
| 270 | if (!ret) | ||
| 271 | ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); | ||
| 272 | /* Enable Auto Neg */ | ||
| 273 | if (!ret) | ||
| 274 | ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); | ||
| 275 | /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ | ||
| 276 | if (!ret) | ||
| 277 | ret = mcs7830_write_phy(dev, MII_BMCR, | ||
| 278 | BMCR_ANENABLE | BMCR_ANRESTART ); | ||
| 279 | return ret < 0 ? : 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | /* | ||
| 284 | * if we can read register 22, the chip revision is C or higher | ||
| 285 | */ | ||
| 286 | static int mcs7830_get_rev(struct usbnet *dev) | ||
| 287 | { | ||
| 288 | u8 dummy[2]; | ||
| 289 | int ret; | ||
| 290 | ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); | ||
| 291 | if (ret > 0) | ||
| 292 | return 2; /* Rev C or later */ | ||
| 293 | return 1; /* earlier revision */ | ||
| 294 | } | ||
| 295 | |||
| 296 | /* | ||
| 297 | * On rev. C we need to set the pause threshold | ||
| 298 | */ | ||
| 299 | static void mcs7830_rev_C_fixup(struct usbnet *dev) | ||
| 300 | { | ||
| 301 | u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; | ||
| 302 | int retry; | ||
| 303 | |||
| 304 | for (retry = 0; retry < 2; retry++) { | ||
| 305 | if (mcs7830_get_rev(dev) == 2) { | ||
| 306 | dev_info(&dev->udev->dev, "applying rev.C fixup\n"); | ||
| 307 | mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, | ||
| 308 | 1, &pause_threshold); | ||
| 309 | } | ||
| 310 | msleep(1); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | static int mcs7830_init_dev(struct usbnet *dev) | ||
| 315 | { | ||
| 316 | int ret; | ||
| 317 | int retry; | ||
| 318 | |||
| 319 | /* Read MAC address from EEPROM */ | ||
| 320 | ret = -EINVAL; | ||
| 321 | for (retry = 0; retry < 5 && ret; retry++) | ||
| 322 | ret = mcs7830_get_address(dev); | ||
| 323 | if (ret) { | ||
| 324 | dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | |||
| 328 | /* Set up PHY */ | ||
| 329 | ret = mcs7830_set_autoneg(dev, 0); | ||
| 330 | if (ret) { | ||
| 331 | dev_info(&dev->udev->dev, "Cannot set autoneg\n"); | ||
| 332 | goto out; | ||
| 333 | } | ||
| 334 | |||
| 335 | mcs7830_rev_C_fixup(dev); | ||
| 336 | ret = 0; | ||
| 337 | out: | ||
| 338 | return ret; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, | ||
| 342 | int location) | ||
| 343 | { | ||
| 344 | struct usbnet *dev = netdev->priv; | ||
| 345 | return mcs7830_read_phy(dev, location); | ||
| 346 | } | ||
| 347 | |||
| 348 | static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, | ||
| 349 | int location, int val) | ||
| 350 | { | ||
| 351 | struct usbnet *dev = netdev->priv; | ||
| 352 | mcs7830_write_phy(dev, location, val); | ||
| 353 | } | ||
| 354 | |||
| 355 | static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
| 356 | { | ||
| 357 | struct usbnet *dev = netdev_priv(net); | ||
| 358 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
| 359 | } | ||
| 360 | |||
| 361 | /* credits go to asix_set_multicast */ | ||
| 362 | static void mcs7830_set_multicast(struct net_device *net) | ||
| 363 | { | ||
| 364 | struct usbnet *dev = netdev_priv(net); | ||
| 365 | struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; | ||
| 366 | |||
| 367 | data->config = HIF_REG_CONFIG_TXENABLE; | ||
| 368 | |||
| 369 | /* this should not be needed, but it doesn't work otherwise */ | ||
| 370 | data->config |= HIF_REG_CONFIG_ALLMULTICAST; | ||
| 371 | |||
| 372 | if (net->flags & IFF_PROMISC) { | ||
| 373 | data->config |= HIF_REG_CONFIG_PROMISCIOUS; | ||
| 374 | } else if (net->flags & IFF_ALLMULTI | ||
| 375 | || net->mc_count > MCS7830_MAX_MCAST) { | ||
| 376 | data->config |= HIF_REG_CONFIG_ALLMULTICAST; | ||
| 377 | } else if (net->mc_count == 0) { | ||
| 378 | /* just broadcast and directed */ | ||
| 379 | } else { | ||
| 380 | /* We use the 20 byte dev->data | ||
| 381 | * for our 8 byte filter buffer | ||
| 382 | * to avoid allocating memory that | ||
| 383 | * is tricky to free later */ | ||
| 384 | struct dev_mc_list *mc_list = net->mc_list; | ||
| 385 | u32 crc_bits; | ||
| 386 | int i; | ||
| 387 | |||
| 388 | memset(data->multi_filter, 0, sizeof data->multi_filter); | ||
| 389 | |||
| 390 | /* Build the multicast hash filter. */ | ||
| 391 | for (i = 0; i < net->mc_count; i++) { | ||
| 392 | crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; | ||
| 393 | data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); | ||
| 394 | mc_list = mc_list->next; | ||
| 395 | } | ||
| 396 | |||
| 397 | mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, | ||
| 398 | sizeof data->multi_filter, | ||
| 399 | data->multi_filter); | ||
| 400 | } | ||
| 401 | |||
| 402 | mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); | ||
| 403 | } | ||
| 404 | |||
| 405 | static int mcs7830_get_regs_len(struct net_device *net) | ||
| 406 | { | ||
| 407 | struct usbnet *dev = netdev_priv(net); | ||
| 408 | |||
| 409 | switch (mcs7830_get_rev(dev)) { | ||
| 410 | case 1: | ||
| 411 | return 21; | ||
| 412 | case 2: | ||
| 413 | return 32; | ||
| 414 | } | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) | ||
| 419 | { | ||
| 420 | usbnet_get_drvinfo(net, drvinfo); | ||
| 421 | drvinfo->regdump_len = mcs7830_get_regs_len(net); | ||
| 422 | } | ||
| 423 | |||
| 424 | static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) | ||
| 425 | { | ||
| 426 | struct usbnet *dev = netdev_priv(net); | ||
| 427 | |||
| 428 | regs->version = mcs7830_get_rev(dev); | ||
| 429 | mcs7830_get_reg(dev, 0, regs->len, data); | ||
| 430 | } | ||
| 431 | |||
| 432 | static struct ethtool_ops mcs7830_ethtool_ops = { | ||
| 433 | .get_drvinfo = mcs7830_get_drvinfo, | ||
| 434 | .get_regs_len = mcs7830_get_regs_len, | ||
| 435 | .get_regs = mcs7830_get_regs, | ||
| 436 | |||
| 437 | /* common usbnet calls */ | ||
| 438 | .get_link = usbnet_get_link, | ||
| 439 | .get_msglevel = usbnet_get_msglevel, | ||
| 440 | .set_msglevel = usbnet_set_msglevel, | ||
| 441 | .get_settings = usbnet_get_settings, | ||
| 442 | .set_settings = usbnet_set_settings, | ||
| 443 | .nway_reset = usbnet_nway_reset, | ||
| 444 | }; | ||
| 445 | |||
| 446 | static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) | ||
| 447 | { | ||
| 448 | struct net_device *net = dev->net; | ||
| 449 | int ret; | ||
| 450 | |||
| 451 | ret = mcs7830_init_dev(dev); | ||
| 452 | if (ret) | ||
| 453 | goto out; | ||
| 454 | |||
| 455 | net->do_ioctl = mcs7830_ioctl; | ||
| 456 | net->ethtool_ops = &mcs7830_ethtool_ops; | ||
| 457 | net->set_multicast_list = mcs7830_set_multicast; | ||
| 458 | mcs7830_set_multicast(net); | ||
| 459 | |||
| 460 | /* reserve space for the status byte on rx */ | ||
| 461 | dev->rx_urb_size = ETH_FRAME_LEN + 1; | ||
| 462 | |||
| 463 | dev->mii.mdio_read = mcs7830_mdio_read; | ||
| 464 | dev->mii.mdio_write = mcs7830_mdio_write; | ||
| 465 | dev->mii.dev = net; | ||
| 466 | dev->mii.phy_id_mask = 0x3f; | ||
| 467 | dev->mii.reg_num_mask = 0x1f; | ||
| 468 | dev->mii.phy_id = *((u8 *) net->dev_addr + 1); | ||
| 469 | |||
| 470 | ret = usbnet_get_endpoints(dev, udev); | ||
| 471 | out: | ||
| 472 | return ret; | ||
| 473 | } | ||
| 474 | |||
| 475 | /* The chip always appends a status bytes that we need to strip */ | ||
| 476 | static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
| 477 | { | ||
| 478 | u8 status; | ||
| 479 | |||
| 480 | if (skb->len == 0) { | ||
| 481 | dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); | ||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | skb_trim(skb, skb->len - 1); | ||
| 486 | status = skb->data[skb->len]; | ||
| 487 | |||
| 488 | if (status != 0x20) | ||
| 489 | dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); | ||
| 490 | |||
| 491 | return skb->len > 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | static const struct driver_info moschip_info = { | ||
| 495 | .description = "MOSCHIP 7830 usb-NET adapter", | ||
| 496 | .bind = mcs7830_bind, | ||
| 497 | .rx_fixup = mcs7830_rx_fixup, | ||
| 498 | .flags = FLAG_ETHER, | ||
| 499 | .in = 1, | ||
| 500 | .out = 2, | ||
| 501 | }; | ||
| 502 | |||
| 503 | static const struct usb_device_id products[] = { | ||
| 504 | { | ||
| 505 | USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), | ||
| 506 | .driver_info = (unsigned long) &moschip_info, | ||
| 507 | }, | ||
| 508 | {}, | ||
| 509 | }; | ||
| 510 | MODULE_DEVICE_TABLE(usb, products); | ||
| 511 | |||
| 512 | static struct usb_driver mcs7830_driver = { | ||
| 513 | .name = driver_name, | ||
| 514 | .id_table = products, | ||
| 515 | .probe = usbnet_probe, | ||
| 516 | .disconnect = usbnet_disconnect, | ||
| 517 | .suspend = usbnet_suspend, | ||
| 518 | .resume = usbnet_resume, | ||
| 519 | }; | ||
| 520 | |||
| 521 | static int __init mcs7830_init(void) | ||
| 522 | { | ||
| 523 | return usb_register(&mcs7830_driver); | ||
| 524 | } | ||
| 525 | module_init(mcs7830_init); | ||
| 526 | |||
| 527 | static void __exit mcs7830_exit(void) | ||
| 528 | { | ||
| 529 | usb_deregister(&mcs7830_driver); | ||
| 530 | } | ||
| 531 | module_exit(mcs7830_exit); | ||
| 532 | |||
| 533 | MODULE_DESCRIPTION("USB to network adapter MCS7830)"); | ||
| 534 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 24bd3486ee63..cf3d20eb781c 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c | |||
| @@ -669,6 +669,37 @@ done: | |||
| 669 | * they'll probably want to use this base set. | 669 | * they'll probably want to use this base set. |
| 670 | */ | 670 | */ |
| 671 | 671 | ||
| 672 | int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) | ||
| 673 | { | ||
| 674 | struct usbnet *dev = netdev_priv(net); | ||
| 675 | |||
| 676 | if (!dev->mii.mdio_read) | ||
| 677 | return -EOPNOTSUPP; | ||
| 678 | |||
| 679 | return mii_ethtool_gset(&dev->mii, cmd); | ||
| 680 | } | ||
| 681 | EXPORT_SYMBOL_GPL(usbnet_get_settings); | ||
| 682 | |||
| 683 | int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) | ||
| 684 | { | ||
| 685 | struct usbnet *dev = netdev_priv(net); | ||
| 686 | int retval; | ||
| 687 | |||
| 688 | if (!dev->mii.mdio_write) | ||
| 689 | return -EOPNOTSUPP; | ||
| 690 | |||
| 691 | retval = mii_ethtool_sset(&dev->mii, cmd); | ||
| 692 | |||
| 693 | /* link speed/duplex might have changed */ | ||
| 694 | if (dev->driver_info->link_reset) | ||
| 695 | dev->driver_info->link_reset(dev); | ||
| 696 | |||
| 697 | return retval; | ||
| 698 | |||
| 699 | } | ||
| 700 | EXPORT_SYMBOL_GPL(usbnet_set_settings); | ||
| 701 | |||
| 702 | |||
| 672 | void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) | 703 | void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) |
| 673 | { | 704 | { |
| 674 | struct usbnet *dev = netdev_priv(net); | 705 | struct usbnet *dev = netdev_priv(net); |
| @@ -682,7 +713,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) | |||
| 682 | } | 713 | } |
| 683 | EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); | 714 | EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); |
| 684 | 715 | ||
| 685 | static u32 usbnet_get_link (struct net_device *net) | 716 | u32 usbnet_get_link (struct net_device *net) |
| 686 | { | 717 | { |
| 687 | struct usbnet *dev = netdev_priv(net); | 718 | struct usbnet *dev = netdev_priv(net); |
| 688 | 719 | ||
| @@ -690,9 +721,14 @@ static u32 usbnet_get_link (struct net_device *net) | |||
| 690 | if (dev->driver_info->check_connect) | 721 | if (dev->driver_info->check_connect) |
| 691 | return dev->driver_info->check_connect (dev) == 0; | 722 | return dev->driver_info->check_connect (dev) == 0; |
| 692 | 723 | ||
| 724 | /* if the device has mii operations, use those */ | ||
| 725 | if (dev->mii.mdio_read) | ||
| 726 | return mii_link_ok(&dev->mii); | ||
| 727 | |||
| 693 | /* Otherwise, say we're up (to avoid breaking scripts) */ | 728 | /* Otherwise, say we're up (to avoid breaking scripts) */ |
| 694 | return 1; | 729 | return 1; |
| 695 | } | 730 | } |
| 731 | EXPORT_SYMBOL_GPL(usbnet_get_link); | ||
| 696 | 732 | ||
| 697 | u32 usbnet_get_msglevel (struct net_device *net) | 733 | u32 usbnet_get_msglevel (struct net_device *net) |
| 698 | { | 734 | { |
| @@ -710,10 +746,24 @@ void usbnet_set_msglevel (struct net_device *net, u32 level) | |||
| 710 | } | 746 | } |
| 711 | EXPORT_SYMBOL_GPL(usbnet_set_msglevel); | 747 | EXPORT_SYMBOL_GPL(usbnet_set_msglevel); |
| 712 | 748 | ||
| 749 | int usbnet_nway_reset(struct net_device *net) | ||
| 750 | { | ||
| 751 | struct usbnet *dev = netdev_priv(net); | ||
| 752 | |||
| 753 | if (!dev->mii.mdio_write) | ||
| 754 | return -EOPNOTSUPP; | ||
| 755 | |||
| 756 | return mii_nway_restart(&dev->mii); | ||
| 757 | } | ||
| 758 | EXPORT_SYMBOL_GPL(usbnet_nway_reset); | ||
| 759 | |||
| 713 | /* drivers may override default ethtool_ops in their bind() routine */ | 760 | /* drivers may override default ethtool_ops in their bind() routine */ |
| 714 | static struct ethtool_ops usbnet_ethtool_ops = { | 761 | static struct ethtool_ops usbnet_ethtool_ops = { |
| 762 | .get_settings = usbnet_get_settings, | ||
| 763 | .set_settings = usbnet_set_settings, | ||
| 715 | .get_drvinfo = usbnet_get_drvinfo, | 764 | .get_drvinfo = usbnet_get_drvinfo, |
| 716 | .get_link = usbnet_get_link, | 765 | .get_link = usbnet_get_link, |
| 766 | .nway_reset = usbnet_nway_reset, | ||
| 717 | .get_msglevel = usbnet_get_msglevel, | 767 | .get_msglevel = usbnet_get_msglevel, |
| 718 | .set_msglevel = usbnet_set_msglevel, | 768 | .set_msglevel = usbnet_set_msglevel, |
| 719 | }; | 769 | }; |
| @@ -1094,6 +1144,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
| 1094 | dev->delay.function = usbnet_bh; | 1144 | dev->delay.function = usbnet_bh; |
| 1095 | dev->delay.data = (unsigned long) dev; | 1145 | dev->delay.data = (unsigned long) dev; |
| 1096 | init_timer (&dev->delay); | 1146 | init_timer (&dev->delay); |
| 1147 | mutex_init (&dev->phy_mutex); | ||
| 1097 | 1148 | ||
| 1098 | SET_MODULE_OWNER (net); | 1149 | SET_MODULE_OWNER (net); |
| 1099 | dev->net = net; | 1150 | dev->net = net; |
| @@ -1225,7 +1276,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume); | |||
| 1225 | static int __init usbnet_init(void) | 1276 | static int __init usbnet_init(void) |
| 1226 | { | 1277 | { |
| 1227 | /* compiler should optimize this out */ | 1278 | /* compiler should optimize this out */ |
| 1228 | BUG_ON (sizeof (((struct sk_buff *)0)->cb) | 1279 | BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) |
| 1229 | < sizeof (struct skb_data)); | 1280 | < sizeof (struct skb_data)); |
| 1230 | 1281 | ||
| 1231 | random_ether_addr(node_id); | 1282 | random_ether_addr(node_id); |
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index c0746f0454af..07c70abbe0ec 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h | |||
| @@ -30,6 +30,7 @@ struct usbnet { | |||
| 30 | struct usb_device *udev; | 30 | struct usb_device *udev; |
| 31 | struct driver_info *driver_info; | 31 | struct driver_info *driver_info; |
| 32 | wait_queue_head_t *wait; | 32 | wait_queue_head_t *wait; |
| 33 | struct mutex phy_mutex; | ||
| 33 | 34 | ||
| 34 | /* i/o info: pipes etc */ | 35 | /* i/o info: pipes etc */ |
| 35 | unsigned in, out; | 36 | unsigned in, out; |
| @@ -168,9 +169,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int); | |||
| 168 | extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); | 169 | extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); |
| 169 | extern void usbnet_unlink_rx_urbs(struct usbnet *); | 170 | extern void usbnet_unlink_rx_urbs(struct usbnet *); |
| 170 | 171 | ||
| 172 | extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); | ||
| 173 | extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); | ||
| 174 | extern u32 usbnet_get_link (struct net_device *net); | ||
| 171 | extern u32 usbnet_get_msglevel (struct net_device *); | 175 | extern u32 usbnet_get_msglevel (struct net_device *); |
| 172 | extern void usbnet_set_msglevel (struct net_device *, u32); | 176 | extern void usbnet_set_msglevel (struct net_device *, u32); |
| 173 | extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); | 177 | extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); |
| 178 | extern int usbnet_nway_reset(struct net_device *net); | ||
| 174 | 179 | ||
| 175 | /* messaging support includes the interface name, so it must not be | 180 | /* messaging support includes the interface name, so it must not be |
| 176 | * used before it has one ... notably, in minidriver bind() calls. | 181 | * used before it has one ... notably, in minidriver bind() calls. |
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5076b9d97057..9a6ec1b5e3d5 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig | |||
| @@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232 | |||
| 422 | To compile this driver as a module, choose M here: the | 422 | To compile this driver as a module, choose M here: the |
| 423 | module will be called mct_u232. | 423 | module will be called mct_u232. |
| 424 | 424 | ||
| 425 | config USB_SERIAL_MOS7720 | ||
| 426 | tristate "USB Moschip 7720 Single Port Serial Driver" | ||
| 427 | depends on USB_SERIAL | ||
| 428 | ---help--- | ||
| 429 | Say Y here if you want to use a USB Serial single port adapter from | ||
| 430 | Moschip Semiconductor Tech. | ||
| 431 | |||
| 432 | To compile this driver as a module, choose M here: the | ||
| 433 | module will be called mos7720. | ||
| 434 | |||
| 425 | config USB_SERIAL_MOS7840 | 435 | config USB_SERIAL_MOS7840 |
| 426 | tristate "USB Moschip 7840/7820 USB Serial Driver" | 436 | tristate "USB Moschip 7840/7820 USB Serial Driver" |
| 427 | depends on USB_SERIAL | 437 | depends on USB_SERIAL |
| @@ -527,8 +537,7 @@ config USB_SERIAL_OPTION | |||
| 527 | The USB bus on these cards is not accessible externally. | 537 | The USB bus on these cards is not accessible externally. |
| 528 | 538 | ||
| 529 | Supported devices include (some of?) those made by: | 539 | Supported devices include (some of?) those made by: |
| 530 | Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or | 540 | Option, Huawei, Audiovox, Novatel Wireless, or Anydata. |
| 531 | Anydata. | ||
| 532 | 541 | ||
| 533 | To compile this driver as a module, choose M here: the | 542 | To compile this driver as a module, choose M here: the |
| 534 | module will be called option. | 543 | module will be called option. |
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 8dce83340e31..a5047dc599bb 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile | |||
| @@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o | |||
| 34 | obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o | 34 | obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o |
| 35 | obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o | 35 | obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o |
| 36 | obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o | 36 | obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o |
| 37 | obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o | ||
| 37 | obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o | 38 | obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o |
| 38 | obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o | 39 | obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o |
| 39 | obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o | 40 | obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o |
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 2c19f19b255c..7f5d546da39a 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c | |||
| @@ -18,12 +18,8 @@ | |||
| 18 | 18 | ||
| 19 | static struct usb_device_id id_table [] = { | 19 | static struct usb_device_id id_table [] = { |
| 20 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ | 20 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ |
| 21 | { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ | ||
| 22 | { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ | ||
| 23 | { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ | ||
| 24 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ | ||
| 25 | { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ | ||
| 26 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ | 21 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ |
| 22 | { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ | ||
| 27 | { }, | 23 | { }, |
| 28 | }; | 24 | }; |
| 29 | MODULE_DEVICE_TABLE(usb, id_table); | 25 | MODULE_DEVICE_TABLE(usb, id_table); |
| @@ -133,6 +129,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) | |||
| 133 | } | 129 | } |
| 134 | urb = usb_alloc_urb(0, GFP_KERNEL); | 130 | urb = usb_alloc_urb(0, GFP_KERNEL); |
| 135 | if (!urb) { | 131 | if (!urb) { |
| 132 | kfree(buffer); | ||
| 136 | dev_err(&port->dev, "%s - no more urbs?\n", | 133 | dev_err(&port->dev, "%s - no more urbs?\n", |
| 137 | __FUNCTION__); | 134 | __FUNCTION__); |
| 138 | result = -ENOMEM; | 135 | result = -ENOMEM; |
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 486c7411b9a7..bbf6532c26e5 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c | |||
| @@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = { | |||
| 65 | { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ | 65 | { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ |
| 66 | { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ | 66 | { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ |
| 67 | { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ | 67 | { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ |
| 68 | { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ | ||
| 68 | { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ | 69 | { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ |
| 69 | { } /* Terminating Entry */ | 70 | { } /* Terminating Entry */ |
| 70 | }; | 71 | }; |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d3dc1a15ec6c..bd76b4c11fcc 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -1,16 +1,16 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * USB FTDI SIO driver | 2 | * USB FTDI SIO driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999 - 2001 | 4 | * Copyright (C) 1999 - 2001 |
| 5 | * Greg Kroah-Hartman (greg@kroah.com) | 5 | * Greg Kroah-Hartman (greg@kroah.com) |
| 6 | * Bill Ryder (bryder@sgi.com) | 6 | * Bill Ryder (bryder@sgi.com) |
| 7 | * Copyright (C) 2002 | 7 | * Copyright (C) 2002 |
| 8 | * Kuba Ober (kuba@mareimbrium.org) | 8 | * Kuba Ober (kuba@mareimbrium.org) |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| 12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
| 13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
| 14 | * | 14 | * |
| 15 | * See Documentation/usb/usb-serial.txt for more information on using this driver | 15 | * See Documentation/usb/usb-serial.txt for more information on using this driver |
| 16 | * | 16 | * |
| @@ -32,7 +32,7 @@ | |||
| 32 | * Changed full name of USB-UIRT device to avoid "/" character. | 32 | * Changed full name of USB-UIRT device to avoid "/" character. |
| 33 | * Added FTDI's alternate PID (0x6006) for FT232/245 devices. | 33 | * Added FTDI's alternate PID (0x6006) for FT232/245 devices. |
| 34 | * Added PID for "ELV USB Module UO100" from Stefan Frings. | 34 | * Added PID for "ELV USB Module UO100" from Stefan Frings. |
| 35 | * | 35 | * |
| 36 | * (21/Oct/2003) Ian Abbott | 36 | * (21/Oct/2003) Ian Abbott |
| 37 | * Renamed some VID/PID macros for Matrix Orbital and Perle Systems | 37 | * Renamed some VID/PID macros for Matrix Orbital and Perle Systems |
| 38 | * devices. Removed Matrix Orbital and Perle Systems devices from the | 38 | * devices. Removed Matrix Orbital and Perle Systems devices from the |
| @@ -69,7 +69,7 @@ | |||
| 69 | * does not incure any measurable overhead. This also relies on the fact | 69 | * does not incure any measurable overhead. This also relies on the fact |
| 70 | * that we have proper reference counting logic for urbs. I nicked this | 70 | * that we have proper reference counting logic for urbs. I nicked this |
| 71 | * from Greg KH's Visor driver. | 71 | * from Greg KH's Visor driver. |
| 72 | * | 72 | * |
| 73 | * (23/Jun/2003) Ian Abbott | 73 | * (23/Jun/2003) Ian Abbott |
| 74 | * Reduced flip buffer pushes and corrected a data length test in | 74 | * Reduced flip buffer pushes and corrected a data length test in |
| 75 | * ftdi_read_bulk_callback. | 75 | * ftdi_read_bulk_callback. |
| @@ -77,7 +77,7 @@ | |||
| 77 | * | 77 | * |
| 78 | * (21/Jun/2003) Erik Nygren | 78 | * (21/Jun/2003) Erik Nygren |
| 79 | * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. | 79 | * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. |
| 80 | * See <http://www.home-electro.com/tira1.htm>. Only operates properly | 80 | * See <http://www.home-electro.com/tira1.htm>. Only operates properly |
| 81 | * at 100000 and RTS-CTS, so set custom divisor mode on startup. | 81 | * at 100000 and RTS-CTS, so set custom divisor mode on startup. |
| 82 | * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. | 82 | * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. |
| 83 | * | 83 | * |
| @@ -137,17 +137,17 @@ | |||
| 137 | * (17/Feb/2003) Bill Ryder | 137 | * (17/Feb/2003) Bill Ryder |
| 138 | * Added write urb buffer pool on a per device basis | 138 | * Added write urb buffer pool on a per device basis |
| 139 | * Added more checking for open file on callbacks (fixed OOPS) | 139 | * Added more checking for open file on callbacks (fixed OOPS) |
| 140 | * Added CrystalFontz 632 and 634 PIDs | 140 | * Added CrystalFontz 632 and 634 PIDs |
| 141 | * (thanx to CrystalFontz for the sample devices - they flushed out | 141 | * (thanx to CrystalFontz for the sample devices - they flushed out |
| 142 | * some driver bugs) | 142 | * some driver bugs) |
| 143 | * Minor debugging message changes | 143 | * Minor debugging message changes |
| 144 | * Added throttle, unthrottle and chars_in_buffer functions | 144 | * Added throttle, unthrottle and chars_in_buffer functions |
| 145 | * Fixed FTDI_SIO (the original device) bug | 145 | * Fixed FTDI_SIO (the original device) bug |
| 146 | * Fixed some shutdown handling | 146 | * Fixed some shutdown handling |
| 147 | * | 147 | * |
| 148 | * | 148 | * |
| 149 | * | 149 | * |
| 150 | * | 150 | * |
| 151 | * (07/Jun/2002) Kuba Ober | 151 | * (07/Jun/2002) Kuba Ober |
| 152 | * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor | 152 | * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor |
| 153 | * function. It was getting too complex. | 153 | * function. It was getting too complex. |
| @@ -158,7 +158,7 @@ | |||
| 158 | * | 158 | * |
| 159 | * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch | 159 | * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch |
| 160 | * Not tested by me but it doesn't break anything I use. | 160 | * Not tested by me but it doesn't break anything I use. |
| 161 | * | 161 | * |
| 162 | * (04/Jan/2002) Kuba Ober | 162 | * (04/Jan/2002) Kuba Ober |
| 163 | * Implemented 38400 baudrate kludge, where it can be substituted with other | 163 | * Implemented 38400 baudrate kludge, where it can be substituted with other |
| 164 | * values. That's the only way to set custom baudrates. | 164 | * values. That's the only way to set custom baudrates. |
| @@ -179,7 +179,7 @@ | |||
| 179 | * (the previous version caused panics) | 179 | * (the previous version caused panics) |
| 180 | * Removed port iteration code since the device only has one I/O port and it | 180 | * Removed port iteration code since the device only has one I/O port and it |
| 181 | * was wrong anyway. | 181 | * was wrong anyway. |
| 182 | * | 182 | * |
| 183 | * (31/May/2001) gkh | 183 | * (31/May/2001) gkh |
| 184 | * Switched from using spinlock to a semaphore, which fixes lots of problems. | 184 | * Switched from using spinlock to a semaphore, which fixes lots of problems. |
| 185 | * | 185 | * |
| @@ -188,16 +188,16 @@ | |||
| 188 | * Cleaned up comments for 8U232 | 188 | * Cleaned up comments for 8U232 |
| 189 | * Added parity, framing and overrun error handling | 189 | * Added parity, framing and overrun error handling |
| 190 | * Added receive break handling. | 190 | * Added receive break handling. |
| 191 | * | 191 | * |
| 192 | * (04/08/2001) gb | 192 | * (04/08/2001) gb |
| 193 | * Identify version on module load. | 193 | * Identify version on module load. |
| 194 | * | 194 | * |
| 195 | * (18/March/2001) Bill Ryder | 195 | * (18/March/2001) Bill Ryder |
| 196 | * (Not released) | 196 | * (Not released) |
| 197 | * Added send break handling. (requires kernel patch too) | 197 | * Added send break handling. (requires kernel patch too) |
| 198 | * Fixed 8U232AM hardware RTS/CTS etc status reporting. | 198 | * Fixed 8U232AM hardware RTS/CTS etc status reporting. |
| 199 | * Added flipbuf fix copied from generic device | 199 | * Added flipbuf fix copied from generic device |
| 200 | * | 200 | * |
| 201 | * (12/3/2000) Bill Ryder | 201 | * (12/3/2000) Bill Ryder |
| 202 | * Added support for 8U232AM device. | 202 | * Added support for 8U232AM device. |
| 203 | * Moved PID and VIDs into header file only. | 203 | * Moved PID and VIDs into header file only. |
| @@ -211,14 +211,14 @@ | |||
| 211 | * Cleaned up comments. Removed multiple PID/VID definitions. | 211 | * Cleaned up comments. Removed multiple PID/VID definitions. |
| 212 | * Factorised cts/dtr code | 212 | * Factorised cts/dtr code |
| 213 | * Made use of __FUNCTION__ in dbg's | 213 | * Made use of __FUNCTION__ in dbg's |
| 214 | * | 214 | * |
| 215 | * (11/01/2000) Adam J. Richter | 215 | * (11/01/2000) Adam J. Richter |
| 216 | * usb_device_id table support | 216 | * usb_device_id table support |
| 217 | * | 217 | * |
| 218 | * (10/05/2000) gkh | 218 | * (10/05/2000) gkh |
| 219 | * Fixed bug with urb->dev not being set properly, now that the usb | 219 | * Fixed bug with urb->dev not being set properly, now that the usb |
| 220 | * core needs it. | 220 | * core needs it. |
| 221 | * | 221 | * |
| 222 | * (09/11/2000) gkh | 222 | * (09/11/2000) gkh |
| 223 | * Removed DEBUG #ifdefs with call to usb_serial_debug_data | 223 | * Removed DEBUG #ifdefs with call to usb_serial_debug_data |
| 224 | * | 224 | * |
| @@ -226,11 +226,11 @@ | |||
| 226 | * Added module_init and module_exit functions to handle the fact that this | 226 | * Added module_init and module_exit functions to handle the fact that this |
| 227 | * driver is a loadable module now. | 227 | * driver is a loadable module now. |
| 228 | * | 228 | * |
| 229 | * (04/04/2000) Bill Ryder | 229 | * (04/04/2000) Bill Ryder |
| 230 | * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are | 230 | * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are |
| 231 | * handled elsewhere in the tty io driver chain). | 231 | * handled elsewhere in the tty io driver chain). |
| 232 | * | 232 | * |
| 233 | * (03/30/2000) Bill Ryder | 233 | * (03/30/2000) Bill Ryder |
| 234 | * Implemented lots of ioctls | 234 | * Implemented lots of ioctls |
| 235 | * Fixed a race condition in write | 235 | * Fixed a race condition in write |
| 236 | * Changed some dbg's to errs | 236 | * Changed some dbg's to errs |
| @@ -444,13 +444,13 @@ static struct usb_device_id id_table_combined [] = { | |||
| 444 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ | 444 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ |
| 445 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ | 445 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ |
| 446 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ | 446 | /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ |
| 447 | { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, | 447 | { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, |
| 448 | { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, | 448 | { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, |
| 449 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, | 449 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, |
| 450 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, | 450 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, |
| 451 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, | 451 | { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, |
| 452 | { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, | 452 | { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, |
| 453 | { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, | 453 | { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, |
| 454 | { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, | 454 | { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, |
| 455 | { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, | 455 | { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, |
| 456 | { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, | 456 | { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, |
| @@ -522,7 +522,7 @@ static struct usb_driver ftdi_driver = { | |||
| 522 | .probe = usb_serial_probe, | 522 | .probe = usb_serial_probe, |
| 523 | .disconnect = usb_serial_disconnect, | 523 | .disconnect = usb_serial_disconnect, |
| 524 | .id_table = id_table_combined, | 524 | .id_table = id_table_combined, |
| 525 | .no_dynamic_id = 1, | 525 | .no_dynamic_id = 1, |
| 526 | }; | 526 | }; |
| 527 | 527 | ||
| 528 | static const char *ftdi_chip_name[] = { | 528 | static const char *ftdi_chip_name[] = { |
| @@ -548,13 +548,13 @@ struct ftdi_private { | |||
| 548 | int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ | 548 | int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ |
| 549 | __u16 last_set_data_urb_value ; | 549 | __u16 last_set_data_urb_value ; |
| 550 | /* the last data state set - needed for doing a break */ | 550 | /* the last data state set - needed for doing a break */ |
| 551 | int write_offset; /* This is the offset in the usb data block to write the serial data - | 551 | int write_offset; /* This is the offset in the usb data block to write the serial data - |
| 552 | * it is different between devices | 552 | * it is different between devices |
| 553 | */ | 553 | */ |
| 554 | int flags; /* some ASYNC_xxxx flags are supported */ | 554 | int flags; /* some ASYNC_xxxx flags are supported */ |
| 555 | unsigned long last_dtr_rts; /* saved modem control outputs */ | 555 | unsigned long last_dtr_rts; /* saved modem control outputs */ |
| 556 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 556 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
| 557 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ | 557 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
| 558 | __u8 rx_flags; /* receive state flags (throttling) */ | 558 | __u8 rx_flags; /* receive state flags (throttling) */ |
| 559 | spinlock_t rx_lock; /* spinlock for receive state */ | 559 | spinlock_t rx_lock; /* spinlock for receive state */ |
| 560 | struct work_struct rx_work; | 560 | struct work_struct rx_work; |
| @@ -721,7 +721,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned | |||
| 721 | urb_value |= FTDI_SIO_SET_RTS_HIGH; | 721 | urb_value |= FTDI_SIO_SET_RTS_HIGH; |
| 722 | rv = usb_control_msg(port->serial->dev, | 722 | rv = usb_control_msg(port->serial->dev, |
| 723 | usb_sndctrlpipe(port->serial->dev, 0), | 723 | usb_sndctrlpipe(port->serial->dev, 0), |
| 724 | FTDI_SIO_SET_MODEM_CTRL_REQUEST, | 724 | FTDI_SIO_SET_MODEM_CTRL_REQUEST, |
| 725 | FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, | 725 | FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, |
| 726 | urb_value, priv->interface, | 726 | urb_value, priv->interface, |
| 727 | buf, 0, WDR_TIMEOUT); | 727 | buf, 0, WDR_TIMEOUT); |
| @@ -768,7 +768,7 @@ static int change_speed(struct usb_serial_port *port) | |||
| 768 | if (priv->interface) { /* FT2232C */ | 768 | if (priv->interface) { /* FT2232C */ |
| 769 | urb_index = (__u16)((urb_index << 8) | priv->interface); | 769 | urb_index = (__u16)((urb_index << 8) | priv->interface); |
| 770 | } | 770 | } |
| 771 | 771 | ||
| 772 | rv = usb_control_msg(port->serial->dev, | 772 | rv = usb_control_msg(port->serial->dev, |
| 773 | usb_sndctrlpipe(port->serial->dev, 0), | 773 | usb_sndctrlpipe(port->serial->dev, 0), |
| 774 | FTDI_SIO_SET_BAUDRATE_REQUEST, | 774 | FTDI_SIO_SET_BAUDRATE_REQUEST, |
| @@ -827,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) | |||
| 827 | 827 | ||
| 828 | /* 3. Convert baudrate to device-specific divisor */ | 828 | /* 3. Convert baudrate to device-specific divisor */ |
| 829 | 829 | ||
| 830 | if (!baud) baud = 9600; | 830 | if (!baud) baud = 9600; |
| 831 | switch(priv->chip_type) { | 831 | switch(priv->chip_type) { |
| 832 | case SIO: /* SIO chip */ | 832 | case SIO: /* SIO chip */ |
| 833 | switch(baud) { | 833 | switch(baud) { |
| @@ -843,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) | |||
| 843 | case 115200: div_value = ftdi_sio_b115200; break; | 843 | case 115200: div_value = ftdi_sio_b115200; break; |
| 844 | } /* baud */ | 844 | } /* baud */ |
| 845 | if (div_value == 0) { | 845 | if (div_value == 0) { |
| 846 | dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); | 846 | dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); |
| 847 | div_value = ftdi_sio_b9600; | 847 | div_value = ftdi_sio_b9600; |
| 848 | div_okay = 0; | 848 | div_okay = 0; |
| 849 | } | 849 | } |
| @@ -925,7 +925,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _ | |||
| 925 | /* Make the changes - these are privileged changes! */ | 925 | /* Make the changes - these are privileged changes! */ |
| 926 | 926 | ||
| 927 | priv->flags = ((priv->flags & ~ASYNC_FLAGS) | | 927 | priv->flags = ((priv->flags & ~ASYNC_FLAGS) | |
| 928 | (new_serial.flags & ASYNC_FLAGS)); | 928 | (new_serial.flags & ASYNC_FLAGS)); |
| 929 | priv->custom_divisor = new_serial.custom_divisor; | 929 | priv->custom_divisor = new_serial.custom_divisor; |
| 930 | 930 | ||
| 931 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 931 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
| @@ -950,7 +950,7 @@ check_and_exit: | |||
| 950 | (old_priv.custom_divisor != priv->custom_divisor))) { | 950 | (old_priv.custom_divisor != priv->custom_divisor))) { |
| 951 | change_speed(port); | 951 | change_speed(port); |
| 952 | } | 952 | } |
| 953 | 953 | ||
| 954 | return (0); | 954 | return (0); |
| 955 | 955 | ||
| 956 | } /* set_serial_info */ | 956 | } /* set_serial_info */ |
| @@ -1022,18 +1022,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a | |||
| 1022 | struct usb_device *udev; | 1022 | struct usb_device *udev; |
| 1023 | unsigned short latency = 0; | 1023 | unsigned short latency = 0; |
| 1024 | int rv = 0; | 1024 | int rv = 0; |
| 1025 | 1025 | ||
| 1026 | udev = to_usb_device(dev); | 1026 | udev = to_usb_device(dev); |
| 1027 | 1027 | ||
| 1028 | dbg("%s",__FUNCTION__); | 1028 | dbg("%s",__FUNCTION__); |
| 1029 | 1029 | ||
| 1030 | rv = usb_control_msg(udev, | 1030 | rv = usb_control_msg(udev, |
| 1031 | usb_rcvctrlpipe(udev, 0), | 1031 | usb_rcvctrlpipe(udev, 0), |
| 1032 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST, | 1032 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST, |
| 1033 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, | 1033 | FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, |
| 1034 | 0, priv->interface, | 1034 | 0, priv->interface, |
| 1035 | (char*) &latency, 1, WDR_TIMEOUT); | 1035 | (char*) &latency, 1, WDR_TIMEOUT); |
| 1036 | 1036 | ||
| 1037 | if (rv < 0) { | 1037 | if (rv < 0) { |
| 1038 | dev_err(dev, "Unable to read latency timer: %i", rv); | 1038 | dev_err(dev, "Unable to read latency timer: %i", rv); |
| 1039 | return -EIO; | 1039 | return -EIO; |
| @@ -1051,23 +1051,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute * | |||
| 1051 | char buf[1]; | 1051 | char buf[1]; |
| 1052 | int v = simple_strtoul(valbuf, NULL, 10); | 1052 | int v = simple_strtoul(valbuf, NULL, 10); |
| 1053 | int rv = 0; | 1053 | int rv = 0; |
| 1054 | 1054 | ||
| 1055 | udev = to_usb_device(dev); | 1055 | udev = to_usb_device(dev); |
| 1056 | 1056 | ||
| 1057 | dbg("%s: setting latency timer = %i", __FUNCTION__, v); | 1057 | dbg("%s: setting latency timer = %i", __FUNCTION__, v); |
| 1058 | 1058 | ||
| 1059 | rv = usb_control_msg(udev, | 1059 | rv = usb_control_msg(udev, |
| 1060 | usb_sndctrlpipe(udev, 0), | 1060 | usb_sndctrlpipe(udev, 0), |
| 1061 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST, | 1061 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST, |
| 1062 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, | 1062 | FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, |
| 1063 | v, priv->interface, | 1063 | v, priv->interface, |
| 1064 | buf, 0, WDR_TIMEOUT); | 1064 | buf, 0, WDR_TIMEOUT); |
| 1065 | 1065 | ||
| 1066 | if (rv < 0) { | 1066 | if (rv < 0) { |
| 1067 | dev_err(dev, "Unable to write latency timer: %i", rv); | 1067 | dev_err(dev, "Unable to write latency timer: %i", rv); |
| 1068 | return -EIO; | 1068 | return -EIO; |
| 1069 | } | 1069 | } |
| 1070 | 1070 | ||
| 1071 | return count; | 1071 | return count; |
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| @@ -1082,23 +1082,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att | |||
| 1082 | char buf[1]; | 1082 | char buf[1]; |
| 1083 | int v = simple_strtoul(valbuf, NULL, 10); | 1083 | int v = simple_strtoul(valbuf, NULL, 10); |
| 1084 | int rv = 0; | 1084 | int rv = 0; |
| 1085 | 1085 | ||
| 1086 | udev = to_usb_device(dev); | 1086 | udev = to_usb_device(dev); |
| 1087 | 1087 | ||
| 1088 | dbg("%s: setting event char = %i", __FUNCTION__, v); | 1088 | dbg("%s: setting event char = %i", __FUNCTION__, v); |
| 1089 | 1089 | ||
| 1090 | rv = usb_control_msg(udev, | 1090 | rv = usb_control_msg(udev, |
| 1091 | usb_sndctrlpipe(udev, 0), | 1091 | usb_sndctrlpipe(udev, 0), |
| 1092 | FTDI_SIO_SET_EVENT_CHAR_REQUEST, | 1092 | FTDI_SIO_SET_EVENT_CHAR_REQUEST, |
| 1093 | FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, | 1093 | FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, |
| 1094 | v, priv->interface, | 1094 | v, priv->interface, |
| 1095 | buf, 0, WDR_TIMEOUT); | 1095 | buf, 0, WDR_TIMEOUT); |
| 1096 | 1096 | ||
| 1097 | if (rv < 0) { | 1097 | if (rv < 0) { |
| 1098 | dbg("Unable to write event character: %i", rv); | 1098 | dbg("Unable to write event character: %i", rv); |
| 1099 | return -EIO; | 1099 | return -EIO; |
| 1100 | } | 1100 | } |
| 1101 | 1101 | ||
| 1102 | return count; | 1102 | return count; |
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| @@ -1135,11 +1135,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial) | |||
| 1135 | struct ftdi_private *priv; | 1135 | struct ftdi_private *priv; |
| 1136 | struct usb_device *udev; | 1136 | struct usb_device *udev; |
| 1137 | 1137 | ||
| 1138 | dbg("%s",__FUNCTION__); | 1138 | dbg("%s",__FUNCTION__); |
| 1139 | 1139 | ||
| 1140 | priv = usb_get_serial_port_data(serial->port[0]); | 1140 | priv = usb_get_serial_port_data(serial->port[0]); |
| 1141 | udev = serial->dev; | 1141 | udev = serial->dev; |
| 1142 | 1142 | ||
| 1143 | /* XXX see create_sysfs_attrs */ | 1143 | /* XXX see create_sysfs_attrs */ |
| 1144 | if (priv->chip_type != SIO) { | 1144 | if (priv->chip_type != SIO) { |
| 1145 | device_remove_file(&udev->dev, &dev_attr_event_char); | 1145 | device_remove_file(&udev->dev, &dev_attr_event_char); |
| @@ -1147,7 +1147,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial) | |||
| 1147 | device_remove_file(&udev->dev, &dev_attr_latency_timer); | 1147 | device_remove_file(&udev->dev, &dev_attr_latency_timer); |
| 1148 | } | 1148 | } |
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| 1151 | } | 1151 | } |
| 1152 | 1152 | ||
| 1153 | /* | 1153 | /* |
| @@ -1258,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) | |||
| 1258 | } /* ftdi_HE_TIRA1_setup */ | 1258 | } /* ftdi_HE_TIRA1_setup */ |
| 1259 | 1259 | ||
| 1260 | 1260 | ||
| 1261 | /* ftdi_shutdown is called from usbserial:usb_serial_disconnect | 1261 | /* ftdi_shutdown is called from usbserial:usb_serial_disconnect |
| 1262 | * it is called when the usb device is disconnected | 1262 | * it is called when the usb device is disconnected |
| 1263 | * | 1263 | * |
| 1264 | * usbserial:usb_serial_disconnect | 1264 | * usbserial:usb_serial_disconnect |
| @@ -1269,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) | |||
| 1269 | 1269 | ||
| 1270 | static void ftdi_shutdown (struct usb_serial *serial) | 1270 | static void ftdi_shutdown (struct usb_serial *serial) |
| 1271 | { /* ftdi_shutdown */ | 1271 | { /* ftdi_shutdown */ |
| 1272 | 1272 | ||
| 1273 | struct usb_serial_port *port = serial->port[0]; | 1273 | struct usb_serial_port *port = serial->port[0]; |
| 1274 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1274 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
| 1275 | 1275 | ||
| 1276 | dbg("%s", __FUNCTION__); | 1276 | dbg("%s", __FUNCTION__); |
| 1277 | 1277 | ||
| 1278 | remove_sysfs_attrs(serial); | 1278 | remove_sysfs_attrs(serial); |
| 1279 | 1279 | ||
| 1280 | /* all open ports are closed at this point | 1280 | /* all open ports are closed at this point |
| 1281 | * (by usbserial.c:__serial_close, which calls ftdi_close) | 1281 | * (by usbserial.c:__serial_close, which calls ftdi_close) |
| 1282 | */ | 1282 | */ |
| 1283 | 1283 | ||
| 1284 | if (priv) { | 1284 | if (priv) { |
| @@ -1293,7 +1293,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
| 1293 | struct usb_device *dev = port->serial->dev; | 1293 | struct usb_device *dev = port->serial->dev; |
| 1294 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1294 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
| 1295 | unsigned long flags; | 1295 | unsigned long flags; |
| 1296 | 1296 | ||
| 1297 | int result = 0; | 1297 | int result = 0; |
| 1298 | char buf[1]; /* Needed for the usb_control_msg I think */ | 1298 | char buf[1]; /* Needed for the usb_control_msg I think */ |
| 1299 | 1299 | ||
| @@ -1312,8 +1312,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
| 1312 | /* No error checking for this (will get errors later anyway) */ | 1312 | /* No error checking for this (will get errors later anyway) */ |
| 1313 | /* See ftdi_sio.h for description of what is reset */ | 1313 | /* See ftdi_sio.h for description of what is reset */ |
| 1314 | usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1314 | usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
| 1315 | FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, | 1315 | FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, |
| 1316 | FTDI_SIO_RESET_SIO, | 1316 | FTDI_SIO_RESET_SIO, |
| 1317 | priv->interface, buf, 0, WDR_TIMEOUT); | 1317 | priv->interface, buf, 0, WDR_TIMEOUT); |
| 1318 | 1318 | ||
| 1319 | /* Termios defaults are set by usb_serial_init. We don't change | 1319 | /* 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) | |||
| 1350 | 1350 | ||
| 1351 | 1351 | ||
| 1352 | 1352 | ||
| 1353 | /* | 1353 | /* |
| 1354 | * usbserial:__serial_close only calls ftdi_close if the point is open | 1354 | * usbserial:__serial_close only calls ftdi_close if the point is open |
| 1355 | * | 1355 | * |
| 1356 | * This only gets called when it is the last close | 1356 | * This only gets called when it is the last close |
| 1357 | * | 1357 | * |
| 1358 | * | 1358 | * |
| 1359 | */ | 1359 | */ |
| 1360 | 1360 | ||
| 1361 | static void ftdi_close (struct usb_serial_port *port, struct file *filp) | 1361 | 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) | |||
| 1368 | 1368 | ||
| 1369 | if (c_cflag & HUPCL){ | 1369 | if (c_cflag & HUPCL){ |
| 1370 | /* Disable flow control */ | 1370 | /* Disable flow control */ |
| 1371 | if (usb_control_msg(port->serial->dev, | 1371 | if (usb_control_msg(port->serial->dev, |
| 1372 | usb_sndctrlpipe(port->serial->dev, 0), | 1372 | usb_sndctrlpipe(port->serial->dev, 0), |
| 1373 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | 1373 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, |
| 1374 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | 1374 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, |
| 1375 | 0, priv->interface, buf, 0, | 1375 | 0, priv->interface, buf, 0, |
| 1376 | WDR_TIMEOUT) < 0) { | 1376 | WDR_TIMEOUT) < 0) { |
| 1377 | err("error from flowcontrol urb"); | 1377 | err("error from flowcontrol urb"); |
| 1378 | } | 1378 | } |
| 1379 | 1379 | ||
| 1380 | /* drop RTS and DTR */ | 1380 | /* drop RTS and DTR */ |
| 1381 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | 1381 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
| @@ -1384,14 +1384,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) | |||
| 1384 | /* cancel any scheduled reading */ | 1384 | /* cancel any scheduled reading */ |
| 1385 | cancel_delayed_work(&priv->rx_work); | 1385 | cancel_delayed_work(&priv->rx_work); |
| 1386 | flush_scheduled_work(); | 1386 | flush_scheduled_work(); |
| 1387 | 1387 | ||
| 1388 | /* shutdown our bulk read */ | 1388 | /* shutdown our bulk read */ |
| 1389 | if (port->read_urb) | 1389 | if (port->read_urb) |
| 1390 | usb_kill_urb(port->read_urb); | 1390 | usb_kill_urb(port->read_urb); |
| 1391 | } /* ftdi_close */ | 1391 | } /* ftdi_close */ |
| 1392 | 1392 | ||
| 1393 | 1393 | ||
| 1394 | 1394 | ||
| 1395 | /* The SIO requires the first byte to have: | 1395 | /* The SIO requires the first byte to have: |
| 1396 | * B0 1 | 1396 | * B0 1 |
| 1397 | * B1 0 | 1397 | * B1 0 |
| @@ -1423,7 +1423,7 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1423 | return 0; | 1423 | return 0; |
| 1424 | } | 1424 | } |
| 1425 | spin_unlock_irqrestore(&priv->tx_lock, flags); | 1425 | spin_unlock_irqrestore(&priv->tx_lock, flags); |
| 1426 | 1426 | ||
| 1427 | data_offset = priv->write_offset; | 1427 | data_offset = priv->write_offset; |
| 1428 | dbg("data_offset set to %d",data_offset); | 1428 | dbg("data_offset set to %d",data_offset); |
| 1429 | 1429 | ||
| @@ -1462,7 +1462,7 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1462 | user_pktsz = todo; | 1462 | user_pktsz = todo; |
| 1463 | } | 1463 | } |
| 1464 | /* Write the control byte at the front of the packet*/ | 1464 | /* Write the control byte at the front of the packet*/ |
| 1465 | *first_byte = 1 | ((user_pktsz) << 2); | 1465 | *first_byte = 1 | ((user_pktsz) << 2); |
| 1466 | /* Copy data for packet */ | 1466 | /* Copy data for packet */ |
| 1467 | memcpy (first_byte + data_offset, | 1467 | memcpy (first_byte + data_offset, |
| 1468 | current_position, user_pktsz); | 1468 | current_position, user_pktsz); |
| @@ -1479,7 +1479,7 @@ static int ftdi_write (struct usb_serial_port *port, | |||
| 1479 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); | 1479 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); |
| 1480 | 1480 | ||
| 1481 | /* fill the buffer and send it */ | 1481 | /* fill the buffer and send it */ |
| 1482 | usb_fill_bulk_urb(urb, port->serial->dev, | 1482 | usb_fill_bulk_urb(urb, port->serial->dev, |
| 1483 | usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), | 1483 | usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), |
| 1484 | buffer, transfer_size, | 1484 | buffer, transfer_size, |
| 1485 | ftdi_write_bulk_callback, port); | 1485 | ftdi_write_bulk_callback, port); |
| @@ -1520,7 +1520,7 @@ static void ftdi_write_bulk_callback (struct urb *urb) | |||
| 1520 | kfree (urb->transfer_buffer); | 1520 | kfree (urb->transfer_buffer); |
| 1521 | 1521 | ||
| 1522 | dbg("%s - port %d", __FUNCTION__, port->number); | 1522 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 1523 | 1523 | ||
| 1524 | if (urb->status) { | 1524 | if (urb->status) { |
| 1525 | dbg("nonzero write bulk status received: %d", urb->status); | 1525 | dbg("nonzero write bulk status received: %d", urb->status); |
| 1526 | return; | 1526 | return; |
| @@ -1651,7 +1651,7 @@ static void ftdi_process_read (void *param) | |||
| 1651 | struct tty_struct *tty; | 1651 | struct tty_struct *tty; |
| 1652 | struct ftdi_private *priv; | 1652 | struct ftdi_private *priv; |
| 1653 | char error_flag; | 1653 | char error_flag; |
| 1654 | unsigned char *data; | 1654 | unsigned char *data; |
| 1655 | 1655 | ||
| 1656 | int i; | 1656 | int i; |
| 1657 | int result; | 1657 | int result; |
| @@ -1759,7 +1759,7 @@ static void ftdi_process_read (void *param) | |||
| 1759 | } | 1759 | } |
| 1760 | if (length > 0) { | 1760 | if (length > 0) { |
| 1761 | for (i = 2; i < length+2; i++) { | 1761 | for (i = 2; i < length+2; i++) { |
| 1762 | /* Note that the error flag is duplicated for | 1762 | /* Note that the error flag is duplicated for |
| 1763 | every character received since we don't know | 1763 | every character received since we don't know |
| 1764 | which character it applied to */ | 1764 | which character it applied to */ |
| 1765 | tty_insert_flip_char(tty, data[packet_offset+i], error_flag); | 1765 | tty_insert_flip_char(tty, data[packet_offset+i], error_flag); |
| @@ -1773,7 +1773,7 @@ static void ftdi_process_read (void *param) | |||
| 1773 | This doesn't work well since the application receives a never | 1773 | This doesn't work well since the application receives a never |
| 1774 | ending stream of bad data - even though new data hasn't been sent. | 1774 | ending stream of bad data - even though new data hasn't been sent. |
| 1775 | Therefore I (bill) have taken this out. | 1775 | Therefore I (bill) have taken this out. |
| 1776 | However - this might make sense for framing errors and so on | 1776 | However - this might make sense for framing errors and so on |
| 1777 | so I am leaving the code in for now. | 1777 | so I am leaving the code in for now. |
| 1778 | */ | 1778 | */ |
| 1779 | else { | 1779 | else { |
| @@ -1827,7 +1827,7 @@ static void ftdi_process_read (void *param) | |||
| 1827 | /* if the port is closed stop trying to read */ | 1827 | /* if the port is closed stop trying to read */ |
| 1828 | if (port->open_count > 0){ | 1828 | if (port->open_count > 0){ |
| 1829 | /* Continue trying to always read */ | 1829 | /* Continue trying to always read */ |
| 1830 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | 1830 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, |
| 1831 | usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), | 1831 | usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), |
| 1832 | port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, | 1832 | port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, |
| 1833 | ftdi_read_bulk_callback, port); | 1833 | ftdi_read_bulk_callback, port); |
| @@ -1844,9 +1844,9 @@ static void ftdi_process_read (void *param) | |||
| 1844 | static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) | 1844 | static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) |
| 1845 | { | 1845 | { |
| 1846 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1846 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
| 1847 | __u16 urb_value = 0; | 1847 | __u16 urb_value = 0; |
| 1848 | char buf[1]; | 1848 | char buf[1]; |
| 1849 | 1849 | ||
| 1850 | /* break_state = -1 to turn on break, and 0 to turn off break */ | 1850 | /* break_state = -1 to turn on break, and 0 to turn off break */ |
| 1851 | /* see drivers/char/tty_io.c to see it used */ | 1851 | /* see drivers/char/tty_io.c to see it used */ |
| 1852 | /* last_set_data_urb_value NEVER has the break bit set in it */ | 1852 | /* 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 ) | |||
| 1854 | if (break_state) { | 1854 | if (break_state) { |
| 1855 | urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; | 1855 | urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; |
| 1856 | } else { | 1856 | } else { |
| 1857 | urb_value = priv->last_set_data_urb_value; | 1857 | urb_value = priv->last_set_data_urb_value; |
| 1858 | } | 1858 | } |
| 1859 | 1859 | ||
| 1860 | 1860 | ||
| 1861 | if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), | 1861 | if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), |
| 1862 | FTDI_SIO_SET_DATA_REQUEST, | 1862 | FTDI_SIO_SET_DATA_REQUEST, |
| 1863 | FTDI_SIO_SET_DATA_REQUEST_TYPE, | 1863 | FTDI_SIO_SET_DATA_REQUEST_TYPE, |
| 1864 | urb_value , priv->interface, | 1864 | urb_value , priv->interface, |
| 1865 | buf, 0, WDR_TIMEOUT) < 0) { | 1865 | buf, 0, WDR_TIMEOUT) < 0) { |
| 1866 | err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); | 1866 | err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); |
| 1867 | } | 1867 | } |
| 1868 | 1868 | ||
| 1869 | dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value); | 1869 | dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value); |
| 1870 | 1870 | ||
| 1871 | } | 1871 | } |
| 1872 | 1872 | ||
| 1873 | 1873 | ||
| @@ -1883,12 +1883,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
| 1883 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1883 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
| 1884 | __u16 urb_value; /* will hold the new flags */ | 1884 | __u16 urb_value; /* will hold the new flags */ |
| 1885 | char buf[1]; /* Perhaps I should dynamically alloc this? */ | 1885 | char buf[1]; /* Perhaps I should dynamically alloc this? */ |
| 1886 | 1886 | ||
| 1887 | // Added for xon/xoff support | 1887 | // Added for xon/xoff support |
| 1888 | unsigned int iflag = port->tty->termios->c_iflag; | 1888 | unsigned int iflag = port->tty->termios->c_iflag; |
| 1889 | unsigned char vstop; | 1889 | unsigned char vstop; |
| 1890 | unsigned char vstart; | 1890 | unsigned char vstart; |
| 1891 | 1891 | ||
| 1892 | dbg("%s", __FUNCTION__); | 1892 | dbg("%s", __FUNCTION__); |
| 1893 | 1893 | ||
| 1894 | /* Force baud rate if this device requires it, unless it is set to B0. */ | 1894 | /* 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_ | |||
| 1906 | 1906 | ||
| 1907 | cflag = port->tty->termios->c_cflag; | 1907 | cflag = port->tty->termios->c_cflag; |
| 1908 | 1908 | ||
| 1909 | /* FIXME -For this cut I don't care if the line is really changing or | 1909 | /* FIXME -For this cut I don't care if the line is really changing or |
| 1910 | not - so just do the change regardless - should be able to | 1910 | not - so just do the change regardless - should be able to |
| 1911 | compare old_termios and tty->termios */ | 1911 | compare old_termios and tty->termios */ |
| 1912 | /* NOTE These routines can get interrupted by | 1912 | /* NOTE These routines can get interrupted by |
| 1913 | ftdi_sio_read_bulk_callback - need to examine what this | 1913 | ftdi_sio_read_bulk_callback - need to examine what this |
| 1914 | means - don't see any problems yet */ | 1914 | means - don't see any problems yet */ |
| 1915 | 1915 | ||
| 1916 | /* Set number of data bits, parity, stop bits */ | 1916 | /* Set number of data bits, parity, stop bits */ |
| 1917 | 1917 | ||
| 1918 | urb_value = 0; | 1918 | urb_value = 0; |
| 1919 | urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : | 1919 | urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : |
| 1920 | FTDI_SIO_SET_DATA_STOP_BITS_1); | 1920 | FTDI_SIO_SET_DATA_STOP_BITS_1); |
| 1921 | urb_value |= (cflag & PARENB ? | 1921 | urb_value |= (cflag & PARENB ? |
| 1922 | (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : | 1922 | (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : |
| 1923 | FTDI_SIO_SET_DATA_PARITY_EVEN) : | 1923 | FTDI_SIO_SET_DATA_PARITY_EVEN) : |
| 1924 | FTDI_SIO_SET_DATA_PARITY_NONE); | 1924 | FTDI_SIO_SET_DATA_PARITY_NONE); |
| 1925 | if (cflag & CSIZE) { | 1925 | if (cflag & CSIZE) { |
| @@ -1936,25 +1936,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
| 1936 | /* This is needed by the break command since it uses the same command - but is | 1936 | /* This is needed by the break command since it uses the same command - but is |
| 1937 | * or'ed with this value */ | 1937 | * or'ed with this value */ |
| 1938 | priv->last_set_data_urb_value = urb_value; | 1938 | priv->last_set_data_urb_value = urb_value; |
| 1939 | 1939 | ||
| 1940 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1940 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
| 1941 | FTDI_SIO_SET_DATA_REQUEST, | 1941 | FTDI_SIO_SET_DATA_REQUEST, |
| 1942 | FTDI_SIO_SET_DATA_REQUEST_TYPE, | 1942 | FTDI_SIO_SET_DATA_REQUEST_TYPE, |
| 1943 | urb_value , priv->interface, | 1943 | urb_value , priv->interface, |
| 1944 | buf, 0, WDR_SHORT_TIMEOUT) < 0) { | 1944 | buf, 0, WDR_SHORT_TIMEOUT) < 0) { |
| 1945 | err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); | 1945 | err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); |
| 1946 | } | 1946 | } |
| 1947 | 1947 | ||
| 1948 | /* Now do the baudrate */ | 1948 | /* Now do the baudrate */ |
| 1949 | if ((cflag & CBAUD) == B0 ) { | 1949 | if ((cflag & CBAUD) == B0 ) { |
| 1950 | /* Disable flow control */ | 1950 | /* Disable flow control */ |
| 1951 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1951 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
| 1952 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | 1952 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, |
| 1953 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | 1953 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, |
| 1954 | 0, priv->interface, | 1954 | 0, priv->interface, |
| 1955 | buf, 0, WDR_TIMEOUT) < 0) { | 1955 | buf, 0, WDR_TIMEOUT) < 0) { |
| 1956 | err("%s error from disable flowcontrol urb", __FUNCTION__); | 1956 | err("%s error from disable flowcontrol urb", __FUNCTION__); |
| 1957 | } | 1957 | } |
| 1958 | /* Drop RTS and DTR */ | 1958 | /* Drop RTS and DTR */ |
| 1959 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | 1959 | clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
| 1960 | } else { | 1960 | } else { |
| @@ -1972,16 +1972,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
| 1972 | /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ | 1972 | /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ |
| 1973 | if (cflag & CRTSCTS) { | 1973 | if (cflag & CRTSCTS) { |
| 1974 | dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); | 1974 | dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); |
| 1975 | if (usb_control_msg(dev, | 1975 | if (usb_control_msg(dev, |
| 1976 | usb_sndctrlpipe(dev, 0), | 1976 | usb_sndctrlpipe(dev, 0), |
| 1977 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | 1977 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, |
| 1978 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | 1978 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, |
| 1979 | 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), | 1979 | 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), |
| 1980 | buf, 0, WDR_TIMEOUT) < 0) { | 1980 | buf, 0, WDR_TIMEOUT) < 0) { |
| 1981 | err("urb failed to set to rts/cts flow control"); | 1981 | err("urb failed to set to rts/cts flow control"); |
| 1982 | } | 1982 | } |
| 1983 | 1983 | ||
| 1984 | } else { | 1984 | } else { |
| 1985 | /* | 1985 | /* |
| 1986 | * Xon/Xoff code | 1986 | * Xon/Xoff code |
| 1987 | * | 1987 | * |
| @@ -2011,16 +2011,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
| 2011 | /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ | 2011 | /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ |
| 2012 | /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ | 2012 | /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ |
| 2013 | dbg("%s Turning off hardware flow control", __FUNCTION__); | 2013 | dbg("%s Turning off hardware flow control", __FUNCTION__); |
| 2014 | if (usb_control_msg(dev, | 2014 | if (usb_control_msg(dev, |
| 2015 | usb_sndctrlpipe(dev, 0), | 2015 | usb_sndctrlpipe(dev, 0), |
| 2016 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, | 2016 | FTDI_SIO_SET_FLOW_CTRL_REQUEST, |
| 2017 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, | 2017 | FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, |
| 2018 | 0, priv->interface, | 2018 | 0, priv->interface, |
| 2019 | buf, 0, WDR_TIMEOUT) < 0) { | 2019 | buf, 0, WDR_TIMEOUT) < 0) { |
| 2020 | err("urb failed to clear flow control"); | 2020 | err("urb failed to clear flow control"); |
| 2021 | } | 2021 | } |
| 2022 | } | 2022 | } |
| 2023 | 2023 | ||
| 2024 | } | 2024 | } |
| 2025 | return; | 2025 | return; |
| 2026 | } /* ftdi_termios */ | 2026 | } /* ftdi_termios */ |
| @@ -2036,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) | |||
| 2036 | switch (priv->chip_type) { | 2036 | switch (priv->chip_type) { |
| 2037 | case SIO: | 2037 | case SIO: |
| 2038 | /* Request the status from the device */ | 2038 | /* Request the status from the device */ |
| 2039 | if ((ret = usb_control_msg(port->serial->dev, | 2039 | if ((ret = usb_control_msg(port->serial->dev, |
| 2040 | usb_rcvctrlpipe(port->serial->dev, 0), | 2040 | usb_rcvctrlpipe(port->serial->dev, 0), |
| 2041 | FTDI_SIO_GET_MODEM_STATUS_REQUEST, | 2041 | FTDI_SIO_GET_MODEM_STATUS_REQUEST, |
| 2042 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | 2042 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, |
| 2043 | 0, 0, | 2043 | 0, 0, |
| 2044 | buf, 1, WDR_TIMEOUT)) < 0 ) { | 2044 | buf, 1, WDR_TIMEOUT)) < 0 ) { |
| 2045 | err("%s Could not get modem status of device - err: %d", __FUNCTION__, | 2045 | err("%s Could not get modem status of device - err: %d", __FUNCTION__, |
| 2046 | ret); | 2046 | ret); |
| @@ -2052,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) | |||
| 2052 | case FT2232C: | 2052 | case FT2232C: |
| 2053 | /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same | 2053 | /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same |
| 2054 | format as the data returned from the in point */ | 2054 | format as the data returned from the in point */ |
| 2055 | if ((ret = usb_control_msg(port->serial->dev, | 2055 | if ((ret = usb_control_msg(port->serial->dev, |
| 2056 | usb_rcvctrlpipe(port->serial->dev, 0), | 2056 | usb_rcvctrlpipe(port->serial->dev, 0), |
| 2057 | FTDI_SIO_GET_MODEM_STATUS_REQUEST, | 2057 | FTDI_SIO_GET_MODEM_STATUS_REQUEST, |
| 2058 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | 2058 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, |
| 2059 | 0, priv->interface, | 2059 | 0, priv->interface, |
| 2060 | buf, 2, WDR_TIMEOUT)) < 0 ) { | 2060 | buf, 2, WDR_TIMEOUT)) < 0 ) { |
| 2061 | err("%s Could not get modem status of device - err: %d", __FUNCTION__, | 2061 | err("%s Could not get modem status of device - err: %d", __FUNCTION__, |
| 2062 | ret); | 2062 | ret); |
| @@ -2067,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) | |||
| 2067 | return -EFAULT; | 2067 | return -EFAULT; |
| 2068 | break; | 2068 | break; |
| 2069 | } | 2069 | } |
| 2070 | 2070 | ||
| 2071 | return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | | 2071 | return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | |
| 2072 | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | | 2072 | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | |
| 2073 | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | | 2073 | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | |
| 2074 | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | | 2074 | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | |
| 2075 | priv->last_dtr_rts; | 2075 | priv->last_dtr_rts; |
| 2076 | } | 2076 | } |
| 2077 | 2077 | ||
| 2078 | static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) | 2078 | 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 | |||
| 2138 | break; | 2138 | break; |
| 2139 | default: | 2139 | default: |
| 2140 | break; | 2140 | break; |
| 2141 | 2141 | ||
| 2142 | } | 2142 | } |
| 2143 | 2143 | ||
| 2144 | 2144 | ||
| 2145 | /* This is not necessarily an error - turns out the higher layers will do | 2145 | /* This is not necessarily an error - turns out the higher layers will do |
| 2146 | * some ioctls itself (see comment above) | 2146 | * some ioctls itself (see comment above) |
| 2147 | */ | 2147 | */ |
| 2148 | dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd); | 2148 | 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) | |||
| 2199 | if (retval) | 2199 | if (retval) |
| 2200 | goto failed_sio_register; | 2200 | goto failed_sio_register; |
| 2201 | retval = usb_register(&ftdi_driver); | 2201 | retval = usb_register(&ftdi_driver); |
| 2202 | if (retval) | 2202 | if (retval) |
| 2203 | goto failed_usb_register; | 2203 | goto failed_usb_register; |
| 2204 | 2204 | ||
| 2205 | info(DRIVER_VERSION ":" DRIVER_DESC); | 2205 | info(DRIVER_VERSION ":" DRIVER_DESC); |
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c new file mode 100644 index 000000000000..82cd15b894b0 --- /dev/null +++ b/drivers/usb/serial/mos7720.c | |||
| @@ -0,0 +1,1683 @@ | |||
| 1 | /* | ||
| 2 | * mos7720.c | ||
| 3 | * Controls the Moschip 7720 usb to dual port serial convertor | ||
| 4 | * | ||
| 5 | * Copyright 2006 Moschip Semiconductor Tech. Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation, version 2 of the License. | ||
| 10 | * | ||
| 11 | * Developed by: | ||
| 12 | * VijayaKumar.G.N. <vijaykumar@aspirecom.net> | ||
| 13 | * AjayKumar <ajay@aspirecom.net> | ||
| 14 | * Gurudeva.N. <gurudev@aspirecom.net> | ||
| 15 | * | ||
| 16 | * Cleaned up from the original by: | ||
| 17 | * Greg Kroah-Hartman <gregkh@suse.de> | ||
| 18 | * | ||
| 19 | * Originally based on drivers/usb/serial/io_edgeport.c which is: | ||
| 20 | * Copyright (C) 2000 Inside Out Networks, All rights reserved. | ||
| 21 | * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> | ||
| 22 | */ | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/tty.h> | ||
| 28 | #include <linux/tty_driver.h> | ||
| 29 | #include <linux/tty_flip.h> | ||
| 30 | #include <linux/module.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 32 | #include <linux/serial.h> | ||
| 33 | #include <linux/serial_reg.h> | ||
| 34 | #include <linux/usb.h> | ||
| 35 | #include <linux/usb/serial.h> | ||
| 36 | #include <asm/uaccess.h> | ||
| 37 | |||
| 38 | |||
| 39 | /* | ||
| 40 | * Version Information | ||
| 41 | */ | ||
| 42 | #define DRIVER_VERSION "1.0.0.4F" | ||
| 43 | #define DRIVER_AUTHOR "Aspire Communications pvt Ltd." | ||
| 44 | #define DRIVER_DESC "Moschip USB Serial Driver" | ||
| 45 | |||
| 46 | /* default urb timeout */ | ||
| 47 | #define MOS_WDR_TIMEOUT (HZ * 5) | ||
| 48 | |||
| 49 | #define MOS_PORT1 0x0200 | ||
| 50 | #define MOS_PORT2 0x0300 | ||
| 51 | #define MOS_VENREG 0x0000 | ||
| 52 | #define MOS_MAX_PORT 0x02 | ||
| 53 | #define MOS_WRITE 0x0E | ||
| 54 | #define MOS_READ 0x0D | ||
| 55 | |||
| 56 | /* Interrupt Rotinue Defines */ | ||
| 57 | #define SERIAL_IIR_RLS 0x06 | ||
| 58 | #define SERIAL_IIR_RDA 0x04 | ||
| 59 | #define SERIAL_IIR_CTI 0x0c | ||
| 60 | #define SERIAL_IIR_THR 0x02 | ||
| 61 | #define SERIAL_IIR_MS 0x00 | ||
| 62 | |||
| 63 | #define NUM_URBS 16 /* URB Count */ | ||
| 64 | #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ | ||
| 65 | |||
| 66 | /* This structure holds all of the local port information */ | ||
| 67 | struct moschip_port | ||
| 68 | { | ||
| 69 | __u8 shadowLCR; /* last LCR value received */ | ||
| 70 | __u8 shadowMCR; /* last MCR value received */ | ||
| 71 | __u8 shadowMSR; /* last MSR value received */ | ||
| 72 | char open; | ||
| 73 | struct async_icount icount; | ||
| 74 | struct usb_serial_port *port; /* loop back to the owner */ | ||
| 75 | struct urb *write_urb_pool[NUM_URBS]; | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* This structure holds all of the individual serial device information */ | ||
| 79 | struct moschip_serial | ||
| 80 | { | ||
| 81 | int interrupt_started; | ||
| 82 | }; | ||
| 83 | |||
| 84 | static int debug; | ||
| 85 | |||
| 86 | #define USB_VENDOR_ID_MOSCHIP 0x9710 | ||
| 87 | #define MOSCHIP_DEVICE_ID_7720 0x7720 | ||
| 88 | #define MOSCHIP_DEVICE_ID_7715 0x7715 | ||
| 89 | |||
| 90 | static struct usb_device_id moschip_port_id_table [] = { | ||
| 91 | { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) }, | ||
| 92 | { } /* terminating entry */ | ||
| 93 | }; | ||
| 94 | MODULE_DEVICE_TABLE(usb, moschip_port_id_table); | ||
| 95 | |||
| 96 | |||
| 97 | /* | ||
| 98 | * mos7720_interrupt_callback | ||
| 99 | * this is the callback function for when we have received data on the | ||
| 100 | * interrupt endpoint. | ||
| 101 | */ | ||
| 102 | static void mos7720_interrupt_callback(struct urb *urb) | ||
| 103 | { | ||
| 104 | int result; | ||
| 105 | int length; | ||
| 106 | __u32 *data; | ||
| 107 | unsigned int status; | ||
| 108 | __u8 sp1; | ||
| 109 | __u8 sp2; | ||
| 110 | __u8 st; | ||
| 111 | |||
| 112 | dbg("%s"," : Entering\n"); | ||
| 113 | |||
| 114 | if (!urb) { | ||
| 115 | dbg("%s","Invalid Pointer !!!!:\n"); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | switch (urb->status) { | ||
| 120 | case 0: | ||
| 121 | /* success */ | ||
| 122 | break; | ||
| 123 | case -ECONNRESET: | ||
| 124 | case -ENOENT: | ||
| 125 | case -ESHUTDOWN: | ||
| 126 | /* this urb is terminated, clean up */ | ||
| 127 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, | ||
| 128 | urb->status); | ||
| 129 | return; | ||
| 130 | default: | ||
| 131 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, | ||
| 132 | urb->status); | ||
| 133 | goto exit; | ||
| 134 | } | ||
| 135 | |||
| 136 | length = urb->actual_length; | ||
| 137 | data = urb->transfer_buffer; | ||
| 138 | |||
| 139 | /* Moschip get 4 bytes | ||
| 140 | * Byte 1 IIR Port 1 (port.number is 0) | ||
| 141 | * Byte 2 IIR Port 2 (port.number is 1) | ||
| 142 | * Byte 3 -------------- | ||
| 143 | * Byte 4 FIFO status for both */ | ||
| 144 | if (length && length > 4) { | ||
| 145 | dbg("Wrong data !!!"); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | |||
| 149 | status = *data; | ||
| 150 | |||
| 151 | sp1 = (status & 0xff000000)>>24; | ||
| 152 | sp2 = (status & 0x00ff0000)>>16; | ||
| 153 | st = status & 0x000000ff; | ||
| 154 | |||
| 155 | if ((sp1 & 0x01) || (sp2 & 0x01)) { | ||
| 156 | /* No Interrupt Pending in both the ports */ | ||
| 157 | dbg("No Interrupt !!!"); | ||
| 158 | } else { | ||
| 159 | switch (sp1 & 0x0f) { | ||
| 160 | case SERIAL_IIR_RLS: | ||
| 161 | dbg("Serial Port 1: Receiver status error or address " | ||
| 162 | "bit detected in 9-bit mode\n"); | ||
| 163 | break; | ||
| 164 | case SERIAL_IIR_CTI: | ||
| 165 | dbg("Serial Port 1: Receiver time out"); | ||
| 166 | break; | ||
| 167 | case SERIAL_IIR_MS: | ||
| 168 | dbg("Serial Port 1: Modem status change"); | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | |||
| 172 | switch (sp2 & 0x0f) { | ||
| 173 | case SERIAL_IIR_RLS: | ||
| 174 | dbg("Serial Port 2: Receiver status error or address " | ||
| 175 | "bit detected in 9-bit mode"); | ||
| 176 | break; | ||
| 177 | case SERIAL_IIR_CTI: | ||
| 178 | dbg("Serial Port 2: Receiver time out"); | ||
| 179 | break; | ||
| 180 | case SERIAL_IIR_MS: | ||
| 181 | dbg("Serial Port 2: Modem status change"); | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | exit: | ||
| 187 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 188 | if (result) | ||
| 189 | dev_err(&urb->dev->dev, | ||
| 190 | "%s - Error %d submitting control urb\n", | ||
| 191 | __FUNCTION__, result); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* | ||
| 196 | * mos7720_bulk_in_callback | ||
| 197 | * this is the callback function for when we have received data on the | ||
| 198 | * bulk in endpoint. | ||
| 199 | */ | ||
| 200 | static void mos7720_bulk_in_callback(struct urb *urb) | ||
| 201 | { | ||
| 202 | int status; | ||
| 203 | unsigned char *data ; | ||
| 204 | struct usb_serial_port *port; | ||
| 205 | struct moschip_port *mos7720_port; | ||
| 206 | struct tty_struct *tty; | ||
| 207 | |||
| 208 | if (urb->status) { | ||
| 209 | dbg("nonzero read bulk status received: %d",urb->status); | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | mos7720_port = urb->context; | ||
| 214 | if (!mos7720_port) { | ||
| 215 | dbg("%s","NULL mos7720_port pointer \n"); | ||
| 216 | return ; | ||
| 217 | } | ||
| 218 | |||
| 219 | port = mos7720_port->port; | ||
| 220 | |||
| 221 | dbg("Entering...%s", __FUNCTION__); | ||
| 222 | |||
| 223 | data = urb->transfer_buffer; | ||
| 224 | |||
| 225 | tty = port->tty; | ||
| 226 | if (tty && urb->actual_length) { | ||
| 227 | tty_buffer_request_room(tty, urb->actual_length); | ||
| 228 | tty_insert_flip_string(tty, data, urb->actual_length); | ||
| 229 | tty_flip_buffer_push(tty); | ||
| 230 | } | ||
| 231 | |||
| 232 | if (!port->read_urb) { | ||
| 233 | dbg("URB KILLED !!!"); | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (port->read_urb->status != -EINPROGRESS) { | ||
| 238 | port->read_urb->dev = port->serial->dev; | ||
| 239 | |||
| 240 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
| 241 | if (status) | ||
| 242 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
| 243 | status); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | /* | ||
| 248 | * mos7720_bulk_out_data_callback | ||
| 249 | * this is the callback function for when we have finished sending serial | ||
| 250 | * data on the bulk out endpoint. | ||
| 251 | */ | ||
| 252 | static void mos7720_bulk_out_data_callback(struct urb *urb) | ||
| 253 | { | ||
| 254 | struct moschip_port *mos7720_port; | ||
| 255 | struct tty_struct *tty; | ||
| 256 | |||
| 257 | if (urb->status) { | ||
| 258 | dbg("nonzero write bulk status received:%d", urb->status); | ||
| 259 | return; | ||
| 260 | } | ||
| 261 | |||
| 262 | mos7720_port = urb->context; | ||
| 263 | if (!mos7720_port) { | ||
| 264 | dbg("NULL mos7720_port pointer"); | ||
| 265 | return ; | ||
| 266 | } | ||
| 267 | |||
| 268 | dbg("Entering ........."); | ||
| 269 | |||
| 270 | tty = mos7720_port->port->tty; | ||
| 271 | |||
| 272 | if (tty && mos7720_port->open) { | ||
| 273 | /* let the tty driver wakeup if it has a special * | ||
| 274 | * write_wakeup function */ | ||
| 275 | if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | ||
| 276 | tty->ldisc.write_wakeup) | ||
| 277 | (tty->ldisc.write_wakeup)(tty); | ||
| 278 | |||
| 279 | /* tell the tty driver that something has changed */ | ||
| 280 | wake_up_interruptible(&tty->write_wait); | ||
| 281 | } | ||
| 282 | |||
| 283 | /* schedule_work(&mos7720_port->port->work); */ | ||
| 284 | } | ||
| 285 | |||
| 286 | /* | ||
| 287 | * send_mos_cmd | ||
| 288 | * this function will be used for sending command to device | ||
| 289 | */ | ||
| 290 | static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, | ||
| 291 | __u16 index, void *data) | ||
| 292 | { | ||
| 293 | int status; | ||
| 294 | unsigned int pipe; | ||
| 295 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
| 296 | __u8 requesttype; | ||
| 297 | __u16 size = 0x0000; | ||
| 298 | |||
| 299 | if (value < MOS_MAX_PORT) { | ||
| 300 | if (product == MOSCHIP_DEVICE_ID_7715) { | ||
| 301 | value = value*0x100+0x100; | ||
| 302 | } else { | ||
| 303 | value = value*0x100+0x200; | ||
| 304 | } | ||
| 305 | } else { | ||
| 306 | value = 0x0000; | ||
| 307 | if ((product == MOSCHIP_DEVICE_ID_7715) && | ||
| 308 | (index != 0x08)) { | ||
| 309 | dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); | ||
| 310 | //index = 0x01 ; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | if (request == MOS_WRITE) { | ||
| 315 | request = (__u8)MOS_WRITE; | ||
| 316 | requesttype = (__u8)0x40; | ||
| 317 | value = value + (__u16)*((unsigned char *)data); | ||
| 318 | data = NULL; | ||
| 319 | pipe = usb_sndctrlpipe(serial->dev, 0); | ||
| 320 | } else { | ||
| 321 | request = (__u8)MOS_READ; | ||
| 322 | requesttype = (__u8)0xC0; | ||
| 323 | size = 0x01; | ||
| 324 | pipe = usb_rcvctrlpipe(serial->dev,0); | ||
| 325 | } | ||
| 326 | |||
| 327 | status = usb_control_msg(serial->dev, pipe, request, requesttype, | ||
| 328 | value, index, data, size, MOS_WDR_TIMEOUT); | ||
| 329 | |||
| 330 | if (status < 0) | ||
| 331 | dbg("Command Write failed Value %x index %x\n",value,index); | ||
| 332 | |||
| 333 | return status; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int mos7720_open(struct usb_serial_port *port, struct file * filp) | ||
| 337 | { | ||
| 338 | struct usb_serial *serial; | ||
| 339 | struct usb_serial_port *port0; | ||
| 340 | struct urb *urb; | ||
| 341 | struct moschip_serial *mos7720_serial; | ||
| 342 | struct moschip_port *mos7720_port; | ||
| 343 | int response; | ||
| 344 | int port_number; | ||
| 345 | char data; | ||
| 346 | int j; | ||
| 347 | |||
| 348 | serial = port->serial; | ||
| 349 | |||
| 350 | mos7720_port = usb_get_serial_port_data(port); | ||
| 351 | if (mos7720_port == NULL) | ||
| 352 | return -ENODEV; | ||
| 353 | |||
| 354 | port0 = serial->port[0]; | ||
| 355 | |||
| 356 | mos7720_serial = usb_get_serial_data(serial); | ||
| 357 | |||
| 358 | if (mos7720_serial == NULL || port0 == NULL) | ||
| 359 | return -ENODEV; | ||
| 360 | |||
| 361 | usb_clear_halt(serial->dev, port->write_urb->pipe); | ||
| 362 | usb_clear_halt(serial->dev, port->read_urb->pipe); | ||
| 363 | |||
| 364 | /* Initialising the write urb pool */ | ||
| 365 | for (j = 0; j < NUM_URBS; ++j) { | ||
| 366 | urb = usb_alloc_urb(0,SLAB_ATOMIC); | ||
| 367 | mos7720_port->write_urb_pool[j] = urb; | ||
| 368 | |||
| 369 | if (urb == NULL) { | ||
| 370 | err("No more urbs???"); | ||
| 371 | continue; | ||
| 372 | } | ||
| 373 | |||
| 374 | urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, | ||
| 375 | GFP_KERNEL); | ||
| 376 | if (!urb->transfer_buffer) { | ||
| 377 | err("%s-out of memory for urb buffers.", __FUNCTION__); | ||
| 378 | continue; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | /* Initialize MCS7720 -- Write Init values to corresponding Registers | ||
| 383 | * | ||
| 384 | * Register Index | ||
| 385 | * 1 : IER | ||
| 386 | * 2 : FCR | ||
| 387 | * 3 : LCR | ||
| 388 | * 4 : MCR | ||
| 389 | * | ||
| 390 | * 0x08 : SP1/2 Control Reg | ||
| 391 | */ | ||
| 392 | port_number = port->number - port->serial->minor; | ||
| 393 | send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); | ||
| 394 | dbg("SS::%p LSR:%x\n",mos7720_port, data); | ||
| 395 | |||
| 396 | dbg("Check:Sending Command .........."); | ||
| 397 | |||
| 398 | data = 0x02; | ||
| 399 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); | ||
| 400 | data = 0x02; | ||
| 401 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); | ||
| 402 | |||
| 403 | data = 0x00; | ||
| 404 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 405 | data = 0x00; | ||
| 406 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
| 407 | |||
| 408 | data = 0xCF; | ||
| 409 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
| 410 | data = 0x03; | ||
| 411 | mos7720_port->shadowLCR = data; | ||
| 412 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
| 413 | data = 0x0b; | ||
| 414 | mos7720_port->shadowMCR = data; | ||
| 415 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 416 | data = 0x0b; | ||
| 417 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 418 | |||
| 419 | data = 0x00; | ||
| 420 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
| 421 | data = 0x00; | ||
| 422 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
| 423 | |||
| 424 | /* data = 0x00; | ||
| 425 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); | ||
| 426 | data = 0x03; | ||
| 427 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); | ||
| 428 | data = 0x00; | ||
| 429 | send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); | ||
| 430 | */ | ||
| 431 | data = 0x00; | ||
| 432 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
| 433 | |||
| 434 | data = data | (port->number - port->serial->minor + 1); | ||
| 435 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
| 436 | |||
| 437 | data = 0x83; | ||
| 438 | mos7720_port->shadowLCR = data; | ||
| 439 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
| 440 | data = 0x0c; | ||
| 441 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); | ||
| 442 | data = 0x00; | ||
| 443 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 444 | data = 0x03; | ||
| 445 | mos7720_port->shadowLCR = data; | ||
| 446 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
| 447 | data = 0x0c; | ||
| 448 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 449 | data = 0x0c; | ||
| 450 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 451 | |||
| 452 | //Matrix | ||
| 453 | |||
| 454 | /* force low_latency on so that our tty_push actually forces * | ||
| 455 | * the data through,otherwise it is scheduled, and with * | ||
| 456 | * high data rates (like with OHCI) data can get lost. */ | ||
| 457 | |||
| 458 | if (port->tty) | ||
| 459 | port->tty->low_latency = 1; | ||
| 460 | |||
| 461 | /* see if we've set up our endpoint info yet * | ||
| 462 | * (can't set it up in mos7720_startup as the * | ||
| 463 | * structures were not set up at that time.) */ | ||
| 464 | if (!mos7720_serial->interrupt_started) { | ||
| 465 | dbg("Interrupt buffer NULL !!!"); | ||
| 466 | |||
| 467 | /* not set up yet, so do it now */ | ||
| 468 | mos7720_serial->interrupt_started = 1; | ||
| 469 | |||
| 470 | dbg("To Submit URB !!!"); | ||
| 471 | |||
| 472 | /* set up our interrupt urb */ | ||
| 473 | usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, | ||
| 474 | usb_rcvintpipe(serial->dev, | ||
| 475 | port->interrupt_in_endpointAddress), | ||
| 476 | port0->interrupt_in_buffer, | ||
| 477 | port0->interrupt_in_urb->transfer_buffer_length, | ||
| 478 | mos7720_interrupt_callback, mos7720_port, | ||
| 479 | port0->interrupt_in_urb->interval); | ||
| 480 | |||
| 481 | /* start interrupt read for this mos7720 this interrupt * | ||
| 482 | * will continue as long as the mos7720 is connected */ | ||
| 483 | dbg("Submit URB over !!!"); | ||
| 484 | response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); | ||
| 485 | if (response) | ||
| 486 | dev_err(&port->dev, | ||
| 487 | "%s - Error %d submitting control urb", | ||
| 488 | __FUNCTION__, response); | ||
| 489 | } | ||
| 490 | |||
| 491 | /* set up our bulk in urb */ | ||
| 492 | usb_fill_bulk_urb(port->read_urb, serial->dev, | ||
| 493 | usb_rcvbulkpipe(serial->dev, | ||
| 494 | port->bulk_in_endpointAddress), | ||
| 495 | port->bulk_in_buffer, | ||
| 496 | port->read_urb->transfer_buffer_length, | ||
| 497 | mos7720_bulk_in_callback, mos7720_port); | ||
| 498 | response = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
| 499 | if (response) | ||
| 500 | dev_err(&port->dev, | ||
| 501 | "%s - Error %d submitting read urb", __FUNCTION__, response); | ||
| 502 | |||
| 503 | /* initialize our icount structure */ | ||
| 504 | memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); | ||
| 505 | |||
| 506 | /* initialize our port settings */ | ||
| 507 | mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ | ||
| 508 | |||
| 509 | /* send a open port command */ | ||
| 510 | mos7720_port->open = 1; | ||
| 511 | |||
| 512 | return 0; | ||
| 513 | } | ||
| 514 | |||
| 515 | /* | ||
| 516 | * mos7720_chars_in_buffer | ||
| 517 | * this function is called by the tty driver when it wants to know how many | ||
| 518 | * bytes of data we currently have outstanding in the port (data that has | ||
| 519 | * been written, but hasn't made it out the port yet) | ||
| 520 | * If successful, we return the number of bytes left to be written in the | ||
| 521 | * system, | ||
| 522 | * Otherwise we return a negative error number. | ||
| 523 | */ | ||
| 524 | static int mos7720_chars_in_buffer(struct usb_serial_port *port) | ||
| 525 | { | ||
| 526 | int i; | ||
| 527 | int chars = 0; | ||
| 528 | struct moschip_port *mos7720_port; | ||
| 529 | |||
| 530 | dbg("%s:entering ...........", __FUNCTION__); | ||
| 531 | |||
| 532 | mos7720_port = usb_get_serial_port_data(port); | ||
| 533 | if (mos7720_port == NULL) { | ||
| 534 | dbg("%s:leaving ...........", __FUNCTION__); | ||
| 535 | return -ENODEV; | ||
| 536 | } | ||
| 537 | |||
| 538 | for (i = 0; i < NUM_URBS; ++i) { | ||
| 539 | if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) | ||
| 540 | chars += URB_TRANSFER_BUFFER_SIZE; | ||
| 541 | } | ||
| 542 | dbg("%s - returns %d", __FUNCTION__, chars); | ||
| 543 | return chars; | ||
| 544 | } | ||
| 545 | |||
| 546 | static void mos7720_close(struct usb_serial_port *port, struct file *filp) | ||
| 547 | { | ||
| 548 | struct usb_serial *serial; | ||
| 549 | struct moschip_port *mos7720_port; | ||
| 550 | char data; | ||
| 551 | int j; | ||
| 552 | |||
| 553 | dbg("mos7720_close:entering..."); | ||
| 554 | |||
| 555 | serial = port->serial; | ||
| 556 | |||
| 557 | mos7720_port = usb_get_serial_port_data(port); | ||
| 558 | if (mos7720_port == NULL) | ||
| 559 | return; | ||
| 560 | |||
| 561 | for (j = 0; j < NUM_URBS; ++j) | ||
| 562 | usb_kill_urb(mos7720_port->write_urb_pool[j]); | ||
| 563 | |||
| 564 | /* Freeing Write URBs */ | ||
| 565 | for (j = 0; j < NUM_URBS; ++j) { | ||
| 566 | if (mos7720_port->write_urb_pool[j]) { | ||
| 567 | kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); | ||
| 568 | usb_free_urb(mos7720_port->write_urb_pool[j]); | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 572 | /* While closing port, shutdown all bulk read, write * | ||
| 573 | * and interrupt read if they exists */ | ||
| 574 | if (serial->dev) { | ||
| 575 | dbg("Shutdown bulk write"); | ||
| 576 | usb_kill_urb(port->write_urb); | ||
| 577 | dbg("Shutdown bulk read"); | ||
| 578 | usb_kill_urb(port->read_urb); | ||
| 579 | } | ||
| 580 | |||
| 581 | data = 0x00; | ||
| 582 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
| 583 | 0x04, &data); | ||
| 584 | |||
| 585 | data = 0x00; | ||
| 586 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
| 587 | 0x01, &data); | ||
| 588 | |||
| 589 | mos7720_port->open = 0; | ||
| 590 | |||
| 591 | dbg("Leaving %s", __FUNCTION__); | ||
| 592 | } | ||
| 593 | |||
| 594 | static void mos7720_break(struct usb_serial_port *port, int break_state) | ||
| 595 | { | ||
| 596 | unsigned char data; | ||
| 597 | struct usb_serial *serial; | ||
| 598 | struct moschip_port *mos7720_port; | ||
| 599 | |||
| 600 | dbg("Entering %s", __FUNCTION__); | ||
| 601 | |||
| 602 | serial = port->serial; | ||
| 603 | |||
| 604 | mos7720_port = usb_get_serial_port_data(port); | ||
| 605 | if (mos7720_port == NULL) | ||
| 606 | return; | ||
| 607 | |||
| 608 | if (break_state == -1) | ||
| 609 | data = mos7720_port->shadowLCR | UART_LCR_SBC; | ||
| 610 | else | ||
| 611 | data = mos7720_port->shadowLCR & ~UART_LCR_SBC; | ||
| 612 | |||
| 613 | mos7720_port->shadowLCR = data; | ||
| 614 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
| 615 | 0x03, &data); | ||
| 616 | |||
| 617 | return; | ||
| 618 | } | ||
| 619 | |||
| 620 | /* | ||
| 621 | * mos7720_write_room | ||
| 622 | * this function is called by the tty driver when it wants to know how many | ||
| 623 | * bytes of data we can accept for a specific port. | ||
| 624 | * If successful, we return the amount of room that we have for this port | ||
| 625 | * Otherwise we return a negative error number. | ||
| 626 | */ | ||
| 627 | static int mos7720_write_room(struct usb_serial_port *port) | ||
| 628 | { | ||
| 629 | struct moschip_port *mos7720_port; | ||
| 630 | int room = 0; | ||
| 631 | int i; | ||
| 632 | |||
| 633 | dbg("%s:entering ...........", __FUNCTION__); | ||
| 634 | |||
| 635 | mos7720_port = usb_get_serial_port_data(port); | ||
| 636 | if (mos7720_port == NULL) { | ||
| 637 | dbg("%s:leaving ...........", __FUNCTION__); | ||
| 638 | return -ENODEV; | ||
| 639 | } | ||
| 640 | |||
| 641 | for (i = 0; i < NUM_URBS; ++i) { | ||
| 642 | if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) | ||
| 643 | room += URB_TRANSFER_BUFFER_SIZE; | ||
| 644 | } | ||
| 645 | |||
| 646 | dbg("%s - returns %d", __FUNCTION__, room); | ||
| 647 | return room; | ||
| 648 | } | ||
| 649 | |||
| 650 | static int mos7720_write(struct usb_serial_port *port, | ||
| 651 | const unsigned char *data, int count) | ||
| 652 | { | ||
| 653 | int status; | ||
| 654 | int i; | ||
| 655 | int bytes_sent = 0; | ||
| 656 | int transfer_size; | ||
| 657 | |||
| 658 | struct moschip_port *mos7720_port; | ||
| 659 | struct usb_serial *serial; | ||
| 660 | struct urb *urb; | ||
| 661 | const unsigned char *current_position = data; | ||
| 662 | |||
| 663 | dbg("%s:entering ...........", __FUNCTION__); | ||
| 664 | |||
| 665 | serial = port->serial; | ||
| 666 | |||
| 667 | mos7720_port = usb_get_serial_port_data(port); | ||
| 668 | if (mos7720_port == NULL) { | ||
| 669 | dbg("mos7720_port is NULL"); | ||
| 670 | return -ENODEV; | ||
| 671 | } | ||
| 672 | |||
| 673 | /* try to find a free urb in the list */ | ||
| 674 | urb = NULL; | ||
| 675 | |||
| 676 | for (i = 0; i < NUM_URBS; ++i) { | ||
| 677 | if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { | ||
| 678 | urb = mos7720_port->write_urb_pool[i]; | ||
| 679 | dbg("URB:%d",i); | ||
| 680 | break; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | if (urb == NULL) { | ||
| 685 | dbg("%s - no more free urbs", __FUNCTION__); | ||
| 686 | goto exit; | ||
| 687 | } | ||
| 688 | |||
| 689 | if (urb->transfer_buffer == NULL) { | ||
| 690 | urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, | ||
| 691 | GFP_KERNEL); | ||
| 692 | if (urb->transfer_buffer == NULL) { | ||
| 693 | err("%s no more kernel memory...", __FUNCTION__); | ||
| 694 | goto exit; | ||
| 695 | } | ||
| 696 | } | ||
| 697 | transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); | ||
| 698 | |||
| 699 | memcpy(urb->transfer_buffer, current_position, transfer_size); | ||
| 700 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, | ||
| 701 | urb->transfer_buffer); | ||
| 702 | |||
| 703 | /* fill urb with data and submit */ | ||
| 704 | usb_fill_bulk_urb(urb, serial->dev, | ||
| 705 | usb_sndbulkpipe(serial->dev, | ||
| 706 | port->bulk_out_endpointAddress), | ||
| 707 | urb->transfer_buffer, transfer_size, | ||
| 708 | mos7720_bulk_out_data_callback, mos7720_port); | ||
| 709 | |||
| 710 | /* send it down the pipe */ | ||
| 711 | status = usb_submit_urb(urb,GFP_ATOMIC); | ||
| 712 | if (status) { | ||
| 713 | err("%s - usb_submit_urb(write bulk) failed with status = %d", | ||
| 714 | __FUNCTION__, status); | ||
| 715 | bytes_sent = status; | ||
| 716 | goto exit; | ||
| 717 | } | ||
| 718 | bytes_sent = transfer_size; | ||
| 719 | |||
| 720 | exit: | ||
| 721 | return bytes_sent; | ||
| 722 | } | ||
| 723 | |||
| 724 | static void mos7720_throttle(struct usb_serial_port *port) | ||
| 725 | { | ||
| 726 | struct moschip_port *mos7720_port; | ||
| 727 | struct tty_struct *tty; | ||
| 728 | int status; | ||
| 729 | |||
| 730 | dbg("%s- port %d\n", __FUNCTION__, port->number); | ||
| 731 | |||
| 732 | mos7720_port = usb_get_serial_port_data(port); | ||
| 733 | |||
| 734 | if (mos7720_port == NULL) | ||
| 735 | return; | ||
| 736 | |||
| 737 | if (!mos7720_port->open) { | ||
| 738 | dbg("port not opened"); | ||
| 739 | return; | ||
| 740 | } | ||
| 741 | |||
| 742 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 743 | |||
| 744 | tty = port->tty; | ||
| 745 | if (!tty) { | ||
| 746 | dbg("%s - no tty available", __FUNCTION__); | ||
| 747 | return; | ||
| 748 | } | ||
| 749 | |||
| 750 | /* if we are implementing XON/XOFF, send the stop character */ | ||
| 751 | if (I_IXOFF(tty)) { | ||
| 752 | unsigned char stop_char = STOP_CHAR(tty); | ||
| 753 | status = mos7720_write(port, &stop_char, 1); | ||
| 754 | if (status <= 0) | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | |||
| 758 | /* if we are implementing RTS/CTS, toggle that line */ | ||
| 759 | if (tty->termios->c_cflag & CRTSCTS) { | ||
| 760 | mos7720_port->shadowMCR &= ~UART_MCR_RTS; | ||
| 761 | status = send_mos_cmd(port->serial, MOS_WRITE, | ||
| 762 | port->number - port->serial->minor, | ||
| 763 | UART_MCR, &mos7720_port->shadowMCR); | ||
| 764 | if (status != 0) | ||
| 765 | return; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | |||
| 769 | static void mos7720_unthrottle(struct usb_serial_port *port) | ||
| 770 | { | ||
| 771 | struct tty_struct *tty; | ||
| 772 | int status; | ||
| 773 | struct moschip_port *mos7720_port = usb_get_serial_port_data(port); | ||
| 774 | |||
| 775 | if (mos7720_port == NULL) | ||
| 776 | return; | ||
| 777 | |||
| 778 | if (!mos7720_port->open) { | ||
| 779 | dbg("%s - port not opened", __FUNCTION__); | ||
| 780 | return; | ||
| 781 | } | ||
| 782 | |||
| 783 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 784 | |||
| 785 | tty = port->tty; | ||
| 786 | if (!tty) { | ||
| 787 | dbg("%s - no tty available", __FUNCTION__); | ||
| 788 | return; | ||
| 789 | } | ||
| 790 | |||
| 791 | /* if we are implementing XON/XOFF, send the start character */ | ||
| 792 | if (I_IXOFF(tty)) { | ||
| 793 | unsigned char start_char = START_CHAR(tty); | ||
| 794 | status = mos7720_write(port, &start_char, 1); | ||
| 795 | if (status <= 0) | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | |||
| 799 | /* if we are implementing RTS/CTS, toggle that line */ | ||
| 800 | if (tty->termios->c_cflag & CRTSCTS) { | ||
| 801 | mos7720_port->shadowMCR |= UART_MCR_RTS; | ||
| 802 | status = send_mos_cmd(port->serial, MOS_WRITE, | ||
| 803 | port->number - port->serial->minor, | ||
| 804 | UART_MCR, &mos7720_port->shadowMCR); | ||
| 805 | if (status != 0) | ||
| 806 | return; | ||
| 807 | } | ||
| 808 | } | ||
| 809 | |||
| 810 | static int set_higher_rates(struct moschip_port *mos7720_port, | ||
| 811 | unsigned int baud) | ||
| 812 | { | ||
| 813 | unsigned char data; | ||
| 814 | struct usb_serial_port *port; | ||
| 815 | struct usb_serial *serial; | ||
| 816 | int port_number; | ||
| 817 | |||
| 818 | if (mos7720_port == NULL) | ||
| 819 | return -EINVAL; | ||
| 820 | |||
| 821 | port = mos7720_port->port; | ||
| 822 | serial = port->serial; | ||
| 823 | |||
| 824 | /*********************************************** | ||
| 825 | * Init Sequence for higher rates | ||
| 826 | ***********************************************/ | ||
| 827 | dbg("Sending Setting Commands .........."); | ||
| 828 | port_number = port->number - port->serial->minor; | ||
| 829 | |||
| 830 | data = 0x000; | ||
| 831 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 832 | data = 0x000; | ||
| 833 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
| 834 | data = 0x0CF; | ||
| 835 | send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); | ||
| 836 | data = 0x00b; | ||
| 837 | mos7720_port->shadowMCR = data; | ||
| 838 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 839 | data = 0x00b; | ||
| 840 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 841 | |||
| 842 | data = 0x000; | ||
| 843 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
| 844 | data = 0x000; | ||
| 845 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
| 846 | |||
| 847 | |||
| 848 | /*********************************************** | ||
| 849 | * Set for higher rates * | ||
| 850 | ***********************************************/ | ||
| 851 | |||
| 852 | data = baud * 0x10; | ||
| 853 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); | ||
| 854 | |||
| 855 | data = 0x003; | ||
| 856 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
| 857 | data = 0x003; | ||
| 858 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
| 859 | |||
| 860 | data = 0x02b; | ||
| 861 | mos7720_port->shadowMCR = data; | ||
| 862 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 863 | data = 0x02b; | ||
| 864 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 865 | |||
| 866 | /*********************************************** | ||
| 867 | * Set DLL/DLM | ||
| 868 | ***********************************************/ | ||
| 869 | |||
| 870 | data = mos7720_port->shadowLCR | UART_LCR_DLAB; | ||
| 871 | mos7720_port->shadowLCR = data; | ||
| 872 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
| 873 | |||
| 874 | data = 0x001; /* DLL */ | ||
| 875 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); | ||
| 876 | data = 0x000; /* DLM */ | ||
| 877 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
| 878 | |||
| 879 | data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; | ||
| 880 | mos7720_port->shadowLCR = data; | ||
| 881 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
| 882 | |||
| 883 | return 0; | ||
| 884 | } | ||
| 885 | |||
| 886 | /* baud rate information */ | ||
| 887 | struct divisor_table_entry | ||
| 888 | { | ||
| 889 | __u32 baudrate; | ||
| 890 | __u16 divisor; | ||
| 891 | }; | ||
| 892 | |||
| 893 | /* Define table of divisors for moschip 7720 hardware * | ||
| 894 | * These assume a 3.6864MHz crystal, the standard /16, and * | ||
| 895 | * MCR.7 = 0. */ | ||
| 896 | static struct divisor_table_entry divisor_table[] = { | ||
| 897 | { 50, 2304}, | ||
| 898 | { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ | ||
| 899 | { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ | ||
| 900 | { 150, 768}, | ||
| 901 | { 300, 384}, | ||
| 902 | { 600, 192}, | ||
| 903 | { 1200, 96}, | ||
| 904 | { 1800, 64}, | ||
| 905 | { 2400, 48}, | ||
| 906 | { 4800, 24}, | ||
| 907 | { 7200, 16}, | ||
| 908 | { 9600, 12}, | ||
| 909 | { 19200, 6}, | ||
| 910 | { 38400, 3}, | ||
| 911 | { 57600, 2}, | ||
| 912 | { 115200, 1}, | ||
| 913 | }; | ||
| 914 | |||
| 915 | /***************************************************************************** | ||
| 916 | * calc_baud_rate_divisor | ||
| 917 | * this function calculates the proper baud rate divisor for the specified | ||
| 918 | * baud rate. | ||
| 919 | *****************************************************************************/ | ||
| 920 | static int calc_baud_rate_divisor(int baudrate, int *divisor) | ||
| 921 | { | ||
| 922 | int i; | ||
| 923 | __u16 custom; | ||
| 924 | __u16 round1; | ||
| 925 | __u16 round; | ||
| 926 | |||
| 927 | |||
| 928 | dbg("%s - %d", __FUNCTION__, baudrate); | ||
| 929 | |||
| 930 | for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { | ||
| 931 | if (divisor_table[i].baudrate == baudrate) { | ||
| 932 | *divisor = divisor_table[i].divisor; | ||
| 933 | return 0; | ||
| 934 | } | ||
| 935 | } | ||
| 936 | |||
| 937 | /* After trying for all the standard baud rates * | ||
| 938 | * Try calculating the divisor for this baud rate */ | ||
| 939 | if (baudrate > 75 && baudrate < 230400) { | ||
| 940 | /* get the divisor */ | ||
| 941 | custom = (__u16)(230400L / baudrate); | ||
| 942 | |||
| 943 | /* Check for round off */ | ||
| 944 | round1 = (__u16)(2304000L / baudrate); | ||
| 945 | round = (__u16)(round1 - (custom * 10)); | ||
| 946 | if (round > 4) | ||
| 947 | custom++; | ||
| 948 | *divisor = custom; | ||
| 949 | |||
| 950 | dbg("Baud %d = %d",baudrate, custom); | ||
| 951 | return 0; | ||
| 952 | } | ||
| 953 | |||
| 954 | dbg("Baud calculation Failed..."); | ||
| 955 | return -EINVAL; | ||
| 956 | } | ||
| 957 | |||
| 958 | /* | ||
| 959 | * send_cmd_write_baud_rate | ||
| 960 | * this function sends the proper command to change the baud rate of the | ||
| 961 | * specified port. | ||
| 962 | */ | ||
| 963 | static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, | ||
| 964 | int baudrate) | ||
| 965 | { | ||
| 966 | struct usb_serial_port *port; | ||
| 967 | struct usb_serial *serial; | ||
| 968 | int divisor; | ||
| 969 | int status; | ||
| 970 | unsigned char data; | ||
| 971 | unsigned char number; | ||
| 972 | |||
| 973 | if (mos7720_port == NULL) | ||
| 974 | return -1; | ||
| 975 | |||
| 976 | port = mos7720_port->port; | ||
| 977 | serial = port->serial; | ||
| 978 | |||
| 979 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 980 | |||
| 981 | number = port->number - port->serial->minor; | ||
| 982 | dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); | ||
| 983 | |||
| 984 | /* Calculate the Divisor */ | ||
| 985 | status = calc_baud_rate_divisor(baudrate, &divisor); | ||
| 986 | if (status) { | ||
| 987 | err("%s - bad baud rate", __FUNCTION__); | ||
| 988 | return status; | ||
| 989 | } | ||
| 990 | |||
| 991 | /* Enable access to divisor latch */ | ||
| 992 | data = mos7720_port->shadowLCR | UART_LCR_DLAB; | ||
| 993 | mos7720_port->shadowLCR = data; | ||
| 994 | send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); | ||
| 995 | |||
| 996 | /* Write the divisor */ | ||
| 997 | data = ((unsigned char)(divisor & 0xff)); | ||
| 998 | send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); | ||
| 999 | |||
| 1000 | data = ((unsigned char)((divisor & 0xff00) >> 8)); | ||
| 1001 | send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); | ||
| 1002 | |||
| 1003 | /* Disable access to divisor latch */ | ||
| 1004 | data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; | ||
| 1005 | mos7720_port->shadowLCR = data; | ||
| 1006 | send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); | ||
| 1007 | |||
| 1008 | return status; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | /* | ||
| 1012 | * change_port_settings | ||
| 1013 | * This routine is called to set the UART on the device to match | ||
| 1014 | * the specified new settings. | ||
| 1015 | */ | ||
| 1016 | static void change_port_settings(struct moschip_port *mos7720_port, | ||
| 1017 | struct termios *old_termios) | ||
| 1018 | { | ||
| 1019 | struct usb_serial_port *port; | ||
| 1020 | struct usb_serial *serial; | ||
| 1021 | struct tty_struct *tty; | ||
| 1022 | int baud; | ||
| 1023 | unsigned cflag; | ||
| 1024 | unsigned iflag; | ||
| 1025 | __u8 mask = 0xff; | ||
| 1026 | __u8 lData; | ||
| 1027 | __u8 lParity; | ||
| 1028 | __u8 lStop; | ||
| 1029 | int status; | ||
| 1030 | int port_number; | ||
| 1031 | char data; | ||
| 1032 | |||
| 1033 | if (mos7720_port == NULL) | ||
| 1034 | return ; | ||
| 1035 | |||
| 1036 | port = mos7720_port->port; | ||
| 1037 | serial = port->serial; | ||
| 1038 | port_number = port->number - port->serial->minor; | ||
| 1039 | |||
| 1040 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
| 1041 | |||
| 1042 | if (!mos7720_port->open) { | ||
| 1043 | dbg("%s - port not opened", __FUNCTION__); | ||
| 1044 | return; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | tty = mos7720_port->port->tty; | ||
| 1048 | |||
| 1049 | if ((!tty) || (!tty->termios)) { | ||
| 1050 | dbg("%s - no tty structures", __FUNCTION__); | ||
| 1051 | return; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 1055 | |||
| 1056 | lData = UART_LCR_WLEN8; | ||
| 1057 | lStop = 0x00; /* 1 stop bit */ | ||
| 1058 | lParity = 0x00; /* No parity */ | ||
| 1059 | |||
| 1060 | cflag = tty->termios->c_cflag; | ||
| 1061 | iflag = tty->termios->c_iflag; | ||
| 1062 | |||
| 1063 | /* Change the number of bits */ | ||
| 1064 | switch (cflag & CSIZE) { | ||
| 1065 | case CS5: | ||
| 1066 | lData = UART_LCR_WLEN5; | ||
| 1067 | mask = 0x1f; | ||
| 1068 | break; | ||
| 1069 | |||
| 1070 | case CS6: | ||
| 1071 | lData = UART_LCR_WLEN6; | ||
| 1072 | mask = 0x3f; | ||
| 1073 | break; | ||
| 1074 | |||
| 1075 | case CS7: | ||
| 1076 | lData = UART_LCR_WLEN7; | ||
| 1077 | mask = 0x7f; | ||
| 1078 | break; | ||
| 1079 | default: | ||
| 1080 | case CS8: | ||
| 1081 | lData = UART_LCR_WLEN8; | ||
| 1082 | break; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | /* Change the Parity bit */ | ||
| 1086 | if (cflag & PARENB) { | ||
| 1087 | if (cflag & PARODD) { | ||
| 1088 | lParity = UART_LCR_PARITY; | ||
| 1089 | dbg("%s - parity = odd", __FUNCTION__); | ||
| 1090 | } else { | ||
| 1091 | lParity = (UART_LCR_EPAR | UART_LCR_PARITY); | ||
| 1092 | dbg("%s - parity = even", __FUNCTION__); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | } else { | ||
| 1096 | dbg("%s - parity = none", __FUNCTION__); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | if (cflag & CMSPAR) | ||
| 1100 | lParity = lParity | 0x20; | ||
| 1101 | |||
| 1102 | /* Change the Stop bit */ | ||
| 1103 | if (cflag & CSTOPB) { | ||
| 1104 | lStop = UART_LCR_STOP; | ||
| 1105 | dbg("%s - stop bits = 2", __FUNCTION__); | ||
| 1106 | } else { | ||
| 1107 | lStop = 0x00; | ||
| 1108 | dbg("%s - stop bits = 1", __FUNCTION__); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | #define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ | ||
| 1112 | #define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ | ||
| 1113 | #define LCR_PAR_MASK 0x38 /* Mask for parity field */ | ||
| 1114 | |||
| 1115 | /* Update the LCR with the correct value */ | ||
| 1116 | mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); | ||
| 1117 | mos7720_port->shadowLCR |= (lData | lParity | lStop); | ||
| 1118 | |||
| 1119 | |||
| 1120 | /* Disable Interrupts */ | ||
| 1121 | data = 0x00; | ||
| 1122 | send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data); | ||
| 1123 | |||
| 1124 | data = 0x00; | ||
| 1125 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); | ||
| 1126 | |||
| 1127 | data = 0xcf; | ||
| 1128 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); | ||
| 1129 | |||
| 1130 | /* Send the updated LCR value to the mos7720 */ | ||
| 1131 | data = mos7720_port->shadowLCR; | ||
| 1132 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); | ||
| 1133 | |||
| 1134 | data = 0x00b; | ||
| 1135 | mos7720_port->shadowMCR = data; | ||
| 1136 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 1137 | data = 0x00b; | ||
| 1138 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
| 1139 | |||
| 1140 | /* set up the MCR register and send it to the mos7720 */ | ||
| 1141 | mos7720_port->shadowMCR = UART_MCR_OUT2; | ||
| 1142 | if (cflag & CBAUD) | ||
| 1143 | mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); | ||
| 1144 | |||
| 1145 | if (cflag & CRTSCTS) { | ||
| 1146 | mos7720_port->shadowMCR |= (UART_MCR_XONANY); | ||
| 1147 | |||
| 1148 | /* To set hardware flow control to the specified * | ||
| 1149 | * serial port, in SP1/2_CONTROL_REG */ | ||
| 1150 | if (port->number) { | ||
| 1151 | data = 0x001; | ||
| 1152 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, | ||
| 1153 | 0x08, &data); | ||
| 1154 | } else { | ||
| 1155 | data = 0x002; | ||
| 1156 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, | ||
| 1157 | 0x08, &data); | ||
| 1158 | } | ||
| 1159 | } else { | ||
| 1160 | mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | data = mos7720_port->shadowMCR; | ||
| 1164 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); | ||
| 1165 | |||
| 1166 | /* Determine divisor based on baud rate */ | ||
| 1167 | baud = tty_get_baud_rate(tty); | ||
| 1168 | if (!baud) { | ||
| 1169 | /* pick a default, any default... */ | ||
| 1170 | dbg("Picked default baud..."); | ||
| 1171 | baud = 9600; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | if (baud >= 230400) { | ||
| 1175 | set_higher_rates(mos7720_port, baud); | ||
| 1176 | /* Enable Interrupts */ | ||
| 1177 | data = 0x0c; | ||
| 1178 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); | ||
| 1179 | return; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | dbg("%s - baud rate = %d", __FUNCTION__, baud); | ||
| 1183 | status = send_cmd_write_baud_rate(mos7720_port, baud); | ||
| 1184 | |||
| 1185 | /* Enable Interrupts */ | ||
| 1186 | data = 0x0c; | ||
| 1187 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); | ||
| 1188 | |||
| 1189 | if (port->read_urb->status != -EINPROGRESS) { | ||
| 1190 | port->read_urb->dev = serial->dev; | ||
| 1191 | |||
| 1192 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
| 1193 | if (status) | ||
| 1194 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
| 1195 | status); | ||
| 1196 | } | ||
| 1197 | return; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | /* | ||
| 1201 | * mos7720_set_termios | ||
| 1202 | * this function is called by the tty driver when it wants to change the | ||
| 1203 | * termios structure. | ||
| 1204 | */ | ||
| 1205 | static void mos7720_set_termios(struct usb_serial_port *port, | ||
| 1206 | struct termios *old_termios) | ||
| 1207 | { | ||
| 1208 | int status; | ||
| 1209 | unsigned int cflag; | ||
| 1210 | struct usb_serial *serial; | ||
| 1211 | struct moschip_port *mos7720_port; | ||
| 1212 | struct tty_struct *tty; | ||
| 1213 | |||
| 1214 | serial = port->serial; | ||
| 1215 | |||
| 1216 | mos7720_port = usb_get_serial_port_data(port); | ||
| 1217 | |||
| 1218 | if (mos7720_port == NULL) | ||
| 1219 | return; | ||
| 1220 | |||
| 1221 | tty = port->tty; | ||
| 1222 | |||
| 1223 | if (!port->tty || !port->tty->termios) { | ||
| 1224 | dbg("%s - no tty or termios", __FUNCTION__); | ||
| 1225 | return; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | if (!mos7720_port->open) { | ||
| 1229 | dbg("%s - port not opened", __FUNCTION__); | ||
| 1230 | return; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | dbg("%s\n","setting termios - ASPIRE"); | ||
| 1234 | |||
| 1235 | cflag = tty->termios->c_cflag; | ||
| 1236 | |||
| 1237 | if (!cflag) { | ||
| 1238 | printk("%s %s\n",__FUNCTION__,"cflag is NULL"); | ||
| 1239 | return; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | /* check that they really want us to change something */ | ||
| 1243 | if (old_termios) { | ||
| 1244 | if ((cflag == old_termios->c_cflag) && | ||
| 1245 | (RELEVANT_IFLAG(tty->termios->c_iflag) == | ||
| 1246 | RELEVANT_IFLAG(old_termios->c_iflag))) { | ||
| 1247 | dbg("Nothing to change"); | ||
| 1248 | return; | ||
| 1249 | } | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | dbg("%s - clfag %08x iflag %08x", __FUNCTION__, | ||
| 1253 | tty->termios->c_cflag, | ||
| 1254 | RELEVANT_IFLAG(tty->termios->c_iflag)); | ||
| 1255 | |||
| 1256 | if (old_termios) | ||
| 1257 | dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, | ||
| 1258 | old_termios->c_cflag, | ||
| 1259 | RELEVANT_IFLAG(old_termios->c_iflag)); | ||
| 1260 | |||
| 1261 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
| 1262 | |||
| 1263 | /* change the port settings to the new ones specified */ | ||
| 1264 | change_port_settings(mos7720_port, old_termios); | ||
| 1265 | |||
| 1266 | if(!port->read_urb) { | ||
| 1267 | dbg("%s","URB KILLED !!!!!\n"); | ||
| 1268 | return; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | if(port->read_urb->status != -EINPROGRESS) { | ||
| 1272 | port->read_urb->dev = serial->dev; | ||
| 1273 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
| 1274 | if (status) | ||
| 1275 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
| 1276 | status); | ||
| 1277 | } | ||
| 1278 | return; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | /* | ||
| 1282 | * get_lsr_info - get line status register info | ||
| 1283 | * | ||
| 1284 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
| 1285 | * is emptied. On bus types like RS485, the transmitter must | ||
| 1286 | * release the bus after transmitting. This must be done when | ||
| 1287 | * the transmit shift register is empty, not be done when the | ||
| 1288 | * transmit holding register is empty. This functionality | ||
| 1289 | * allows an RS485 driver to be written in user space. | ||
| 1290 | */ | ||
| 1291 | static int get_lsr_info(struct moschip_port *mos7720_port, | ||
| 1292 | unsigned int __user *value) | ||
| 1293 | { | ||
| 1294 | int count; | ||
| 1295 | unsigned int result = 0; | ||
| 1296 | |||
| 1297 | count = mos7720_chars_in_buffer(mos7720_port->port); | ||
| 1298 | if (count == 0) { | ||
| 1299 | dbg("%s -- Empty", __FUNCTION__); | ||
| 1300 | result = TIOCSER_TEMT; | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | if (copy_to_user(value, &result, sizeof(int))) | ||
| 1304 | return -EFAULT; | ||
| 1305 | return 0; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | /* | ||
| 1309 | * get_number_bytes_avail - get number of bytes available | ||
| 1310 | * | ||
| 1311 | * Purpose: Let user call ioctl to get the count of number of bytes available. | ||
| 1312 | */ | ||
| 1313 | static int get_number_bytes_avail(struct moschip_port *mos7720_port, | ||
| 1314 | unsigned int __user *value) | ||
| 1315 | { | ||
| 1316 | unsigned int result = 0; | ||
| 1317 | struct tty_struct *tty = mos7720_port->port->tty; | ||
| 1318 | |||
| 1319 | if (!tty) | ||
| 1320 | return -ENOIOCTLCMD; | ||
| 1321 | |||
| 1322 | result = tty->read_cnt; | ||
| 1323 | |||
| 1324 | dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result); | ||
| 1325 | if (copy_to_user(value, &result, sizeof(int))) | ||
| 1326 | return -EFAULT; | ||
| 1327 | |||
| 1328 | return -ENOIOCTLCMD; | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, | ||
| 1332 | unsigned int __user *value) | ||
| 1333 | { | ||
| 1334 | unsigned int mcr ; | ||
| 1335 | unsigned int arg; | ||
| 1336 | unsigned char data; | ||
| 1337 | |||
| 1338 | struct usb_serial_port *port; | ||
| 1339 | |||
| 1340 | if (mos7720_port == NULL) | ||
| 1341 | return -1; | ||
| 1342 | |||
| 1343 | port = (struct usb_serial_port*)mos7720_port->port; | ||
| 1344 | mcr = mos7720_port->shadowMCR; | ||
| 1345 | |||
| 1346 | if (copy_from_user(&arg, value, sizeof(int))) | ||
| 1347 | return -EFAULT; | ||
| 1348 | |||
| 1349 | switch (cmd) { | ||
| 1350 | case TIOCMBIS: | ||
| 1351 | if (arg & TIOCM_RTS) | ||
| 1352 | mcr |= UART_MCR_RTS; | ||
| 1353 | if (arg & TIOCM_DTR) | ||
| 1354 | mcr |= UART_MCR_RTS; | ||
| 1355 | if (arg & TIOCM_LOOP) | ||
| 1356 | mcr |= UART_MCR_LOOP; | ||
| 1357 | break; | ||
| 1358 | |||
| 1359 | case TIOCMBIC: | ||
| 1360 | if (arg & TIOCM_RTS) | ||
| 1361 | mcr &= ~UART_MCR_RTS; | ||
| 1362 | if (arg & TIOCM_DTR) | ||
| 1363 | mcr &= ~UART_MCR_RTS; | ||
| 1364 | if (arg & TIOCM_LOOP) | ||
| 1365 | mcr &= ~UART_MCR_LOOP; | ||
| 1366 | break; | ||
| 1367 | |||
| 1368 | case TIOCMSET: | ||
| 1369 | /* turn off the RTS and DTR and LOOPBACK | ||
| 1370 | * and then only turn on what was asked to */ | ||
| 1371 | mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); | ||
| 1372 | mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); | ||
| 1373 | mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); | ||
| 1374 | mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); | ||
| 1375 | break; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | mos7720_port->shadowMCR = mcr; | ||
| 1379 | |||
| 1380 | data = mos7720_port->shadowMCR; | ||
| 1381 | send_mos_cmd(port->serial, MOS_WRITE, | ||
| 1382 | port->number - port->serial->minor, UART_MCR, &data); | ||
| 1383 | |||
| 1384 | return 0; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | static int get_modem_info(struct moschip_port *mos7720_port, | ||
| 1388 | unsigned int __user *value) | ||
| 1389 | { | ||
| 1390 | unsigned int result = 0; | ||
| 1391 | unsigned int msr = mos7720_port->shadowMSR; | ||
| 1392 | unsigned int mcr = mos7720_port->shadowMCR; | ||
| 1393 | |||
| 1394 | result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ||
| 1395 | | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ | ||
| 1396 | | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ | ||
| 1397 | | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ | ||
| 1398 | | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ||
| 1399 | | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ | ||
| 1400 | |||
| 1401 | |||
| 1402 | dbg("%s -- %x", __FUNCTION__, result); | ||
| 1403 | |||
| 1404 | if (copy_to_user(value, &result, sizeof(int))) | ||
| 1405 | return -EFAULT; | ||
| 1406 | return 0; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | static int get_serial_info(struct moschip_port *mos7720_port, | ||
| 1410 | struct serial_struct __user *retinfo) | ||
| 1411 | { | ||
| 1412 | struct serial_struct tmp; | ||
| 1413 | |||
| 1414 | if (!retinfo) | ||
| 1415 | return -EFAULT; | ||
| 1416 | |||
| 1417 | memset(&tmp, 0, sizeof(tmp)); | ||
| 1418 | |||
| 1419 | tmp.type = PORT_16550A; | ||
| 1420 | tmp.line = mos7720_port->port->serial->minor; | ||
| 1421 | tmp.port = mos7720_port->port->number; | ||
| 1422 | tmp.irq = 0; | ||
| 1423 | tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; | ||
| 1424 | tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; | ||
| 1425 | tmp.baud_base = 9600; | ||
| 1426 | tmp.close_delay = 5*HZ; | ||
| 1427 | tmp.closing_wait = 30*HZ; | ||
| 1428 | |||
| 1429 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
| 1430 | return -EFAULT; | ||
| 1431 | return 0; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | static int mos7720_ioctl(struct usb_serial_port *port, struct file *file, | ||
| 1435 | unsigned int cmd, unsigned long arg) | ||
| 1436 | { | ||
| 1437 | struct moschip_port *mos7720_port; | ||
| 1438 | struct async_icount cnow; | ||
| 1439 | struct async_icount cprev; | ||
| 1440 | struct serial_icounter_struct icount; | ||
| 1441 | |||
| 1442 | mos7720_port = usb_get_serial_port_data(port); | ||
| 1443 | if (mos7720_port == NULL) | ||
| 1444 | return -ENODEV; | ||
| 1445 | |||
| 1446 | dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); | ||
| 1447 | |||
| 1448 | switch (cmd) { | ||
| 1449 | case TIOCINQ: | ||
| 1450 | /* return number of bytes available */ | ||
| 1451 | dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); | ||
| 1452 | return get_number_bytes_avail(mos7720_port, | ||
| 1453 | (unsigned int __user *)arg); | ||
| 1454 | break; | ||
| 1455 | |||
| 1456 | case TIOCSERGETLSR: | ||
| 1457 | dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); | ||
| 1458 | return get_lsr_info(mos7720_port, (unsigned int __user *)arg); | ||
| 1459 | return 0; | ||
| 1460 | |||
| 1461 | case TIOCMBIS: | ||
| 1462 | case TIOCMBIC: | ||
| 1463 | case TIOCMSET: | ||
| 1464 | dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, | ||
| 1465 | port->number); | ||
| 1466 | return set_modem_info(mos7720_port, cmd, | ||
| 1467 | (unsigned int __user *)arg); | ||
| 1468 | |||
| 1469 | case TIOCMGET: | ||
| 1470 | dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); | ||
| 1471 | return get_modem_info(mos7720_port, | ||
| 1472 | (unsigned int __user *)arg); | ||
| 1473 | |||
| 1474 | case TIOCGSERIAL: | ||
| 1475 | dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); | ||
| 1476 | return get_serial_info(mos7720_port, | ||
| 1477 | (struct serial_struct __user *)arg); | ||
| 1478 | |||
| 1479 | case TIOCSSERIAL: | ||
| 1480 | dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); | ||
| 1481 | break; | ||
| 1482 | |||
| 1483 | case TIOCMIWAIT: | ||
| 1484 | dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); | ||
| 1485 | cprev = mos7720_port->icount; | ||
| 1486 | while (1) { | ||
| 1487 | if (signal_pending(current)) | ||
| 1488 | return -ERESTARTSYS; | ||
| 1489 | cnow = mos7720_port->icount; | ||
| 1490 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
| 1491 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) | ||
| 1492 | return -EIO; /* no change => error */ | ||
| 1493 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | ||
| 1494 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | ||
| 1495 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || | ||
| 1496 | ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { | ||
| 1497 | return 0; | ||
| 1498 | } | ||
| 1499 | cprev = cnow; | ||
| 1500 | } | ||
| 1501 | /* NOTREACHED */ | ||
| 1502 | break; | ||
| 1503 | |||
| 1504 | case TIOCGICOUNT: | ||
| 1505 | cnow = mos7720_port->icount; | ||
| 1506 | icount.cts = cnow.cts; | ||
| 1507 | icount.dsr = cnow.dsr; | ||
| 1508 | icount.rng = cnow.rng; | ||
| 1509 | icount.dcd = cnow.dcd; | ||
| 1510 | icount.rx = cnow.rx; | ||
| 1511 | icount.tx = cnow.tx; | ||
| 1512 | icount.frame = cnow.frame; | ||
| 1513 | icount.overrun = cnow.overrun; | ||
| 1514 | icount.parity = cnow.parity; | ||
| 1515 | icount.brk = cnow.brk; | ||
| 1516 | icount.buf_overrun = cnow.buf_overrun; | ||
| 1517 | |||
| 1518 | dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, | ||
| 1519 | port->number, icount.rx, icount.tx ); | ||
| 1520 | if (copy_to_user((void __user *)arg, &icount, sizeof(icount))) | ||
| 1521 | return -EFAULT; | ||
| 1522 | return 0; | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | return -ENOIOCTLCMD; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static int mos7720_startup(struct usb_serial *serial) | ||
| 1529 | { | ||
| 1530 | struct moschip_serial *mos7720_serial; | ||
| 1531 | struct moschip_port *mos7720_port; | ||
| 1532 | struct usb_device *dev; | ||
| 1533 | int i; | ||
| 1534 | char data; | ||
| 1535 | |||
| 1536 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 1537 | |||
| 1538 | if (!serial) { | ||
| 1539 | dbg("Invalid Handler"); | ||
| 1540 | return -ENODEV; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | dev = serial->dev; | ||
| 1544 | |||
| 1545 | /* create our private serial structure */ | ||
| 1546 | mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); | ||
| 1547 | if (mos7720_serial == NULL) { | ||
| 1548 | err("%s - Out of memory", __FUNCTION__); | ||
| 1549 | return -ENOMEM; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | usb_set_serial_data(serial, mos7720_serial); | ||
| 1553 | |||
| 1554 | /* we set up the pointers to the endpoints in the mos7720_open * | ||
| 1555 | * function, as the structures aren't created yet. */ | ||
| 1556 | |||
| 1557 | /* set up port private structures */ | ||
| 1558 | for (i = 0; i < serial->num_ports; ++i) { | ||
| 1559 | mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); | ||
| 1560 | if (mos7720_port == NULL) { | ||
| 1561 | err("%s - Out of memory", __FUNCTION__); | ||
| 1562 | usb_set_serial_data(serial, NULL); | ||
| 1563 | kfree(mos7720_serial); | ||
| 1564 | return -ENOMEM; | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | /* Initialize all port interrupt end point to port 0 int | ||
| 1568 | * endpoint. Our device has only one interrupt endpoint | ||
| 1569 | * comman to all ports */ | ||
| 1570 | serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; | ||
| 1571 | |||
| 1572 | mos7720_port->port = serial->port[i]; | ||
| 1573 | usb_set_serial_port_data(serial->port[i], mos7720_port); | ||
| 1574 | |||
| 1575 | dbg("port number is %d", serial->port[i]->number); | ||
| 1576 | dbg("serial number is %d", serial->minor); | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | |||
| 1580 | /* setting configuration feature to one */ | ||
| 1581 | usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
| 1582 | (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ); | ||
| 1583 | |||
| 1584 | send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1 | ||
| 1585 | dbg("LSR:%x",data); | ||
| 1586 | |||
| 1587 | send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2 | ||
| 1588 | dbg("LSR:%x",data); | ||
| 1589 | |||
| 1590 | return 0; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | static void mos7720_shutdown(struct usb_serial *serial) | ||
| 1594 | { | ||
| 1595 | int i; | ||
| 1596 | |||
| 1597 | /* free private structure allocated for serial port */ | ||
| 1598 | for (i=0; i < serial->num_ports; ++i) { | ||
| 1599 | kfree(usb_get_serial_port_data(serial->port[i])); | ||
| 1600 | usb_set_serial_port_data(serial->port[i], NULL); | ||
| 1601 | } | ||
| 1602 | |||
| 1603 | /* free private structure allocated for serial device */ | ||
| 1604 | kfree(usb_get_serial_data(serial)); | ||
| 1605 | usb_set_serial_data(serial, NULL); | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | static struct usb_serial_driver moschip7720_2port_driver = { | ||
| 1609 | .driver = { | ||
| 1610 | .owner = THIS_MODULE, | ||
| 1611 | .name = "moschip7720", | ||
| 1612 | }, | ||
| 1613 | .description = "Moschip 2 port adapter", | ||
| 1614 | .id_table = moschip_port_id_table, | ||
| 1615 | .num_interrupt_in = 1, | ||
| 1616 | .num_bulk_in = 2, | ||
| 1617 | .num_bulk_out = 2, | ||
| 1618 | .num_ports = 2, | ||
| 1619 | .open = mos7720_open, | ||
| 1620 | .close = mos7720_close, | ||
| 1621 | .throttle = mos7720_throttle, | ||
| 1622 | .unthrottle = mos7720_unthrottle, | ||
| 1623 | .attach = mos7720_startup, | ||
| 1624 | .shutdown = mos7720_shutdown, | ||
| 1625 | .ioctl = mos7720_ioctl, | ||
| 1626 | .set_termios = mos7720_set_termios, | ||
| 1627 | .write = mos7720_write, | ||
| 1628 | .write_room = mos7720_write_room, | ||
| 1629 | .chars_in_buffer = mos7720_chars_in_buffer, | ||
| 1630 | .break_ctl = mos7720_break, | ||
| 1631 | .read_bulk_callback = mos7720_bulk_in_callback, | ||
| 1632 | }; | ||
| 1633 | |||
| 1634 | static struct usb_driver usb_driver = { | ||
| 1635 | .name = "moschip7720", | ||
| 1636 | .probe = usb_serial_probe, | ||
| 1637 | .disconnect = usb_serial_disconnect, | ||
| 1638 | .id_table = moschip_port_id_table, | ||
| 1639 | }; | ||
| 1640 | |||
| 1641 | static int __init moschip7720_init(void) | ||
| 1642 | { | ||
| 1643 | int retval; | ||
| 1644 | |||
| 1645 | dbg("%s: Entering ..........", __FUNCTION__); | ||
| 1646 | |||
| 1647 | /* Register with the usb serial */ | ||
| 1648 | retval = usb_serial_register(&moschip7720_2port_driver); | ||
| 1649 | if (retval) | ||
| 1650 | goto failed_port_device_register; | ||
| 1651 | |||
| 1652 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
| 1653 | |||
| 1654 | /* Register with the usb */ | ||
| 1655 | retval = usb_register(&usb_driver); | ||
| 1656 | if (retval) | ||
| 1657 | goto failed_usb_register; | ||
| 1658 | |||
| 1659 | return 0; | ||
| 1660 | |||
| 1661 | failed_usb_register: | ||
| 1662 | usb_serial_deregister(&moschip7720_2port_driver); | ||
| 1663 | |||
| 1664 | failed_port_device_register: | ||
| 1665 | return retval; | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | static void __exit moschip7720_exit(void) | ||
| 1669 | { | ||
| 1670 | usb_deregister(&usb_driver); | ||
| 1671 | usb_serial_deregister(&moschip7720_2port_driver); | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | module_init(moschip7720_init); | ||
| 1675 | module_exit(moschip7720_exit); | ||
| 1676 | |||
| 1677 | /* Module information */ | ||
| 1678 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
| 1679 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
| 1680 | MODULE_LICENSE("GPL"); | ||
| 1681 | |||
| 1682 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 1683 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 021be39fe16e..5b71962d0351 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c | |||
| @@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, | |||
| 2413 | } | 2413 | } |
| 2414 | 2414 | ||
| 2415 | mos7840_port = mos7840_get_port_private(port); | 2415 | mos7840_port = mos7840_get_port_private(port); |
| 2416 | tty = mos7840_port->port->tty; | ||
| 2417 | 2416 | ||
| 2418 | if (mos7840_port == NULL) | 2417 | if (mos7840_port == NULL) |
| 2419 | return -1; | 2418 | return -1; |
| 2420 | 2419 | ||
| 2420 | tty = mos7840_port->port->tty; | ||
| 2421 | |||
| 2421 | dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); | 2422 | dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); |
| 2422 | 2423 | ||
| 2423 | switch (cmd) { | 2424 | switch (cmd) { |
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d29638daa987..ea16572d19f8 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
| @@ -1,21 +1,35 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Sierra Wireless CDMA Wireless Serial USB driver | 2 | USB Driver for Sierra Wireless |
| 3 | * | 3 | |
| 4 | * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com> | 4 | Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com> |
| 5 | * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de> | 5 | |
| 6 | * | 6 | IMPORTANT DISCLAIMER: This driver is not commercially supported by |
| 7 | * This program is free software; you can redistribute it and/or | 7 | Sierra Wireless. Use at your own risk. |
| 8 | * modify it under the terms of the GNU General Public License version | 8 | |
| 9 | * 2 as published by the Free Software Foundation. | 9 | This driver is free software; you can redistribute it and/or modify |
| 10 | */ | 10 | it under the terms of Version 2 of the GNU General Public License as |
| 11 | published by the Free Software Foundation. | ||
| 12 | |||
| 13 | Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> | ||
| 14 | Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> | ||
| 15 | |||
| 16 | History: | ||
| 17 | */ | ||
| 18 | |||
| 19 | #define DRIVER_VERSION "v.1.0.5" | ||
| 20 | #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" | ||
| 21 | #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" | ||
| 11 | 22 | ||
| 12 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 13 | #include <linux/init.h> | 24 | #include <linux/jiffies.h> |
| 25 | #include <linux/errno.h> | ||
| 14 | #include <linux/tty.h> | 26 | #include <linux/tty.h> |
| 27 | #include <linux/tty_flip.h> | ||
| 15 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 16 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
| 17 | #include <linux/usb/serial.h> | 30 | #include <linux/usb/serial.h> |
| 18 | 31 | ||
| 32 | |||
| 19 | static struct usb_device_id id_table [] = { | 33 | static struct usb_device_id id_table [] = { |
| 20 | { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ | 34 | { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ |
| 21 | { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ | 35 | { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ |
| @@ -23,53 +37,674 @@ static struct usb_device_id id_table [] = { | |||
| 23 | { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ | 37 | { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ |
| 24 | { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ | 38 | { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ |
| 25 | { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ | 39 | { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ |
| 40 | { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ | ||
| 26 | { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ | 41 | { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ |
| 27 | { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ | 42 | { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ |
| 28 | /* Following devices are supported in the airprime.c driver */ | 43 | |
| 29 | /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */ | 44 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ |
| 30 | /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */ | 45 | { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ |
| 31 | { } | 46 | { } |
| 32 | }; | 47 | }; |
| 33 | MODULE_DEVICE_TABLE(usb, id_table); | 48 | MODULE_DEVICE_TABLE(usb, id_table); |
| 34 | 49 | ||
| 50 | static struct usb_device_id id_table_1port [] = { | ||
| 51 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ | ||
| 52 | { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ | ||
| 53 | { } | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct usb_device_id id_table_3port [] = { | ||
| 57 | { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ | ||
| 58 | { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ | ||
| 59 | { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ | ||
| 60 | { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ | ||
| 61 | { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ | ||
| 62 | { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ | ||
| 63 | { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ | ||
| 64 | { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ | ||
| 65 | { } | ||
| 66 | }; | ||
| 67 | |||
| 35 | static struct usb_driver sierra_driver = { | 68 | static struct usb_driver sierra_driver = { |
| 36 | .name = "sierra_wireless", | 69 | .name = "sierra", |
| 37 | .probe = usb_serial_probe, | 70 | .probe = usb_serial_probe, |
| 38 | .disconnect = usb_serial_disconnect, | 71 | .disconnect = usb_serial_disconnect, |
| 39 | .id_table = id_table, | 72 | .id_table = id_table, |
| 73 | .no_dynamic_id = 1, | ||
| 74 | }; | ||
| 75 | |||
| 76 | |||
| 77 | static int debug; | ||
| 78 | |||
| 79 | /* per port private data */ | ||
| 80 | #define N_IN_URB 4 | ||
| 81 | #define N_OUT_URB 1 | ||
| 82 | #define IN_BUFLEN 4096 | ||
| 83 | #define OUT_BUFLEN 128 | ||
| 84 | |||
| 85 | struct sierra_port_private { | ||
| 86 | /* Input endpoints and buffer for this port */ | ||
| 87 | struct urb *in_urbs[N_IN_URB]; | ||
| 88 | char in_buffer[N_IN_URB][IN_BUFLEN]; | ||
| 89 | /* Output endpoints and buffer for this port */ | ||
| 90 | struct urb *out_urbs[N_OUT_URB]; | ||
| 91 | char out_buffer[N_OUT_URB][OUT_BUFLEN]; | ||
| 92 | |||
| 93 | /* Settings for the port */ | ||
| 94 | int rts_state; /* Handshaking pins (outputs) */ | ||
| 95 | int dtr_state; | ||
| 96 | int cts_state; /* Handshaking pins (inputs) */ | ||
| 97 | int dsr_state; | ||
| 98 | int dcd_state; | ||
| 99 | int ri_state; | ||
| 100 | |||
| 101 | unsigned long tx_start_time[N_OUT_URB]; | ||
| 102 | }; | ||
| 103 | |||
| 104 | static int sierra_send_setup(struct usb_serial_port *port) | ||
| 105 | { | ||
| 106 | struct usb_serial *serial = port->serial; | ||
| 107 | struct sierra_port_private *portdata; | ||
| 108 | |||
| 109 | dbg("%s", __FUNCTION__); | ||
| 110 | |||
| 111 | portdata = usb_get_serial_port_data(port); | ||
| 112 | |||
| 113 | if (port->tty) { | ||
| 114 | int val = 0; | ||
| 115 | if (portdata->dtr_state) | ||
| 116 | val |= 0x01; | ||
| 117 | if (portdata->rts_state) | ||
| 118 | val |= 0x02; | ||
| 119 | |||
| 120 | return usb_control_msg(serial->dev, | ||
| 121 | usb_rcvctrlpipe(serial->dev, 0), | ||
| 122 | 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); | ||
| 123 | } | ||
| 124 | |||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static void sierra_rx_throttle(struct usb_serial_port *port) | ||
| 129 | { | ||
| 130 | dbg("%s", __FUNCTION__); | ||
| 131 | } | ||
| 132 | |||
| 133 | static void sierra_rx_unthrottle(struct usb_serial_port *port) | ||
| 134 | { | ||
| 135 | dbg("%s", __FUNCTION__); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void sierra_break_ctl(struct usb_serial_port *port, int break_state) | ||
| 139 | { | ||
| 140 | /* Unfortunately, I don't know how to send a break */ | ||
| 141 | dbg("%s", __FUNCTION__); | ||
| 142 | } | ||
| 143 | |||
| 144 | static void sierra_set_termios(struct usb_serial_port *port, | ||
| 145 | struct termios *old_termios) | ||
| 146 | { | ||
| 147 | dbg("%s", __FUNCTION__); | ||
| 148 | |||
| 149 | sierra_send_setup(port); | ||
| 150 | } | ||
| 151 | |||
| 152 | static int sierra_tiocmget(struct usb_serial_port *port, struct file *file) | ||
| 153 | { | ||
| 154 | unsigned int value; | ||
| 155 | struct sierra_port_private *portdata; | ||
| 156 | |||
| 157 | portdata = usb_get_serial_port_data(port); | ||
| 158 | |||
| 159 | value = ((portdata->rts_state) ? TIOCM_RTS : 0) | | ||
| 160 | ((portdata->dtr_state) ? TIOCM_DTR : 0) | | ||
| 161 | ((portdata->cts_state) ? TIOCM_CTS : 0) | | ||
| 162 | ((portdata->dsr_state) ? TIOCM_DSR : 0) | | ||
| 163 | ((portdata->dcd_state) ? TIOCM_CAR : 0) | | ||
| 164 | ((portdata->ri_state) ? TIOCM_RNG : 0); | ||
| 165 | |||
| 166 | return value; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, | ||
| 170 | unsigned int set, unsigned int clear) | ||
| 171 | { | ||
| 172 | struct sierra_port_private *portdata; | ||
| 173 | |||
| 174 | portdata = usb_get_serial_port_data(port); | ||
| 175 | |||
| 176 | if (set & TIOCM_RTS) | ||
| 177 | portdata->rts_state = 1; | ||
| 178 | if (set & TIOCM_DTR) | ||
| 179 | portdata->dtr_state = 1; | ||
| 180 | |||
| 181 | if (clear & TIOCM_RTS) | ||
| 182 | portdata->rts_state = 0; | ||
| 183 | if (clear & TIOCM_DTR) | ||
| 184 | portdata->dtr_state = 0; | ||
| 185 | return sierra_send_setup(port); | ||
| 186 | } | ||
| 187 | |||
| 188 | static int sierra_ioctl(struct usb_serial_port *port, struct file *file, | ||
| 189 | unsigned int cmd, unsigned long arg) | ||
| 190 | { | ||
| 191 | return -ENOIOCTLCMD; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* Write */ | ||
| 195 | static int sierra_write(struct usb_serial_port *port, | ||
| 196 | const unsigned char *buf, int count) | ||
| 197 | { | ||
| 198 | struct sierra_port_private *portdata; | ||
| 199 | int i; | ||
| 200 | int left, todo; | ||
| 201 | struct urb *this_urb = NULL; /* spurious */ | ||
| 202 | int err; | ||
| 203 | |||
| 204 | portdata = usb_get_serial_port_data(port); | ||
| 205 | |||
| 206 | dbg("%s: write (%d chars)", __FUNCTION__, count); | ||
| 207 | |||
| 208 | i = 0; | ||
| 209 | left = count; | ||
| 210 | for (i=0; left > 0 && i < N_OUT_URB; i++) { | ||
| 211 | todo = left; | ||
| 212 | if (todo > OUT_BUFLEN) | ||
| 213 | todo = OUT_BUFLEN; | ||
| 214 | |||
| 215 | this_urb = portdata->out_urbs[i]; | ||
| 216 | if (this_urb->status == -EINPROGRESS) { | ||
| 217 | if (time_before(jiffies, | ||
| 218 | portdata->tx_start_time[i] + 10 * HZ)) | ||
| 219 | continue; | ||
| 220 | usb_unlink_urb(this_urb); | ||
| 221 | continue; | ||
| 222 | } | ||
| 223 | if (this_urb->status != 0) | ||
| 224 | dbg("usb_write %p failed (err=%d)", | ||
| 225 | this_urb, this_urb->status); | ||
| 226 | |||
| 227 | dbg("%s: endpoint %d buf %d", __FUNCTION__, | ||
| 228 | usb_pipeendpoint(this_urb->pipe), i); | ||
| 229 | |||
| 230 | /* send the data */ | ||
| 231 | memcpy (this_urb->transfer_buffer, buf, todo); | ||
| 232 | this_urb->transfer_buffer_length = todo; | ||
| 233 | |||
| 234 | this_urb->dev = port->serial->dev; | ||
| 235 | err = usb_submit_urb(this_urb, GFP_ATOMIC); | ||
| 236 | if (err) { | ||
| 237 | dbg("usb_submit_urb %p (write bulk) failed " | ||
| 238 | "(%d, has %d)", this_urb, | ||
| 239 | err, this_urb->status); | ||
| 240 | continue; | ||
| 241 | } | ||
| 242 | portdata->tx_start_time[i] = jiffies; | ||
| 243 | buf += todo; | ||
| 244 | left -= todo; | ||
| 245 | } | ||
| 246 | |||
| 247 | count -= left; | ||
| 248 | dbg("%s: wrote (did %d)", __FUNCTION__, count); | ||
| 249 | return count; | ||
| 250 | } | ||
| 251 | |||
| 252 | static void sierra_indat_callback(struct urb *urb) | ||
| 253 | { | ||
| 254 | int err; | ||
| 255 | int endpoint; | ||
| 256 | struct usb_serial_port *port; | ||
| 257 | struct tty_struct *tty; | ||
| 258 | unsigned char *data = urb->transfer_buffer; | ||
| 259 | |||
| 260 | dbg("%s: %p", __FUNCTION__, urb); | ||
| 261 | |||
| 262 | endpoint = usb_pipeendpoint(urb->pipe); | ||
| 263 | port = (struct usb_serial_port *) urb->context; | ||
| 264 | |||
| 265 | if (urb->status) { | ||
| 266 | dbg("%s: nonzero status: %d on endpoint %02x.", | ||
| 267 | __FUNCTION__, urb->status, endpoint); | ||
| 268 | } else { | ||
| 269 | tty = port->tty; | ||
| 270 | if (urb->actual_length) { | ||
| 271 | tty_buffer_request_room(tty, urb->actual_length); | ||
| 272 | tty_insert_flip_string(tty, data, urb->actual_length); | ||
| 273 | tty_flip_buffer_push(tty); | ||
| 274 | } else { | ||
| 275 | dbg("%s: empty read urb received", __FUNCTION__); | ||
| 276 | } | ||
| 277 | |||
| 278 | /* Resubmit urb so we continue receiving */ | ||
| 279 | if (port->open_count && urb->status != -ESHUTDOWN) { | ||
| 280 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 281 | if (err) | ||
| 282 | printk(KERN_ERR "%s: resubmit read urb failed. " | ||
| 283 | "(%d)", __FUNCTION__, err); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | return; | ||
| 287 | } | ||
| 288 | |||
| 289 | static void sierra_outdat_callback(struct urb *urb) | ||
| 290 | { | ||
| 291 | struct usb_serial_port *port; | ||
| 292 | |||
| 293 | dbg("%s", __FUNCTION__); | ||
| 294 | |||
| 295 | port = (struct usb_serial_port *) urb->context; | ||
| 296 | |||
| 297 | usb_serial_port_softint(port); | ||
| 298 | } | ||
| 299 | |||
| 300 | static void sierra_instat_callback(struct urb *urb) | ||
| 301 | { | ||
| 302 | int err; | ||
| 303 | struct usb_serial_port *port = (struct usb_serial_port *) urb->context; | ||
| 304 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||
| 305 | struct usb_serial *serial = port->serial; | ||
| 306 | |||
| 307 | dbg("%s", __FUNCTION__); | ||
| 308 | dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata); | ||
| 309 | |||
| 310 | if (urb->status == 0) { | ||
| 311 | struct usb_ctrlrequest *req_pkt = | ||
| 312 | (struct usb_ctrlrequest *)urb->transfer_buffer; | ||
| 313 | |||
| 314 | if (!req_pkt) { | ||
| 315 | dbg("%s: NULL req_pkt\n", __FUNCTION__); | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | if ((req_pkt->bRequestType == 0xA1) && | ||
| 319 | (req_pkt->bRequest == 0x20)) { | ||
| 320 | int old_dcd_state; | ||
| 321 | unsigned char signals = *((unsigned char *) | ||
| 322 | urb->transfer_buffer + | ||
| 323 | sizeof(struct usb_ctrlrequest)); | ||
| 324 | |||
| 325 | dbg("%s: signal x%x", __FUNCTION__, signals); | ||
| 326 | |||
| 327 | old_dcd_state = portdata->dcd_state; | ||
| 328 | portdata->cts_state = 1; | ||
| 329 | portdata->dcd_state = ((signals & 0x01) ? 1 : 0); | ||
| 330 | portdata->dsr_state = ((signals & 0x02) ? 1 : 0); | ||
| 331 | portdata->ri_state = ((signals & 0x08) ? 1 : 0); | ||
| 332 | |||
| 333 | if (port->tty && !C_CLOCAL(port->tty) && | ||
| 334 | old_dcd_state && !portdata->dcd_state) | ||
| 335 | tty_hangup(port->tty); | ||
| 336 | } else { | ||
| 337 | dbg("%s: type %x req %x", __FUNCTION__, | ||
| 338 | req_pkt->bRequestType,req_pkt->bRequest); | ||
| 339 | } | ||
| 340 | } else | ||
| 341 | dbg("%s: error %d", __FUNCTION__, urb->status); | ||
| 342 | |||
| 343 | /* Resubmit urb so we continue receiving IRQ data */ | ||
| 344 | if (urb->status != -ESHUTDOWN) { | ||
| 345 | urb->dev = serial->dev; | ||
| 346 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 347 | if (err) | ||
| 348 | dbg("%s: resubmit intr urb failed. (%d)", | ||
| 349 | __FUNCTION__, err); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | static int sierra_write_room(struct usb_serial_port *port) | ||
| 354 | { | ||
| 355 | struct sierra_port_private *portdata; | ||
| 356 | int i; | ||
| 357 | int data_len = 0; | ||
| 358 | struct urb *this_urb; | ||
| 359 | |||
| 360 | portdata = usb_get_serial_port_data(port); | ||
| 361 | |||
| 362 | for (i=0; i < N_OUT_URB; i++) { | ||
| 363 | this_urb = portdata->out_urbs[i]; | ||
| 364 | if (this_urb && this_urb->status != -EINPROGRESS) | ||
| 365 | data_len += OUT_BUFLEN; | ||
| 366 | } | ||
| 367 | |||
| 368 | dbg("%s: %d", __FUNCTION__, data_len); | ||
| 369 | return data_len; | ||
| 370 | } | ||
| 371 | |||
| 372 | static int sierra_chars_in_buffer(struct usb_serial_port *port) | ||
| 373 | { | ||
| 374 | struct sierra_port_private *portdata; | ||
| 375 | int i; | ||
| 376 | int data_len = 0; | ||
| 377 | struct urb *this_urb; | ||
| 378 | |||
| 379 | portdata = usb_get_serial_port_data(port); | ||
| 380 | |||
| 381 | for (i=0; i < N_OUT_URB; i++) { | ||
| 382 | this_urb = portdata->out_urbs[i]; | ||
| 383 | if (this_urb && this_urb->status == -EINPROGRESS) | ||
| 384 | data_len += this_urb->transfer_buffer_length; | ||
| 385 | } | ||
| 386 | dbg("%s: %d", __FUNCTION__, data_len); | ||
| 387 | return data_len; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int sierra_open(struct usb_serial_port *port, struct file *filp) | ||
| 391 | { | ||
| 392 | struct sierra_port_private *portdata; | ||
| 393 | struct usb_serial *serial = port->serial; | ||
| 394 | int i, err; | ||
| 395 | struct urb *urb; | ||
| 396 | |||
| 397 | portdata = usb_get_serial_port_data(port); | ||
| 398 | |||
| 399 | dbg("%s", __FUNCTION__); | ||
| 400 | |||
| 401 | /* Set some sane defaults */ | ||
| 402 | portdata->rts_state = 1; | ||
| 403 | portdata->dtr_state = 1; | ||
| 404 | |||
| 405 | /* Reset low level data toggle and start reading from endpoints */ | ||
| 406 | for (i = 0; i < N_IN_URB; i++) { | ||
| 407 | urb = portdata->in_urbs[i]; | ||
| 408 | if (! urb) | ||
| 409 | continue; | ||
| 410 | if (urb->dev != serial->dev) { | ||
| 411 | dbg("%s: dev %p != %p", __FUNCTION__, | ||
| 412 | urb->dev, serial->dev); | ||
| 413 | continue; | ||
| 414 | } | ||
| 415 | |||
| 416 | /* | ||
| 417 | * make sure endpoint data toggle is synchronized with the | ||
| 418 | * device | ||
| 419 | */ | ||
| 420 | usb_clear_halt(urb->dev, urb->pipe); | ||
| 421 | |||
| 422 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
| 423 | if (err) { | ||
| 424 | dbg("%s: submit urb %d failed (%d) %d", | ||
| 425 | __FUNCTION__, i, err, | ||
| 426 | urb->transfer_buffer_length); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | /* Reset low level data toggle on out endpoints */ | ||
| 431 | for (i = 0; i < N_OUT_URB; i++) { | ||
| 432 | urb = portdata->out_urbs[i]; | ||
| 433 | if (! urb) | ||
| 434 | continue; | ||
| 435 | urb->dev = serial->dev; | ||
| 436 | /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), | ||
| 437 | usb_pipeout(urb->pipe), 0); */ | ||
| 438 | } | ||
| 439 | |||
| 440 | port->tty->low_latency = 1; | ||
| 441 | |||
| 442 | sierra_send_setup(port); | ||
| 443 | |||
| 444 | return (0); | ||
| 445 | } | ||
| 446 | |||
| 447 | static inline void stop_urb(struct urb *urb) | ||
| 448 | { | ||
| 449 | if (urb && urb->status == -EINPROGRESS) | ||
| 450 | usb_kill_urb(urb); | ||
| 451 | } | ||
| 452 | |||
| 453 | static void sierra_close(struct usb_serial_port *port, struct file *filp) | ||
| 454 | { | ||
| 455 | int i; | ||
| 456 | struct usb_serial *serial = port->serial; | ||
| 457 | struct sierra_port_private *portdata; | ||
| 458 | |||
| 459 | dbg("%s", __FUNCTION__); | ||
| 460 | portdata = usb_get_serial_port_data(port); | ||
| 461 | |||
| 462 | portdata->rts_state = 0; | ||
| 463 | portdata->dtr_state = 0; | ||
| 464 | |||
| 465 | if (serial->dev) { | ||
| 466 | sierra_send_setup(port); | ||
| 467 | |||
| 468 | /* Stop reading/writing urbs */ | ||
| 469 | for (i = 0; i < N_IN_URB; i++) | ||
| 470 | stop_urb(portdata->in_urbs[i]); | ||
| 471 | for (i = 0; i < N_OUT_URB; i++) | ||
| 472 | stop_urb(portdata->out_urbs[i]); | ||
| 473 | } | ||
| 474 | port->tty = NULL; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* Helper functions used by sierra_setup_urbs */ | ||
| 478 | static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, | ||
| 479 | int dir, void *ctx, char *buf, int len, | ||
| 480 | usb_complete_t callback) | ||
| 481 | { | ||
| 482 | struct urb *urb; | ||
| 483 | |||
| 484 | if (endpoint == -1) | ||
| 485 | return NULL; /* endpoint not needed */ | ||
| 486 | |||
| 487 | urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ | ||
| 488 | if (urb == NULL) { | ||
| 489 | dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint); | ||
| 490 | return NULL; | ||
| 491 | } | ||
| 492 | |||
| 493 | /* Fill URB using supplied data. */ | ||
| 494 | usb_fill_bulk_urb(urb, serial->dev, | ||
| 495 | usb_sndbulkpipe(serial->dev, endpoint) | dir, | ||
| 496 | buf, len, callback, ctx); | ||
| 497 | |||
| 498 | return urb; | ||
| 499 | } | ||
| 500 | |||
| 501 | /* Setup urbs */ | ||
| 502 | static void sierra_setup_urbs(struct usb_serial *serial) | ||
| 503 | { | ||
| 504 | int i,j; | ||
| 505 | struct usb_serial_port *port; | ||
| 506 | struct sierra_port_private *portdata; | ||
| 507 | |||
| 508 | dbg("%s", __FUNCTION__); | ||
| 509 | |||
| 510 | for (i = 0; i < serial->num_ports; i++) { | ||
| 511 | port = serial->port[i]; | ||
| 512 | portdata = usb_get_serial_port_data(port); | ||
| 513 | |||
| 514 | /* Do indat endpoints first */ | ||
| 515 | for (j = 0; j < N_IN_URB; ++j) { | ||
| 516 | portdata->in_urbs[j] = sierra_setup_urb (serial, | ||
| 517 | port->bulk_in_endpointAddress, USB_DIR_IN, port, | ||
| 518 | portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); | ||
| 519 | } | ||
| 520 | |||
| 521 | /* outdat endpoints */ | ||
| 522 | for (j = 0; j < N_OUT_URB; ++j) { | ||
| 523 | portdata->out_urbs[j] = sierra_setup_urb (serial, | ||
| 524 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, | ||
| 525 | portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback); | ||
| 526 | } | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | static int sierra_startup(struct usb_serial *serial) | ||
| 531 | { | ||
| 532 | int i, err; | ||
| 533 | struct usb_serial_port *port; | ||
| 534 | struct sierra_port_private *portdata; | ||
| 535 | |||
| 536 | dbg("%s", __FUNCTION__); | ||
| 537 | |||
| 538 | /* Now setup per port private data */ | ||
| 539 | for (i = 0; i < serial->num_ports; i++) { | ||
| 540 | port = serial->port[i]; | ||
| 541 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); | ||
| 542 | if (!portdata) { | ||
| 543 | dbg("%s: kmalloc for sierra_port_private (%d) failed!.", | ||
| 544 | __FUNCTION__, i); | ||
| 545 | return (1); | ||
| 546 | } | ||
| 547 | |||
| 548 | usb_set_serial_port_data(port, portdata); | ||
| 549 | |||
| 550 | if (! port->interrupt_in_urb) | ||
| 551 | continue; | ||
| 552 | err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | ||
| 553 | if (err) | ||
| 554 | dbg("%s: submit irq_in urb failed %d", | ||
| 555 | __FUNCTION__, err); | ||
| 556 | } | ||
| 557 | |||
| 558 | sierra_setup_urbs(serial); | ||
| 559 | |||
| 560 | return (0); | ||
| 561 | } | ||
| 562 | |||
| 563 | static void sierra_shutdown(struct usb_serial *serial) | ||
| 564 | { | ||
| 565 | int i, j; | ||
| 566 | struct usb_serial_port *port; | ||
| 567 | struct sierra_port_private *portdata; | ||
| 568 | |||
| 569 | dbg("%s", __FUNCTION__); | ||
| 570 | |||
| 571 | /* Stop reading/writing urbs */ | ||
| 572 | for (i = 0; i < serial->num_ports; ++i) { | ||
| 573 | port = serial->port[i]; | ||
| 574 | portdata = usb_get_serial_port_data(port); | ||
| 575 | for (j = 0; j < N_IN_URB; j++) | ||
| 576 | stop_urb(portdata->in_urbs[j]); | ||
| 577 | for (j = 0; j < N_OUT_URB; j++) | ||
| 578 | stop_urb(portdata->out_urbs[j]); | ||
| 579 | } | ||
| 580 | |||
| 581 | /* Now free them */ | ||
| 582 | for (i = 0; i < serial->num_ports; ++i) { | ||
| 583 | port = serial->port[i]; | ||
| 584 | portdata = usb_get_serial_port_data(port); | ||
| 585 | |||
| 586 | for (j = 0; j < N_IN_URB; j++) { | ||
| 587 | if (portdata->in_urbs[j]) { | ||
| 588 | usb_free_urb(portdata->in_urbs[j]); | ||
| 589 | portdata->in_urbs[j] = NULL; | ||
| 590 | } | ||
| 591 | } | ||
| 592 | for (j = 0; j < N_OUT_URB; j++) { | ||
| 593 | if (portdata->out_urbs[j]) { | ||
| 594 | usb_free_urb(portdata->out_urbs[j]); | ||
| 595 | portdata->out_urbs[j] = NULL; | ||
| 596 | } | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | /* Now free per port private data */ | ||
| 601 | for (i = 0; i < serial->num_ports; i++) { | ||
| 602 | port = serial->port[i]; | ||
| 603 | kfree(usb_get_serial_port_data(port)); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | static struct usb_serial_driver sierra_1port_device = { | ||
| 608 | .driver = { | ||
| 609 | .owner = THIS_MODULE, | ||
| 610 | .name = "sierra1", | ||
| 611 | }, | ||
| 612 | .description = "Sierra USB modem (1 port)", | ||
| 613 | .id_table = id_table_1port, | ||
| 614 | .num_interrupt_in = NUM_DONT_CARE, | ||
| 615 | .num_bulk_in = 1, | ||
| 616 | .num_bulk_out = 1, | ||
| 617 | .num_ports = 1, | ||
| 618 | .open = sierra_open, | ||
| 619 | .close = sierra_close, | ||
| 620 | .write = sierra_write, | ||
| 621 | .write_room = sierra_write_room, | ||
| 622 | .chars_in_buffer = sierra_chars_in_buffer, | ||
| 623 | .throttle = sierra_rx_throttle, | ||
| 624 | .unthrottle = sierra_rx_unthrottle, | ||
| 625 | .ioctl = sierra_ioctl, | ||
| 626 | .set_termios = sierra_set_termios, | ||
| 627 | .break_ctl = sierra_break_ctl, | ||
| 628 | .tiocmget = sierra_tiocmget, | ||
| 629 | .tiocmset = sierra_tiocmset, | ||
| 630 | .attach = sierra_startup, | ||
| 631 | .shutdown = sierra_shutdown, | ||
| 632 | .read_int_callback = sierra_instat_callback, | ||
| 40 | }; | 633 | }; |
| 41 | 634 | ||
| 42 | static struct usb_serial_driver sierra_device = { | 635 | static struct usb_serial_driver sierra_3port_device = { |
| 43 | .driver = { | 636 | .driver = { |
| 44 | .owner = THIS_MODULE, | 637 | .owner = THIS_MODULE, |
| 45 | .name = "Sierra_Wireless", | 638 | .name = "sierra3", |
| 46 | }, | 639 | }, |
| 47 | .id_table = id_table, | 640 | .description = "Sierra USB modem (3 port)", |
| 48 | .num_interrupt_in = NUM_DONT_CARE, | 641 | .id_table = id_table_3port, |
| 49 | .num_bulk_in = NUM_DONT_CARE, | 642 | .num_interrupt_in = NUM_DONT_CARE, |
| 50 | .num_bulk_out = NUM_DONT_CARE, | 643 | .num_bulk_in = 3, |
| 51 | .num_ports = 3, | 644 | .num_bulk_out = 3, |
| 645 | .num_ports = 3, | ||
| 646 | .open = sierra_open, | ||
| 647 | .close = sierra_close, | ||
| 648 | .write = sierra_write, | ||
| 649 | .write_room = sierra_write_room, | ||
| 650 | .chars_in_buffer = sierra_chars_in_buffer, | ||
| 651 | .throttle = sierra_rx_throttle, | ||
| 652 | .unthrottle = sierra_rx_unthrottle, | ||
| 653 | .ioctl = sierra_ioctl, | ||
| 654 | .set_termios = sierra_set_termios, | ||
| 655 | .break_ctl = sierra_break_ctl, | ||
| 656 | .tiocmget = sierra_tiocmget, | ||
| 657 | .tiocmset = sierra_tiocmset, | ||
| 658 | .attach = sierra_startup, | ||
| 659 | .shutdown = sierra_shutdown, | ||
| 660 | .read_int_callback = sierra_instat_callback, | ||
| 52 | }; | 661 | }; |
| 53 | 662 | ||
| 663 | /* Functions used by new usb-serial code. */ | ||
| 54 | static int __init sierra_init(void) | 664 | static int __init sierra_init(void) |
| 55 | { | 665 | { |
| 56 | int retval; | 666 | int retval; |
| 57 | 667 | retval = usb_serial_register(&sierra_1port_device); | |
| 58 | retval = usb_serial_register(&sierra_device); | 668 | if (retval) |
| 669 | goto failed_1port_device_register; | ||
| 670 | retval = usb_serial_register(&sierra_3port_device); | ||
| 59 | if (retval) | 671 | if (retval) |
| 60 | return retval; | 672 | goto failed_3port_device_register; |
| 673 | |||
| 674 | |||
| 61 | retval = usb_register(&sierra_driver); | 675 | retval = usb_register(&sierra_driver); |
| 62 | if (retval) | 676 | if (retval) |
| 63 | usb_serial_deregister(&sierra_device); | 677 | goto failed_driver_register; |
| 678 | |||
| 679 | info(DRIVER_DESC ": " DRIVER_VERSION); | ||
| 680 | |||
| 681 | return 0; | ||
| 682 | |||
| 683 | failed_driver_register: | ||
| 684 | usb_serial_deregister(&sierra_3port_device); | ||
| 685 | failed_3port_device_register: | ||
| 686 | usb_serial_deregister(&sierra_1port_device); | ||
| 687 | failed_1port_device_register: | ||
| 64 | return retval; | 688 | return retval; |
| 65 | } | 689 | } |
| 66 | 690 | ||
| 67 | static void __exit sierra_exit(void) | 691 | static void __exit sierra_exit(void) |
| 68 | { | 692 | { |
| 69 | usb_deregister(&sierra_driver); | 693 | usb_deregister (&sierra_driver); |
| 70 | usb_serial_deregister(&sierra_device); | 694 | usb_serial_deregister(&sierra_1port_device); |
| 695 | usb_serial_deregister(&sierra_3port_device); | ||
| 71 | } | 696 | } |
| 72 | 697 | ||
| 73 | module_init(sierra_init); | 698 | module_init(sierra_init); |
| 74 | module_exit(sierra_exit); | 699 | module_exit(sierra_exit); |
| 700 | |||
| 701 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 702 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 703 | MODULE_VERSION(DRIVER_VERSION); | ||
| 75 | MODULE_LICENSE("GPL"); | 704 | MODULE_LICENSE("GPL"); |
| 705 | |||
| 706 | #ifdef CONFIG_USB_DEBUG | ||
| 707 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 708 | MODULE_PARM_DESC(debug, "Debug messages"); | ||
| 709 | #endif | ||
| 710 | |||
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c9a8d50106d1..37ed8e0f2dc8 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h | |||
| @@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, | |||
| 55 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 55 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 56 | US_FL_IGNORE_RESIDUE), | 56 | US_FL_IGNORE_RESIDUE), |
| 57 | 57 | ||
| 58 | UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, | 58 | /* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */ |
| 59 | UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200, | ||
| 59 | "Mitsumi", | 60 | "Mitsumi", |
| 60 | "USB FDD", | 61 | "USB FDD", |
| 61 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 62 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| @@ -182,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, | |||
| 182 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 183 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 183 | US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), | 184 | US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), |
| 184 | 185 | ||
| 186 | /* Reported by Bardur Arantsson <bardur@scientician.net> */ | ||
| 187 | UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, | ||
| 188 | "Nokia", | ||
| 189 | "6131", | ||
| 190 | US_SC_DEVICE, US_PR_DEVICE, NULL, | ||
| 191 | US_FL_MAX_SECTORS_64 ), | ||
| 192 | |||
| 193 | /* Reported by Alex Corcoles <alex@corcoles.net> */ | ||
| 194 | UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, | ||
| 195 | "Nokia", | ||
| 196 | "6234", | ||
| 197 | US_SC_DEVICE, US_PR_DEVICE, NULL, | ||
| 198 | US_FL_MAX_SECTORS_64 ), | ||
| 199 | |||
| 185 | /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ | 200 | /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ |
| 186 | UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, | 201 | UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, |
| 187 | "SMSC", | 202 | "SMSC", |
| @@ -1291,6 +1306,13 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, | |||
| 1291 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 1306 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 1292 | US_FL_FIX_CAPACITY ), | 1307 | US_FL_FIX_CAPACITY ), |
| 1293 | 1308 | ||
| 1309 | /* Reported by Jan Mate <mate@fiit.stuba.sk> */ | ||
| 1310 | UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, | ||
| 1311 | "Sony Ericsson", | ||
| 1312 | "P990i", | ||
| 1313 | US_SC_DEVICE, US_PR_DEVICE, NULL, | ||
| 1314 | US_FL_FIX_CAPACITY ), | ||
| 1315 | |||
| 1294 | /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> | 1316 | /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> |
| 1295 | * Tested on hardware version 1.10. | 1317 | * Tested on hardware version 1.10. |
| 1296 | * Entry is needed only for the initializer function override. | 1318 | * Entry is needed only for the initializer function override. |
