diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-12-29 13:23:05 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-03 15:31:47 -0500 |
commit | 228e4105374cffd5372b1dbdf1f8ec8cf1d964ae (patch) | |
tree | 9ceb1c17ff362ca6e6dbe004b633aebaec8d25c9 /drivers/usb/serial | |
parent | 294bb2c6178da6334f54bd88aac7dca63fd89b06 (diff) |
USB: pl2303: add line-status quirk for Siemens phones
Implement line-status handling for Siemens phones as a quirk rather than
spreading such information all over the driver by matching on vendor and
and product ids.
Note that the SIEMENS_PRODUCT_ID_EF81, which was added after the
line-status handling for the other Siemens phones was fixed, might also
need this quirk.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/pl2303.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 440b99c15435..8dd1c4a0aefd 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c | |||
@@ -31,6 +31,9 @@ | |||
31 | #include <asm/unaligned.h> | 31 | #include <asm/unaligned.h> |
32 | #include "pl2303.h" | 32 | #include "pl2303.h" |
33 | 33 | ||
34 | |||
35 | #define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) | ||
36 | |||
34 | static const struct usb_device_id id_table[] = { | 37 | static const struct usb_device_id id_table[] = { |
35 | { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, | 38 | { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, |
36 | { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, | 39 | { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, |
@@ -58,9 +61,12 @@ static const struct usb_device_id id_table[] = { | |||
58 | { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, | 61 | { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, |
59 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, | 62 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, |
60 | { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, | 63 | { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, |
61 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, | 64 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), |
62 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, | 65 | .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, |
63 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, | 66 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), |
67 | .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, | ||
68 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), | ||
69 | .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, | ||
64 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, | 70 | { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, |
65 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ | 71 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ |
66 | { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, | 72 | { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, |
@@ -110,7 +116,7 @@ MODULE_DEVICE_TABLE(usb, id_table); | |||
110 | #define VENDOR_READ_REQUEST_TYPE 0xc0 | 116 | #define VENDOR_READ_REQUEST_TYPE 0xc0 |
111 | #define VENDOR_READ_REQUEST 0x01 | 117 | #define VENDOR_READ_REQUEST 0x01 |
112 | 118 | ||
113 | #define UART_STATE 0x08 | 119 | #define UART_STATE_INDEX 8 |
114 | #define UART_STATE_TRANSIENT_MASK 0x74 | 120 | #define UART_STATE_TRANSIENT_MASK 0x74 |
115 | #define UART_DCD 0x01 | 121 | #define UART_DCD 0x01 |
116 | #define UART_DSR 0x02 | 122 | #define UART_DSR 0x02 |
@@ -130,6 +136,7 @@ enum pl2303_type { | |||
130 | 136 | ||
131 | struct pl2303_serial_private { | 137 | struct pl2303_serial_private { |
132 | enum pl2303_type type; | 138 | enum pl2303_type type; |
139 | unsigned long quirks; | ||
133 | }; | 140 | }; |
134 | 141 | ||
135 | struct pl2303_private { | 142 | struct pl2303_private { |
@@ -182,6 +189,14 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) | |||
182 | return 0; | 189 | return 0; |
183 | } | 190 | } |
184 | 191 | ||
192 | static int pl2303_probe(struct usb_serial *serial, | ||
193 | const struct usb_device_id *id) | ||
194 | { | ||
195 | usb_set_serial_data(serial, (void *)id->driver_info); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
185 | static int pl2303_startup(struct usb_serial *serial) | 200 | static int pl2303_startup(struct usb_serial *serial) |
186 | { | 201 | { |
187 | struct pl2303_serial_private *spriv; | 202 | struct pl2303_serial_private *spriv; |
@@ -209,6 +224,8 @@ static int pl2303_startup(struct usb_serial *serial) | |||
209 | dev_dbg(&serial->interface->dev, "device type: %d\n", type); | 224 | dev_dbg(&serial->interface->dev, "device type: %d\n", type); |
210 | 225 | ||
211 | spriv->type = type; | 226 | spriv->type = type; |
227 | spriv->quirks = (unsigned long)usb_get_serial_data(serial); | ||
228 | |||
212 | usb_set_serial_data(serial, spriv); | 229 | usb_set_serial_data(serial, spriv); |
213 | 230 | ||
214 | pl2303_vendor_read(serial, 0x8484, buf); | 231 | pl2303_vendor_read(serial, 0x8484, buf); |
@@ -739,27 +756,18 @@ static void pl2303_update_line_status(struct usb_serial_port *port, | |||
739 | unsigned char *data, | 756 | unsigned char *data, |
740 | unsigned int actual_length) | 757 | unsigned int actual_length) |
741 | { | 758 | { |
759 | struct usb_serial *serial = port->serial; | ||
760 | struct pl2303_serial_private *spriv = usb_get_serial_data(serial); | ||
742 | struct pl2303_private *priv = usb_get_serial_port_data(port); | 761 | struct pl2303_private *priv = usb_get_serial_port_data(port); |
743 | struct tty_struct *tty; | 762 | struct tty_struct *tty; |
744 | unsigned long flags; | 763 | unsigned long flags; |
745 | u8 status_idx = UART_STATE; | 764 | unsigned int status_idx = UART_STATE_INDEX; |
746 | u8 length = UART_STATE + 1; | ||
747 | u8 prev_line_status; | 765 | u8 prev_line_status; |
748 | u16 idv, idp; | ||
749 | 766 | ||
750 | idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); | 767 | if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) |
751 | idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); | 768 | status_idx = 0; |
752 | |||
753 | if (idv == SIEMENS_VENDOR_ID) { | ||
754 | if (idp == SIEMENS_PRODUCT_ID_X65 || | ||
755 | idp == SIEMENS_PRODUCT_ID_SX1 || | ||
756 | idp == SIEMENS_PRODUCT_ID_X75) { | ||
757 | length = 1; | ||
758 | status_idx = 0; | ||
759 | } | ||
760 | } | ||
761 | 769 | ||
762 | if (actual_length < length) | 770 | if (actual_length < status_idx + 1) |
763 | return; | 771 | return; |
764 | 772 | ||
765 | /* Save off the uart status for others to look at */ | 773 | /* Save off the uart status for others to look at */ |
@@ -892,6 +900,7 @@ static struct usb_serial_driver pl2303_device = { | |||
892 | .tiocmiwait = pl2303_tiocmiwait, | 900 | .tiocmiwait = pl2303_tiocmiwait, |
893 | .process_read_urb = pl2303_process_read_urb, | 901 | .process_read_urb = pl2303_process_read_urb, |
894 | .read_int_callback = pl2303_read_int_callback, | 902 | .read_int_callback = pl2303_read_int_callback, |
903 | .probe = pl2303_probe, | ||
895 | .attach = pl2303_startup, | 904 | .attach = pl2303_startup, |
896 | .release = pl2303_release, | 905 | .release = pl2303_release, |
897 | .port_probe = pl2303_port_probe, | 906 | .port_probe = pl2303_port_probe, |