diff options
Diffstat (limited to 'drivers/usb/serial')
| -rw-r--r-- | drivers/usb/serial/Kconfig | 28 | ||||
| -rw-r--r-- | drivers/usb/serial/Makefile | 4 | ||||
| -rw-r--r-- | drivers/usb/serial/ch341.c | 396 | ||||
| -rw-r--r-- | drivers/usb/serial/cp210x.c (renamed from drivers/usb/serial/cp2101.c) | 161 | ||||
| -rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 29 | ||||
| -rw-r--r-- | drivers/usb/serial/generic.c | 9 | ||||
| -rw-r--r-- | drivers/usb/serial/ipaq.c | 43 | ||||
| -rw-r--r-- | drivers/usb/serial/keyspan.c | 2 | ||||
| -rw-r--r-- | drivers/usb/serial/opticon.c | 215 | ||||
| -rw-r--r-- | drivers/usb/serial/option.c | 86 | ||||
| -rw-r--r-- | drivers/usb/serial/qcserial.c | 147 | ||||
| -rw-r--r-- | drivers/usb/serial/symbolserial.c | 399 | ||||
| -rw-r--r-- | drivers/usb/serial/usb-serial.c | 20 |
13 files changed, 1355 insertions, 184 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index b361f05cafac..a65f9196b0a0 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig | |||
| @@ -116,14 +116,14 @@ config USB_SERIAL_DIGI_ACCELEPORT | |||
| 116 | To compile this driver as a module, choose M here: the | 116 | To compile this driver as a module, choose M here: the |
| 117 | module will be called digi_acceleport. | 117 | module will be called digi_acceleport. |
| 118 | 118 | ||
| 119 | config USB_SERIAL_CP2101 | 119 | config USB_SERIAL_CP210X |
| 120 | tristate "USB CP2101 UART Bridge Controller" | 120 | tristate "USB CP210x family of UART Bridge Controllers" |
| 121 | help | 121 | help |
| 122 | Say Y here if you want to use a CP2101/CP2102 based USB to RS232 | 122 | Say Y here if you want to use a CP2101/CP2102/CP2103 based USB |
| 123 | converter. | 123 | to RS232 converters. |
| 124 | 124 | ||
| 125 | To compile this driver as a module, choose M here: the | 125 | To compile this driver as a module, choose M here: the |
| 126 | module will be called cp2101. | 126 | module will be called cp210x. |
| 127 | 127 | ||
| 128 | config USB_SERIAL_CYPRESS_M8 | 128 | config USB_SERIAL_CYPRESS_M8 |
| 129 | tristate "USB Cypress M8 USB Serial Driver" | 129 | tristate "USB Cypress M8 USB Serial Driver" |
| @@ -472,6 +472,15 @@ config USB_SERIAL_OTI6858 | |||
| 472 | To compile this driver as a module, choose M here: the | 472 | To compile this driver as a module, choose M here: the |
| 473 | module will be called oti6858. | 473 | module will be called oti6858. |
| 474 | 474 | ||
| 475 | config USB_SERIAL_QUALCOMM | ||
| 476 | tristate "USB Qualcomm Serial modem" | ||
| 477 | help | ||
| 478 | Say Y here if you have a Qualcomm USB modem device. These are | ||
| 479 | usually wireless cellular modems. | ||
| 480 | |||
| 481 | To compile this driver as a module, choose M here: the | ||
| 482 | module will be called qcserial. | ||
| 483 | |||
| 475 | config USB_SERIAL_SPCP8X5 | 484 | config USB_SERIAL_SPCP8X5 |
| 476 | tristate "USB SPCP8x5 USB To Serial Driver" | 485 | tristate "USB SPCP8x5 USB To Serial Driver" |
| 477 | help | 486 | help |
| @@ -515,6 +524,15 @@ config USB_SERIAL_SIERRAWIRELESS | |||
| 515 | To compile this driver as a module, choose M here: the | 524 | To compile this driver as a module, choose M here: the |
| 516 | module will be called sierra. | 525 | module will be called sierra. |
| 517 | 526 | ||
| 527 | config USB_SERIAL_SYMBOL | ||
| 528 | tristate "USB Symbol Barcode driver (serial mode)" | ||
| 529 | help | ||
| 530 | Say Y here if you want to use a Symbol USB Barcode device | ||
| 531 | in serial emulation mode. | ||
| 532 | |||
| 533 | To compile this driver as a module, choose M here: the | ||
| 534 | module will be called symbolserial. | ||
| 535 | |||
| 518 | config USB_SERIAL_TI | 536 | config USB_SERIAL_TI |
| 519 | tristate "USB TI 3410/5052 Serial Driver" | 537 | tristate "USB TI 3410/5052 Serial Driver" |
| 520 | help | 538 | help |
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index b75be91eb8f1..66619beb6cc0 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile | |||
| @@ -15,7 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o | |||
| 15 | obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o | 15 | obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o |
| 16 | obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o | 16 | obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o |
| 17 | obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o | 17 | obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o |
| 18 | obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o | 18 | obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o |
| 19 | obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o | 19 | obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o |
| 20 | obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o | 20 | obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o |
| 21 | obj-$(CONFIG_USB_SERIAL_DEBUG) += usb_debug.o | 21 | obj-$(CONFIG_USB_SERIAL_DEBUG) += usb_debug.o |
| @@ -45,10 +45,12 @@ obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o | |||
| 45 | obj-$(CONFIG_USB_SERIAL_OPTION) += option.o | 45 | obj-$(CONFIG_USB_SERIAL_OPTION) += option.o |
| 46 | obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o | 46 | obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o |
| 47 | obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o | 47 | obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o |
| 48 | obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o | ||
| 48 | obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o | 49 | obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o |
| 49 | obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o | 50 | obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o |
| 50 | obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o | 51 | obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o |
| 51 | obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o | 52 | obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o |
| 53 | obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o | ||
| 52 | obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o | 54 | obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o |
| 53 | obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o | 55 | obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o |
| 54 | obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o | 56 | obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o |
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index f61e3ca64305..ab4cc277aa65 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk> | 2 | * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk> |
| 3 | * Copyright 2007, Werner Cornelius <werner@cornelius-consult.de> | ||
| 4 | * Copyright 2009, Boris Hajduk <boris@hajduk.org> | ||
| 3 | * | 5 | * |
| 4 | * ch341.c implements a serial port driver for the Winchiphead CH341. | 6 | * ch341.c implements a serial port driver for the Winchiphead CH341. |
| 5 | * | 7 | * |
| @@ -21,9 +23,39 @@ | |||
| 21 | #include <linux/usb/serial.h> | 23 | #include <linux/usb/serial.h> |
| 22 | #include <linux/serial.h> | 24 | #include <linux/serial.h> |
| 23 | 25 | ||
| 24 | #define DEFAULT_BAUD_RATE 2400 | 26 | #define DEFAULT_BAUD_RATE 9600 |
| 25 | #define DEFAULT_TIMEOUT 1000 | 27 | #define DEFAULT_TIMEOUT 1000 |
| 26 | 28 | ||
| 29 | /* flags for IO-Bits */ | ||
| 30 | #define CH341_BIT_RTS (1 << 6) | ||
| 31 | #define CH341_BIT_DTR (1 << 5) | ||
| 32 | |||
| 33 | /******************************/ | ||
| 34 | /* interrupt pipe definitions */ | ||
| 35 | /******************************/ | ||
| 36 | /* always 4 interrupt bytes */ | ||
| 37 | /* first irq byte normally 0x08 */ | ||
| 38 | /* second irq byte base 0x7d + below */ | ||
| 39 | /* third irq byte base 0x94 + below */ | ||
| 40 | /* fourth irq byte normally 0xee */ | ||
| 41 | |||
| 42 | /* second interrupt byte */ | ||
| 43 | #define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ | ||
| 44 | |||
| 45 | /* status returned in third interrupt answer byte, inverted in data | ||
| 46 | from irq */ | ||
| 47 | #define CH341_BIT_CTS 0x01 | ||
| 48 | #define CH341_BIT_DSR 0x02 | ||
| 49 | #define CH341_BIT_RI 0x04 | ||
| 50 | #define CH341_BIT_DCD 0x08 | ||
| 51 | #define CH341_BITS_MODEM_STAT 0x0f /* all bits */ | ||
| 52 | |||
| 53 | /*******************************/ | ||
| 54 | /* baudrate calculation factor */ | ||
| 55 | /*******************************/ | ||
| 56 | #define CH341_BAUDBASE_FACTOR 1532620800 | ||
| 57 | #define CH341_BAUDBASE_DIVMAX 3 | ||
| 58 | |||
| 27 | static int debug; | 59 | static int debug; |
| 28 | 60 | ||
| 29 | static struct usb_device_id id_table [] = { | 61 | static struct usb_device_id id_table [] = { |
| @@ -34,9 +66,12 @@ static struct usb_device_id id_table [] = { | |||
| 34 | MODULE_DEVICE_TABLE(usb, id_table); | 66 | MODULE_DEVICE_TABLE(usb, id_table); |
| 35 | 67 | ||
| 36 | struct ch341_private { | 68 | struct ch341_private { |
| 37 | unsigned baud_rate; | 69 | spinlock_t lock; /* access lock */ |
| 38 | u8 dtr; | 70 | wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ |
| 39 | u8 rts; | 71 | unsigned baud_rate; /* set baud rate */ |
| 72 | u8 line_control; /* set line control value RTS/DTR */ | ||
| 73 | u8 line_status; /* active status of modem control inputs */ | ||
| 74 | u8 multi_status_change; /* status changed multiple since last call */ | ||
| 40 | }; | 75 | }; |
| 41 | 76 | ||
| 42 | static int ch341_control_out(struct usb_device *dev, u8 request, | 77 | static int ch341_control_out(struct usb_device *dev, u8 request, |
| @@ -72,37 +107,28 @@ static int ch341_set_baudrate(struct usb_device *dev, | |||
| 72 | { | 107 | { |
| 73 | short a, b; | 108 | short a, b; |
| 74 | int r; | 109 | int r; |
| 110 | unsigned long factor; | ||
| 111 | short divisor; | ||
| 75 | 112 | ||
| 76 | dbg("ch341_set_baudrate(%d)", priv->baud_rate); | 113 | dbg("ch341_set_baudrate(%d)", priv->baud_rate); |
| 77 | switch (priv->baud_rate) { | 114 | |
| 78 | case 2400: | 115 | if (!priv->baud_rate) |
| 79 | a = 0xd901; | ||
| 80 | b = 0x0038; | ||
| 81 | break; | ||
| 82 | case 4800: | ||
| 83 | a = 0x6402; | ||
| 84 | b = 0x001f; | ||
| 85 | break; | ||
| 86 | case 9600: | ||
| 87 | a = 0xb202; | ||
| 88 | b = 0x0013; | ||
| 89 | break; | ||
| 90 | case 19200: | ||
| 91 | a = 0xd902; | ||
| 92 | b = 0x000d; | ||
| 93 | break; | ||
| 94 | case 38400: | ||
| 95 | a = 0x6403; | ||
| 96 | b = 0x000a; | ||
| 97 | break; | ||
| 98 | case 115200: | ||
| 99 | a = 0xcc03; | ||
| 100 | b = 0x0008; | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | return -EINVAL; | 116 | return -EINVAL; |
| 117 | factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); | ||
| 118 | divisor = CH341_BAUDBASE_DIVMAX; | ||
| 119 | |||
| 120 | while ((factor > 0xfff0) && divisor) { | ||
| 121 | factor >>= 3; | ||
| 122 | divisor--; | ||
| 104 | } | 123 | } |
| 105 | 124 | ||
| 125 | if (factor > 0xfff0) | ||
| 126 | return -EINVAL; | ||
| 127 | |||
| 128 | factor = 0x10000 - factor; | ||
| 129 | a = (factor & 0xff00) | divisor; | ||
| 130 | b = factor & 0xff; | ||
| 131 | |||
| 106 | r = ch341_control_out(dev, 0x9a, 0x1312, a); | 132 | r = ch341_control_out(dev, 0x9a, 0x1312, a); |
| 107 | if (!r) | 133 | if (!r) |
| 108 | r = ch341_control_out(dev, 0x9a, 0x0f2c, b); | 134 | r = ch341_control_out(dev, 0x9a, 0x0f2c, b); |
| @@ -110,19 +136,18 @@ static int ch341_set_baudrate(struct usb_device *dev, | |||
| 110 | return r; | 136 | return r; |
| 111 | } | 137 | } |
| 112 | 138 | ||
| 113 | static int ch341_set_handshake(struct usb_device *dev, | 139 | static int ch341_set_handshake(struct usb_device *dev, u8 control) |
| 114 | struct ch341_private *priv) | ||
| 115 | { | 140 | { |
| 116 | dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); | 141 | dbg("ch341_set_handshake(0x%02x)", control); |
| 117 | return ch341_control_out(dev, 0xa4, | 142 | return ch341_control_out(dev, 0xa4, ~control, 0); |
| 118 | ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); | ||
| 119 | } | 143 | } |
| 120 | 144 | ||
| 121 | static int ch341_get_status(struct usb_device *dev) | 145 | static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) |
| 122 | { | 146 | { |
| 123 | char *buffer; | 147 | char *buffer; |
| 124 | int r; | 148 | int r; |
| 125 | const unsigned size = 8; | 149 | const unsigned size = 8; |
| 150 | unsigned long flags; | ||
| 126 | 151 | ||
| 127 | dbg("ch341_get_status()"); | 152 | dbg("ch341_get_status()"); |
| 128 | 153 | ||
| @@ -134,10 +159,15 @@ static int ch341_get_status(struct usb_device *dev) | |||
| 134 | if (r < 0) | 159 | if (r < 0) |
| 135 | goto out; | 160 | goto out; |
| 136 | 161 | ||
| 137 | /* Not having the datasheet for the CH341, we ignore the bytes returned | 162 | /* setup the private status if available */ |
| 138 | * from the device. Return error if the device did not respond in time. | 163 | if (r == 2) { |
| 139 | */ | 164 | r = 0; |
| 140 | r = 0; | 165 | spin_lock_irqsave(&priv->lock, flags); |
| 166 | priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; | ||
| 167 | priv->multi_status_change = 0; | ||
| 168 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 169 | } else | ||
| 170 | r = -EPROTO; | ||
| 141 | 171 | ||
| 142 | out: kfree(buffer); | 172 | out: kfree(buffer); |
| 143 | return r; | 173 | return r; |
| @@ -180,7 +210,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) | |||
| 180 | goto out; | 210 | goto out; |
| 181 | 211 | ||
| 182 | /* expect 0xff 0xee */ | 212 | /* expect 0xff 0xee */ |
| 183 | r = ch341_get_status(dev); | 213 | r = ch341_get_status(dev, priv); |
| 184 | if (r < 0) | 214 | if (r < 0) |
| 185 | goto out; | 215 | goto out; |
| 186 | 216 | ||
| @@ -192,12 +222,12 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) | |||
| 192 | if (r < 0) | 222 | if (r < 0) |
| 193 | goto out; | 223 | goto out; |
| 194 | 224 | ||
| 195 | r = ch341_set_handshake(dev, priv); | 225 | r = ch341_set_handshake(dev, priv->line_control); |
| 196 | if (r < 0) | 226 | if (r < 0) |
| 197 | goto out; | 227 | goto out; |
| 198 | 228 | ||
| 199 | /* expect 0x9f 0xee */ | 229 | /* expect 0x9f 0xee */ |
| 200 | r = ch341_get_status(dev); | 230 | r = ch341_get_status(dev, priv); |
| 201 | 231 | ||
| 202 | out: kfree(buffer); | 232 | out: kfree(buffer); |
| 203 | return r; | 233 | return r; |
| @@ -216,9 +246,10 @@ static int ch341_attach(struct usb_serial *serial) | |||
| 216 | if (!priv) | 246 | if (!priv) |
| 217 | return -ENOMEM; | 247 | return -ENOMEM; |
| 218 | 248 | ||
| 249 | spin_lock_init(&priv->lock); | ||
| 250 | init_waitqueue_head(&priv->delta_msr_wait); | ||
| 219 | priv->baud_rate = DEFAULT_BAUD_RATE; | 251 | priv->baud_rate = DEFAULT_BAUD_RATE; |
| 220 | priv->dtr = 1; | 252 | priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; |
| 221 | priv->rts = 1; | ||
| 222 | 253 | ||
| 223 | r = ch341_configure(serial->dev, priv); | 254 | r = ch341_configure(serial->dev, priv); |
| 224 | if (r < 0) | 255 | if (r < 0) |
| @@ -231,6 +262,35 @@ error: kfree(priv); | |||
| 231 | return r; | 262 | return r; |
| 232 | } | 263 | } |
| 233 | 264 | ||
| 265 | static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, | ||
| 266 | struct file *filp) | ||
| 267 | { | ||
| 268 | struct ch341_private *priv = usb_get_serial_port_data(port); | ||
| 269 | unsigned long flags; | ||
| 270 | unsigned int c_cflag; | ||
| 271 | |||
| 272 | dbg("%s - port %d", __func__, port->number); | ||
| 273 | |||
| 274 | /* shutdown our urbs */ | ||
| 275 | dbg("%s - shutting down urbs", __func__); | ||
| 276 | usb_kill_urb(port->write_urb); | ||
| 277 | usb_kill_urb(port->read_urb); | ||
| 278 | usb_kill_urb(port->interrupt_in_urb); | ||
| 279 | |||
| 280 | if (tty) { | ||
| 281 | c_cflag = tty->termios->c_cflag; | ||
| 282 | if (c_cflag & HUPCL) { | ||
| 283 | /* drop DTR and RTS */ | ||
| 284 | spin_lock_irqsave(&priv->lock, flags); | ||
| 285 | priv->line_control = 0; | ||
| 286 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 287 | ch341_set_handshake(port->serial->dev, 0); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | wake_up_interruptible(&priv->delta_msr_wait); | ||
| 291 | } | ||
| 292 | |||
| 293 | |||
| 234 | /* open this device, set default parameters */ | 294 | /* open this device, set default parameters */ |
| 235 | static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, | 295 | static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, |
| 236 | struct file *filp) | 296 | struct file *filp) |
| @@ -242,14 +302,13 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 242 | dbg("ch341_open()"); | 302 | dbg("ch341_open()"); |
| 243 | 303 | ||
| 244 | priv->baud_rate = DEFAULT_BAUD_RATE; | 304 | priv->baud_rate = DEFAULT_BAUD_RATE; |
| 245 | priv->dtr = 1; | 305 | priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; |
| 246 | priv->rts = 1; | ||
| 247 | 306 | ||
| 248 | r = ch341_configure(serial->dev, priv); | 307 | r = ch341_configure(serial->dev, priv); |
| 249 | if (r) | 308 | if (r) |
| 250 | goto out; | 309 | goto out; |
| 251 | 310 | ||
| 252 | r = ch341_set_handshake(serial->dev, priv); | 311 | r = ch341_set_handshake(serial->dev, priv->line_control); |
| 253 | if (r) | 312 | if (r) |
| 254 | goto out; | 313 | goto out; |
| 255 | 314 | ||
| @@ -257,6 +316,16 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 257 | if (r) | 316 | if (r) |
| 258 | goto out; | 317 | goto out; |
| 259 | 318 | ||
| 319 | dbg("%s - submitting interrupt urb", __func__); | ||
| 320 | port->interrupt_in_urb->dev = serial->dev; | ||
| 321 | r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | ||
| 322 | if (r) { | ||
| 323 | dev_err(&port->dev, "%s - failed submitting interrupt urb," | ||
| 324 | " error %d\n", __func__, r); | ||
| 325 | ch341_close(tty, port, NULL); | ||
| 326 | return -EPROTO; | ||
| 327 | } | ||
| 328 | |||
| 260 | r = usb_serial_generic_open(tty, port, filp); | 329 | r = usb_serial_generic_open(tty, port, filp); |
| 261 | 330 | ||
| 262 | out: return r; | 331 | out: return r; |
| @@ -270,46 +339,224 @@ static void ch341_set_termios(struct tty_struct *tty, | |||
| 270 | { | 339 | { |
| 271 | struct ch341_private *priv = usb_get_serial_port_data(port); | 340 | struct ch341_private *priv = usb_get_serial_port_data(port); |
| 272 | unsigned baud_rate; | 341 | unsigned baud_rate; |
| 342 | unsigned long flags; | ||
| 273 | 343 | ||
| 274 | dbg("ch341_set_termios()"); | 344 | dbg("ch341_set_termios()"); |
| 275 | 345 | ||
| 346 | if (!tty || !tty->termios) | ||
| 347 | return; | ||
| 348 | |||
| 276 | baud_rate = tty_get_baud_rate(tty); | 349 | baud_rate = tty_get_baud_rate(tty); |
| 277 | 350 | ||
| 278 | switch (baud_rate) { | 351 | priv->baud_rate = baud_rate; |
| 279 | case 2400: | 352 | |
| 280 | case 4800: | 353 | if (baud_rate) { |
| 281 | case 9600: | 354 | spin_lock_irqsave(&priv->lock, flags); |
| 282 | case 19200: | 355 | priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); |
| 283 | case 38400: | 356 | spin_unlock_irqrestore(&priv->lock, flags); |
| 284 | case 115200: | 357 | ch341_set_baudrate(port->serial->dev, priv); |
| 285 | priv->baud_rate = baud_rate; | 358 | } else { |
| 286 | break; | 359 | spin_lock_irqsave(&priv->lock, flags); |
| 287 | default: | 360 | priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); |
| 288 | dbg("Rate %d not supported, using %d", | 361 | spin_unlock_irqrestore(&priv->lock, flags); |
| 289 | baud_rate, DEFAULT_BAUD_RATE); | ||
| 290 | priv->baud_rate = DEFAULT_BAUD_RATE; | ||
| 291 | } | 362 | } |
| 292 | 363 | ||
| 293 | ch341_set_baudrate(port->serial->dev, priv); | 364 | ch341_set_handshake(port->serial->dev, priv->line_control); |
| 294 | 365 | ||
| 295 | /* Unimplemented: | 366 | /* Unimplemented: |
| 296 | * (cflag & CSIZE) : data bits [5, 8] | 367 | * (cflag & CSIZE) : data bits [5, 8] |
| 297 | * (cflag & PARENB) : parity {NONE, EVEN, ODD} | 368 | * (cflag & PARENB) : parity {NONE, EVEN, ODD} |
| 298 | * (cflag & CSTOPB) : stop bits [1, 2] | 369 | * (cflag & CSTOPB) : stop bits [1, 2] |
| 299 | */ | 370 | */ |
| 371 | } | ||
| 372 | |||
| 373 | static int ch341_tiocmset(struct tty_struct *tty, struct file *file, | ||
| 374 | unsigned int set, unsigned int clear) | ||
| 375 | { | ||
| 376 | struct usb_serial_port *port = tty->driver_data; | ||
| 377 | struct ch341_private *priv = usb_get_serial_port_data(port); | ||
| 378 | unsigned long flags; | ||
| 379 | u8 control; | ||
| 380 | |||
| 381 | spin_lock_irqsave(&priv->lock, flags); | ||
| 382 | if (set & TIOCM_RTS) | ||
| 383 | priv->line_control |= CH341_BIT_RTS; | ||
| 384 | if (set & TIOCM_DTR) | ||
| 385 | priv->line_control |= CH341_BIT_DTR; | ||
| 386 | if (clear & TIOCM_RTS) | ||
| 387 | priv->line_control &= ~CH341_BIT_RTS; | ||
| 388 | if (clear & TIOCM_DTR) | ||
| 389 | priv->line_control &= ~CH341_BIT_DTR; | ||
| 390 | control = priv->line_control; | ||
| 391 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 392 | |||
| 393 | return ch341_set_handshake(port->serial->dev, control); | ||
| 394 | } | ||
| 395 | |||
| 396 | static void ch341_read_int_callback(struct urb *urb) | ||
| 397 | { | ||
| 398 | struct usb_serial_port *port = (struct usb_serial_port *) urb->context; | ||
| 399 | unsigned char *data = urb->transfer_buffer; | ||
| 400 | unsigned int actual_length = urb->actual_length; | ||
| 401 | int status; | ||
| 402 | |||
| 403 | dbg("%s (%d)", __func__, port->number); | ||
| 404 | |||
| 405 | switch (urb->status) { | ||
| 406 | case 0: | ||
| 407 | /* success */ | ||
| 408 | break; | ||
| 409 | case -ECONNRESET: | ||
| 410 | case -ENOENT: | ||
| 411 | case -ESHUTDOWN: | ||
| 412 | /* this urb is terminated, clean up */ | ||
| 413 | dbg("%s - urb shutting down with status: %d", __func__, | ||
| 414 | urb->status); | ||
| 415 | return; | ||
| 416 | default: | ||
| 417 | dbg("%s - nonzero urb status received: %d", __func__, | ||
| 418 | urb->status); | ||
| 419 | goto exit; | ||
| 420 | } | ||
| 300 | 421 | ||
| 301 | /* Copy back the old hardware settings */ | 422 | usb_serial_debug_data(debug, &port->dev, __func__, |
| 302 | tty_termios_copy_hw(tty->termios, old_termios); | 423 | urb->actual_length, urb->transfer_buffer); |
| 303 | /* And re-encode with the new baud */ | 424 | |
| 304 | tty_encode_baud_rate(tty, baud_rate, baud_rate); | 425 | if (actual_length >= 4) { |
| 426 | struct ch341_private *priv = usb_get_serial_port_data(port); | ||
| 427 | unsigned long flags; | ||
| 428 | |||
| 429 | spin_lock_irqsave(&priv->lock, flags); | ||
| 430 | priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; | ||
| 431 | if ((data[1] & CH341_MULT_STAT)) | ||
| 432 | priv->multi_status_change = 1; | ||
| 433 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 434 | wake_up_interruptible(&priv->delta_msr_wait); | ||
| 435 | } | ||
| 436 | |||
| 437 | exit: | ||
| 438 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 439 | if (status) | ||
| 440 | dev_err(&urb->dev->dev, | ||
| 441 | "%s - usb_submit_urb failed with result %d\n", | ||
| 442 | __func__, status); | ||
| 443 | } | ||
| 444 | |||
| 445 | static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) | ||
| 446 | { | ||
| 447 | struct ch341_private *priv = usb_get_serial_port_data(port); | ||
| 448 | unsigned long flags; | ||
| 449 | u8 prevstatus; | ||
| 450 | u8 status; | ||
| 451 | u8 changed; | ||
| 452 | u8 multi_change = 0; | ||
| 453 | |||
| 454 | spin_lock_irqsave(&priv->lock, flags); | ||
| 455 | prevstatus = priv->line_status; | ||
| 456 | priv->multi_status_change = 0; | ||
| 457 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 458 | |||
| 459 | while (!multi_change) { | ||
| 460 | interruptible_sleep_on(&priv->delta_msr_wait); | ||
| 461 | /* see if a signal did it */ | ||
| 462 | if (signal_pending(current)) | ||
| 463 | return -ERESTARTSYS; | ||
| 464 | |||
| 465 | spin_lock_irqsave(&priv->lock, flags); | ||
| 466 | status = priv->line_status; | ||
| 467 | multi_change = priv->multi_status_change; | ||
| 468 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 469 | |||
| 470 | changed = prevstatus ^ status; | ||
| 471 | |||
| 472 | if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) || | ||
| 473 | ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) || | ||
| 474 | ((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) || | ||
| 475 | ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) { | ||
| 476 | return 0; | ||
| 477 | } | ||
| 478 | prevstatus = status; | ||
| 479 | } | ||
| 480 | |||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | /*static int ch341_ioctl(struct usb_serial_port *port, struct file *file,*/ | ||
| 485 | static int ch341_ioctl(struct tty_struct *tty, struct file *file, | ||
| 486 | unsigned int cmd, unsigned long arg) | ||
| 487 | { | ||
| 488 | struct usb_serial_port *port = tty->driver_data; | ||
| 489 | dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); | ||
| 490 | |||
| 491 | switch (cmd) { | ||
| 492 | case TIOCMIWAIT: | ||
| 493 | dbg("%s (%d) TIOCMIWAIT", __func__, port->number); | ||
| 494 | return wait_modem_info(port, arg); | ||
| 495 | |||
| 496 | default: | ||
| 497 | dbg("%s not supported = 0x%04x", __func__, cmd); | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | |||
| 501 | return -ENOIOCTLCMD; | ||
| 502 | } | ||
| 503 | |||
| 504 | static int ch341_tiocmget(struct tty_struct *tty, struct file *file) | ||
| 505 | { | ||
| 506 | struct usb_serial_port *port = tty->driver_data; | ||
| 507 | struct ch341_private *priv = usb_get_serial_port_data(port); | ||
| 508 | unsigned long flags; | ||
| 509 | u8 mcr; | ||
| 510 | u8 status; | ||
| 511 | unsigned int result; | ||
| 512 | |||
| 513 | dbg("%s (%d)", __func__, port->number); | ||
| 514 | |||
| 515 | spin_lock_irqsave(&priv->lock, flags); | ||
| 516 | mcr = priv->line_control; | ||
| 517 | status = priv->line_status; | ||
| 518 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 519 | |||
| 520 | result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0) | ||
| 521 | | ((mcr & CH341_BIT_RTS) ? TIOCM_RTS : 0) | ||
| 522 | | ((status & CH341_BIT_CTS) ? TIOCM_CTS : 0) | ||
| 523 | | ((status & CH341_BIT_DSR) ? TIOCM_DSR : 0) | ||
| 524 | | ((status & CH341_BIT_RI) ? TIOCM_RI : 0) | ||
| 525 | | ((status & CH341_BIT_DCD) ? TIOCM_CD : 0); | ||
| 526 | |||
| 527 | dbg("%s - result = %x", __func__, result); | ||
| 528 | |||
| 529 | return result; | ||
| 530 | } | ||
| 531 | |||
| 532 | |||
| 533 | static int ch341_reset_resume(struct usb_interface *intf) | ||
| 534 | { | ||
| 535 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 536 | struct usb_serial *serial = NULL; | ||
| 537 | struct ch341_private *priv; | ||
| 538 | |||
| 539 | serial = usb_get_intfdata(intf); | ||
| 540 | priv = usb_get_serial_port_data(serial->port[0]); | ||
| 541 | |||
| 542 | /*reconfigure ch341 serial port after bus-reset*/ | ||
| 543 | ch341_configure(dev, priv); | ||
| 544 | |||
| 545 | usb_serial_resume(intf); | ||
| 546 | |||
| 547 | return 0; | ||
| 305 | } | 548 | } |
| 306 | 549 | ||
| 307 | static struct usb_driver ch341_driver = { | 550 | static struct usb_driver ch341_driver = { |
| 308 | .name = "ch341", | 551 | .name = "ch341", |
| 309 | .probe = usb_serial_probe, | 552 | .probe = usb_serial_probe, |
| 310 | .disconnect = usb_serial_disconnect, | 553 | .disconnect = usb_serial_disconnect, |
| 554 | .suspend = usb_serial_suspend, | ||
| 555 | .resume = usb_serial_resume, | ||
| 556 | .reset_resume = ch341_reset_resume, | ||
| 311 | .id_table = id_table, | 557 | .id_table = id_table, |
| 312 | .no_dynamic_id = 1, | 558 | .no_dynamic_id = 1, |
| 559 | .supports_autosuspend = 1, | ||
| 313 | }; | 560 | }; |
| 314 | 561 | ||
| 315 | static struct usb_serial_driver ch341_device = { | 562 | static struct usb_serial_driver ch341_device = { |
| @@ -317,12 +564,17 @@ static struct usb_serial_driver ch341_device = { | |||
| 317 | .owner = THIS_MODULE, | 564 | .owner = THIS_MODULE, |
| 318 | .name = "ch341-uart", | 565 | .name = "ch341-uart", |
| 319 | }, | 566 | }, |
| 320 | .id_table = id_table, | 567 | .id_table = id_table, |
| 321 | .usb_driver = &ch341_driver, | 568 | .usb_driver = &ch341_driver, |
| 322 | .num_ports = 1, | 569 | .num_ports = 1, |
| 323 | .open = ch341_open, | 570 | .open = ch341_open, |
| 324 | .set_termios = ch341_set_termios, | 571 | .close = ch341_close, |
| 325 | .attach = ch341_attach, | 572 | .ioctl = ch341_ioctl, |
| 573 | .set_termios = ch341_set_termios, | ||
| 574 | .tiocmget = ch341_tiocmget, | ||
| 575 | .tiocmset = ch341_tiocmset, | ||
| 576 | .read_int_callback = ch341_read_int_callback, | ||
| 577 | .attach = ch341_attach, | ||
| 326 | }; | 578 | }; |
| 327 | 579 | ||
| 328 | static int __init ch341_init(void) | 580 | static int __init ch341_init(void) |
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp210x.c index 9b4082b58c5b..e8d5133ce9c8 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp210x.c | |||
| @@ -11,10 +11,6 @@ | |||
| 11 | * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow | 11 | * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow |
| 12 | * control thanks to Munir Nassar nassarmu@real-time.com | 12 | * control thanks to Munir Nassar nassarmu@real-time.com |
| 13 | * | 13 | * |
| 14 | * Outstanding Issues: | ||
| 15 | * Buffers are not flushed when the port is opened. | ||
| 16 | * Multiple calls to write() may fail with "Resource temporarily unavailable" | ||
| 17 | * | ||
| 18 | */ | 14 | */ |
| 19 | 15 | ||
| 20 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| @@ -31,7 +27,7 @@ | |||
| 31 | /* | 27 | /* |
| 32 | * Version Information | 28 | * Version Information |
| 33 | */ | 29 | */ |
| 34 | #define DRIVER_VERSION "v0.07" | 30 | #define DRIVER_VERSION "v0.08" |
| 35 | #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" | 31 | #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" |
| 36 | 32 | ||
| 37 | /* | 33 | /* |
| @@ -42,17 +38,21 @@ static int cp2101_open(struct tty_struct *, struct usb_serial_port *, | |||
| 42 | static void cp2101_cleanup(struct usb_serial_port *); | 38 | static void cp2101_cleanup(struct usb_serial_port *); |
| 43 | static void cp2101_close(struct tty_struct *, struct usb_serial_port *, | 39 | static void cp2101_close(struct tty_struct *, struct usb_serial_port *, |
| 44 | struct file*); | 40 | struct file*); |
| 45 | static void cp2101_get_termios(struct tty_struct *); | 41 | static void cp2101_get_termios(struct tty_struct *, |
| 42 | struct usb_serial_port *port); | ||
| 43 | static void cp2101_get_termios_port(struct usb_serial_port *port, | ||
| 44 | unsigned int *cflagp, unsigned int *baudp); | ||
| 46 | static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *, | 45 | static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *, |
| 47 | struct ktermios*); | 46 | struct ktermios*); |
| 48 | static int cp2101_tiocmget(struct tty_struct *, struct file *); | 47 | static int cp2101_tiocmget(struct tty_struct *, struct file *); |
| 49 | static int cp2101_tiocmset(struct tty_struct *, struct file *, | 48 | static int cp2101_tiocmset(struct tty_struct *, struct file *, |
| 50 | unsigned int, unsigned int); | 49 | unsigned int, unsigned int); |
| 50 | static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *, | ||
| 51 | unsigned int, unsigned int); | ||
| 51 | static void cp2101_break_ctl(struct tty_struct *, int); | 52 | static void cp2101_break_ctl(struct tty_struct *, int); |
| 52 | static int cp2101_startup(struct usb_serial *); | 53 | static int cp2101_startup(struct usb_serial *); |
| 53 | static void cp2101_shutdown(struct usb_serial *); | 54 | static void cp2101_shutdown(struct usb_serial *); |
| 54 | 55 | ||
| 55 | |||
| 56 | static int debug; | 56 | static int debug; |
| 57 | 57 | ||
| 58 | static struct usb_device_id id_table [] = { | 58 | static struct usb_device_id id_table [] = { |
| @@ -91,6 +91,7 @@ static struct usb_device_id id_table [] = { | |||
| 91 | { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */ | 91 | { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */ |
| 92 | { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ | 92 | { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ |
| 93 | { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ | 93 | { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ |
| 94 | { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ | ||
| 94 | { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ | 95 | { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ |
| 95 | { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ | 96 | { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ |
| 96 | { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ | 97 | { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ |
| @@ -225,7 +226,7 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request, | |||
| 225 | kfree(buf); | 226 | kfree(buf); |
| 226 | 227 | ||
| 227 | if (result != size) { | 228 | if (result != size) { |
| 228 | dev_err(&port->dev, "%s - Unable to send config request, " | 229 | dbg("%s - Unable to send config request, " |
| 229 | "request=0x%x size=%d result=%d\n", | 230 | "request=0x%x size=%d result=%d\n", |
| 230 | __func__, request, size, result); | 231 | __func__, request, size, result); |
| 231 | return -EPROTO; | 232 | return -EPROTO; |
| @@ -276,7 +277,7 @@ static int cp2101_set_config(struct usb_serial_port *port, u8 request, | |||
| 276 | kfree(buf); | 277 | kfree(buf); |
| 277 | 278 | ||
| 278 | if ((size > 2 && result != size) || result < 0) { | 279 | if ((size > 2 && result != size) || result < 0) { |
| 279 | dev_err(&port->dev, "%s - Unable to send request, " | 280 | dbg("%s - Unable to send request, " |
| 280 | "request=0x%x size=%d result=%d\n", | 281 | "request=0x%x size=%d result=%d\n", |
| 281 | __func__, request, size, result); | 282 | __func__, request, size, result); |
| 282 | return -EPROTO; | 283 | return -EPROTO; |
| @@ -301,6 +302,47 @@ static inline int cp2101_set_config_single(struct usb_serial_port *port, | |||
| 301 | return cp2101_set_config(port, request, &data, 2); | 302 | return cp2101_set_config(port, request, &data, 2); |
| 302 | } | 303 | } |
| 303 | 304 | ||
| 305 | /* | ||
| 306 | * cp2101_quantise_baudrate | ||
| 307 | * Quantises the baud rate as per AN205 Table 1 | ||
| 308 | */ | ||
| 309 | static unsigned int cp2101_quantise_baudrate(unsigned int baud) { | ||
| 310 | if (baud <= 56) baud = 0; | ||
| 311 | else if (baud <= 300) baud = 300; | ||
| 312 | else if (baud <= 600) baud = 600; | ||
| 313 | else if (baud <= 1200) baud = 1200; | ||
| 314 | else if (baud <= 1800) baud = 1800; | ||
| 315 | else if (baud <= 2400) baud = 2400; | ||
| 316 | else if (baud <= 4000) baud = 4000; | ||
| 317 | else if (baud <= 4803) baud = 4800; | ||
| 318 | else if (baud <= 7207) baud = 7200; | ||
| 319 | else if (baud <= 9612) baud = 9600; | ||
| 320 | else if (baud <= 14428) baud = 14400; | ||
| 321 | else if (baud <= 16062) baud = 16000; | ||
| 322 | else if (baud <= 19250) baud = 19200; | ||
| 323 | else if (baud <= 28912) baud = 28800; | ||
| 324 | else if (baud <= 38601) baud = 38400; | ||
| 325 | else if (baud <= 51558) baud = 51200; | ||
| 326 | else if (baud <= 56280) baud = 56000; | ||
| 327 | else if (baud <= 58053) baud = 57600; | ||
| 328 | else if (baud <= 64111) baud = 64000; | ||
| 329 | else if (baud <= 77608) baud = 76800; | ||
| 330 | else if (baud <= 117028) baud = 115200; | ||
| 331 | else if (baud <= 129347) baud = 128000; | ||
| 332 | else if (baud <= 156868) baud = 153600; | ||
| 333 | else if (baud <= 237832) baud = 230400; | ||
| 334 | else if (baud <= 254234) baud = 250000; | ||
| 335 | else if (baud <= 273066) baud = 256000; | ||
| 336 | else if (baud <= 491520) baud = 460800; | ||
| 337 | else if (baud <= 567138) baud = 500000; | ||
| 338 | else if (baud <= 670254) baud = 576000; | ||
| 339 | else if (baud <= 1053257) baud = 921600; | ||
| 340 | else if (baud <= 1474560) baud = 1228800; | ||
| 341 | else if (baud <= 2457600) baud = 1843200; | ||
| 342 | else baud = 3686400; | ||
| 343 | return baud; | ||
| 344 | } | ||
| 345 | |||
| 304 | static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, | 346 | static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, |
| 305 | struct file *filp) | 347 | struct file *filp) |
| 306 | { | 348 | { |
| @@ -331,10 +373,12 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 331 | } | 373 | } |
| 332 | 374 | ||
| 333 | /* Configure the termios structure */ | 375 | /* Configure the termios structure */ |
| 334 | cp2101_get_termios(tty); | 376 | cp2101_get_termios(tty, port); |
| 335 | 377 | ||
| 336 | /* Set the DTR and RTS pins low */ | 378 | /* Set the DTR and RTS pins low */ |
| 337 | cp2101_tiocmset(tty, NULL, TIOCM_DTR | TIOCM_RTS, 0); | 379 | cp2101_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data |
| 380 | : port, | ||
| 381 | NULL, TIOCM_DTR | TIOCM_RTS, 0); | ||
| 338 | 382 | ||
| 339 | return 0; | 383 | return 0; |
| 340 | } | 384 | } |
| @@ -376,9 +420,31 @@ static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 376 | * from the device, corrects any unsupported values, and configures the | 420 | * from the device, corrects any unsupported values, and configures the |
| 377 | * termios structure to reflect the state of the device | 421 | * termios structure to reflect the state of the device |
| 378 | */ | 422 | */ |
| 379 | static void cp2101_get_termios (struct tty_struct *tty) | 423 | static void cp2101_get_termios(struct tty_struct *tty, |
| 424 | struct usb_serial_port *port) | ||
| 425 | { | ||
| 426 | unsigned int baud; | ||
| 427 | |||
| 428 | if (tty) { | ||
| 429 | cp2101_get_termios_port(tty->driver_data, | ||
| 430 | &tty->termios->c_cflag, &baud); | ||
| 431 | tty_encode_baud_rate(tty, baud, baud); | ||
| 432 | } | ||
| 433 | |||
| 434 | else { | ||
| 435 | unsigned int cflag; | ||
| 436 | cflag = 0; | ||
| 437 | cp2101_get_termios_port(port, &cflag, &baud); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | /* | ||
| 442 | * cp2101_get_termios_port | ||
| 443 | * This is the heart of cp2101_get_termios which always uses a &usb_serial_port. | ||
| 444 | */ | ||
| 445 | static void cp2101_get_termios_port(struct usb_serial_port *port, | ||
| 446 | unsigned int *cflagp, unsigned int *baudp) | ||
| 380 | { | 447 | { |
| 381 | struct usb_serial_port *port = tty->driver_data; | ||
| 382 | unsigned int cflag, modem_ctl[4]; | 448 | unsigned int cflag, modem_ctl[4]; |
| 383 | unsigned int baud; | 449 | unsigned int baud; |
| 384 | unsigned int bits; | 450 | unsigned int bits; |
| @@ -388,12 +454,12 @@ static void cp2101_get_termios (struct tty_struct *tty) | |||
| 388 | cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2); | 454 | cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2); |
| 389 | /* Convert to baudrate */ | 455 | /* Convert to baudrate */ |
| 390 | if (baud) | 456 | if (baud) |
| 391 | baud = BAUD_RATE_GEN_FREQ / baud; | 457 | baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); |
| 392 | 458 | ||
| 393 | dbg("%s - baud rate = %d", __func__, baud); | 459 | dbg("%s - baud rate = %d", __func__, baud); |
| 460 | *baudp = baud; | ||
| 394 | 461 | ||
| 395 | tty_encode_baud_rate(tty, baud, baud); | 462 | cflag = *cflagp; |
| 396 | cflag = tty->termios->c_cflag; | ||
| 397 | 463 | ||
| 398 | cp2101_get_config(port, CP2101_BITS, &bits, 2); | 464 | cp2101_get_config(port, CP2101_BITS, &bits, 2); |
| 399 | cflag &= ~CSIZE; | 465 | cflag &= ~CSIZE; |
| @@ -499,7 +565,7 @@ static void cp2101_get_termios (struct tty_struct *tty) | |||
| 499 | cflag &= ~CRTSCTS; | 565 | cflag &= ~CRTSCTS; |
| 500 | } | 566 | } |
| 501 | 567 | ||
| 502 | tty->termios->c_cflag = cflag; | 568 | *cflagp = cflag; |
| 503 | } | 569 | } |
| 504 | 570 | ||
| 505 | static void cp2101_set_termios(struct tty_struct *tty, | 571 | static void cp2101_set_termios(struct tty_struct *tty, |
| @@ -517,46 +583,16 @@ static void cp2101_set_termios(struct tty_struct *tty, | |||
| 517 | tty->termios->c_cflag &= ~CMSPAR; | 583 | tty->termios->c_cflag &= ~CMSPAR; |
| 518 | cflag = tty->termios->c_cflag; | 584 | cflag = tty->termios->c_cflag; |
| 519 | old_cflag = old_termios->c_cflag; | 585 | old_cflag = old_termios->c_cflag; |
| 520 | baud = tty_get_baud_rate(tty); | 586 | baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty)); |
| 521 | 587 | ||
| 522 | /* If the baud rate is to be updated*/ | 588 | /* If the baud rate is to be updated*/ |
| 523 | if (baud != tty_termios_baud_rate(old_termios)) { | 589 | if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { |
| 524 | switch (baud) { | 590 | dbg("%s - Setting baud rate to %d baud", __func__, |
| 525 | case 0: | 591 | baud); |
| 526 | case 600: | 592 | if (cp2101_set_config_single(port, CP2101_BAUDRATE, |
| 527 | case 1200: | 593 | ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { |
| 528 | case 1800: | 594 | dbg("Baud rate requested not supported by device\n"); |
| 529 | case 2400: | 595 | baud = tty_termios_baud_rate(old_termios); |
| 530 | case 4800: | ||
| 531 | case 7200: | ||
| 532 | case 9600: | ||
| 533 | case 14400: | ||
| 534 | case 19200: | ||
| 535 | case 28800: | ||
| 536 | case 38400: | ||
| 537 | case 55854: | ||
| 538 | case 57600: | ||
| 539 | case 115200: | ||
| 540 | case 127117: | ||
| 541 | case 230400: | ||
| 542 | case 460800: | ||
| 543 | case 921600: | ||
| 544 | case 3686400: | ||
| 545 | break; | ||
| 546 | default: | ||
| 547 | baud = 9600; | ||
| 548 | break; | ||
| 549 | } | ||
| 550 | |||
| 551 | if (baud) { | ||
| 552 | dbg("%s - Setting baud rate to %d baud", __func__, | ||
| 553 | baud); | ||
| 554 | if (cp2101_set_config_single(port, CP2101_BAUDRATE, | ||
| 555 | (BAUD_RATE_GEN_FREQ / baud))) { | ||
| 556 | dev_err(&port->dev, "Baud rate requested not " | ||
| 557 | "supported by device\n"); | ||
| 558 | baud = tty_termios_baud_rate(old_termios); | ||
| 559 | } | ||
| 560 | } | 596 | } |
| 561 | } | 597 | } |
| 562 | /* Report back the resulting baud rate */ | 598 | /* Report back the resulting baud rate */ |
| @@ -588,14 +624,14 @@ static void cp2101_set_termios(struct tty_struct *tty, | |||
| 588 | dbg("%s - data bits = 9", __func__); | 624 | dbg("%s - data bits = 9", __func__); |
| 589 | break;*/ | 625 | break;*/ |
| 590 | default: | 626 | default: |
| 591 | dev_err(&port->dev, "cp2101 driver does not " | 627 | dbg("cp2101 driver does not " |
| 592 | "support the number of bits requested," | 628 | "support the number of bits requested," |
| 593 | " using 8 bit mode\n"); | 629 | " using 8 bit mode\n"); |
| 594 | bits |= BITS_DATA_8; | 630 | bits |= BITS_DATA_8; |
| 595 | break; | 631 | break; |
| 596 | } | 632 | } |
| 597 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) | 633 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) |
| 598 | dev_err(&port->dev, "Number of data bits requested " | 634 | dbg("Number of data bits requested " |
| 599 | "not supported by device\n"); | 635 | "not supported by device\n"); |
| 600 | } | 636 | } |
| 601 | 637 | ||
| @@ -612,7 +648,7 @@ static void cp2101_set_termios(struct tty_struct *tty, | |||
| 612 | } | 648 | } |
| 613 | } | 649 | } |
| 614 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) | 650 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) |
| 615 | dev_err(&port->dev, "Parity mode not supported " | 651 | dbg("Parity mode not supported " |
| 616 | "by device\n"); | 652 | "by device\n"); |
| 617 | } | 653 | } |
| 618 | 654 | ||
| @@ -627,7 +663,7 @@ static void cp2101_set_termios(struct tty_struct *tty, | |||
| 627 | dbg("%s - stop bits = 1", __func__); | 663 | dbg("%s - stop bits = 1", __func__); |
| 628 | } | 664 | } |
| 629 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) | 665 | if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) |
| 630 | dev_err(&port->dev, "Number of stop bits requested " | 666 | dbg("Number of stop bits requested " |
| 631 | "not supported by device\n"); | 667 | "not supported by device\n"); |
| 632 | } | 668 | } |
| 633 | 669 | ||
| @@ -661,6 +697,12 @@ static int cp2101_tiocmset (struct tty_struct *tty, struct file *file, | |||
| 661 | unsigned int set, unsigned int clear) | 697 | unsigned int set, unsigned int clear) |
| 662 | { | 698 | { |
| 663 | struct usb_serial_port *port = tty->driver_data; | 699 | struct usb_serial_port *port = tty->driver_data; |
| 700 | return cp2101_tiocmset_port(port, file, set, clear); | ||
| 701 | } | ||
| 702 | |||
| 703 | static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file, | ||
| 704 | unsigned int set, unsigned int clear) | ||
| 705 | { | ||
| 664 | unsigned int control = 0; | 706 | unsigned int control = 0; |
| 665 | 707 | ||
| 666 | dbg("%s - port %d", __func__, port->number); | 708 | dbg("%s - port %d", __func__, port->number); |
| @@ -685,7 +727,6 @@ static int cp2101_tiocmset (struct tty_struct *tty, struct file *file, | |||
| 685 | dbg("%s - control = 0x%.4x", __func__, control); | 727 | dbg("%s - control = 0x%.4x", __func__, control); |
| 686 | 728 | ||
| 687 | return cp2101_set_config(port, CP2101_CONTROL, &control, 2); | 729 | return cp2101_set_config(port, CP2101_CONTROL, &control, 2); |
| 688 | |||
| 689 | } | 730 | } |
| 690 | 731 | ||
| 691 | static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) | 732 | static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ae84c326a540..dcc87aaa8628 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -1938,18 +1938,16 @@ static void ftdi_process_read(struct work_struct *work) | |||
| 1938 | /* Compare new line status to the old one, signal if different/ | 1938 | /* Compare new line status to the old one, signal if different/ |
| 1939 | N.B. packet may be processed more than once, but differences | 1939 | N.B. packet may be processed more than once, but differences |
| 1940 | are only processed once. */ | 1940 | are only processed once. */ |
| 1941 | if (priv != NULL) { | 1941 | char new_status = data[packet_offset + 0] & |
| 1942 | char new_status = data[packet_offset + 0] & | 1942 | FTDI_STATUS_B0_MASK; |
| 1943 | FTDI_STATUS_B0_MASK; | 1943 | if (new_status != priv->prev_status) { |
| 1944 | if (new_status != priv->prev_status) { | 1944 | priv->diff_status |= |
| 1945 | priv->diff_status |= | 1945 | new_status ^ priv->prev_status; |
| 1946 | new_status ^ priv->prev_status; | 1946 | wake_up_interruptible(&priv->delta_msr_wait); |
| 1947 | wake_up_interruptible(&priv->delta_msr_wait); | 1947 | priv->prev_status = new_status; |
| 1948 | priv->prev_status = new_status; | ||
| 1949 | } | ||
| 1950 | } | 1948 | } |
| 1951 | 1949 | ||
| 1952 | length = min(PKTSZ, urb->actual_length-packet_offset)-2; | 1950 | length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2; |
| 1953 | if (length < 0) { | 1951 | if (length < 0) { |
| 1954 | dev_err(&port->dev, "%s - bad packet length: %d\n", | 1952 | dev_err(&port->dev, "%s - bad packet length: %d\n", |
| 1955 | __func__, length+2); | 1953 | __func__, length+2); |
| @@ -2294,11 +2292,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) | |||
| 2294 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | 2292 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, |
| 2295 | 0, 0, | 2293 | 0, 0, |
| 2296 | buf, 1, WDR_TIMEOUT); | 2294 | buf, 1, WDR_TIMEOUT); |
| 2297 | if (ret < 0) { | 2295 | if (ret < 0) |
| 2298 | dbg("%s Could not get modem status of device - err: %d", __func__, | ||
| 2299 | ret); | ||
| 2300 | return ret; | 2296 | return ret; |
| 2301 | } | ||
| 2302 | break; | 2297 | break; |
| 2303 | case FT8U232AM: | 2298 | case FT8U232AM: |
| 2304 | case FT232BM: | 2299 | case FT232BM: |
| @@ -2313,15 +2308,11 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) | |||
| 2313 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, | 2308 | FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, |
| 2314 | 0, priv->interface, | 2309 | 0, priv->interface, |
| 2315 | buf, 2, WDR_TIMEOUT); | 2310 | buf, 2, WDR_TIMEOUT); |
| 2316 | if (ret < 0) { | 2311 | if (ret < 0) |
| 2317 | dbg("%s Could not get modem status of device - err: %d", __func__, | ||
| 2318 | ret); | ||
| 2319 | return ret; | 2312 | return ret; |
| 2320 | } | ||
| 2321 | break; | 2313 | break; |
| 2322 | default: | 2314 | default: |
| 2323 | return -EFAULT; | 2315 | return -EFAULT; |
| 2324 | break; | ||
| 2325 | } | 2316 | } |
| 2326 | 2317 | ||
| 2327 | return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | | 2318 | return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | |
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 814909f1ee63..9d57cace3731 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
| @@ -177,14 +177,6 @@ int usb_serial_generic_resume(struct usb_serial *serial) | |||
| 177 | struct usb_serial_port *port; | 177 | struct usb_serial_port *port; |
| 178 | int i, c = 0, r; | 178 | int i, c = 0, r; |
| 179 | 179 | ||
| 180 | #ifdef CONFIG_PM | ||
| 181 | /* | ||
| 182 | * If this is an autoresume, don't submit URBs. | ||
| 183 | * They will be submitted in the open function instead. | ||
| 184 | */ | ||
| 185 | if (serial->dev->auto_pm) | ||
| 186 | return 0; | ||
| 187 | #endif | ||
| 188 | for (i = 0; i < serial->num_ports; i++) { | 180 | for (i = 0; i < serial->num_ports; i++) { |
| 189 | port = serial->port[i]; | 181 | port = serial->port[i]; |
| 190 | if (port->port.count && port->read_urb) { | 182 | if (port->port.count && port->read_urb) { |
| @@ -196,6 +188,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) | |||
| 196 | 188 | ||
| 197 | return c ? -EIO : 0; | 189 | return c ? -EIO : 0; |
| 198 | } | 190 | } |
| 191 | EXPORT_SYMBOL_GPL(usb_serial_generic_resume); | ||
| 199 | 192 | ||
| 200 | void usb_serial_generic_close(struct tty_struct *tty, | 193 | void usb_serial_generic_close(struct tty_struct *tty, |
| 201 | struct usb_serial_port *port, struct file *filp) | 194 | struct usb_serial_port *port, struct file *filp) |
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 132be74d2b89..ef92095b0732 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c | |||
| @@ -78,6 +78,7 @@ static int ipaq_open(struct tty_struct *tty, | |||
| 78 | struct usb_serial_port *port, struct file *filp); | 78 | struct usb_serial_port *port, struct file *filp); |
| 79 | static void ipaq_close(struct tty_struct *tty, | 79 | static void ipaq_close(struct tty_struct *tty, |
| 80 | struct usb_serial_port *port, struct file *filp); | 80 | struct usb_serial_port *port, struct file *filp); |
| 81 | static int ipaq_calc_num_ports(struct usb_serial *serial); | ||
| 81 | static int ipaq_startup(struct usb_serial *serial); | 82 | static int ipaq_startup(struct usb_serial *serial); |
| 82 | static void ipaq_shutdown(struct usb_serial *serial); | 83 | static void ipaq_shutdown(struct usb_serial *serial); |
| 83 | static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, | 84 | static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, |
| @@ -572,15 +573,10 @@ static struct usb_serial_driver ipaq_device = { | |||
| 572 | .description = "PocketPC PDA", | 573 | .description = "PocketPC PDA", |
| 573 | .usb_driver = &ipaq_driver, | 574 | .usb_driver = &ipaq_driver, |
| 574 | .id_table = ipaq_id_table, | 575 | .id_table = ipaq_id_table, |
| 575 | /* | ||
| 576 | * some devices have an extra endpoint, which | ||
| 577 | * must be ignored as it would make the core | ||
| 578 | * create a second port which oopses when used | ||
| 579 | */ | ||
| 580 | .num_ports = 1, | ||
| 581 | .open = ipaq_open, | 576 | .open = ipaq_open, |
| 582 | .close = ipaq_close, | 577 | .close = ipaq_close, |
| 583 | .attach = ipaq_startup, | 578 | .attach = ipaq_startup, |
| 579 | .calc_num_ports = ipaq_calc_num_ports, | ||
| 584 | .shutdown = ipaq_shutdown, | 580 | .shutdown = ipaq_shutdown, |
| 585 | .write = ipaq_write, | 581 | .write = ipaq_write, |
| 586 | .write_room = ipaq_write_room, | 582 | .write_room = ipaq_write_room, |
| @@ -956,14 +952,49 @@ static void ipaq_destroy_lists(struct usb_serial_port *port) | |||
| 956 | } | 952 | } |
| 957 | 953 | ||
| 958 | 954 | ||
| 955 | static int ipaq_calc_num_ports(struct usb_serial *serial) | ||
| 956 | { | ||
| 957 | /* | ||
| 958 | * some devices have 3 endpoints, the 3rd of which | ||
| 959 | * must be ignored as it would make the core | ||
| 960 | * create a second port which oopses when used | ||
| 961 | */ | ||
| 962 | int ipaq_num_ports = 1; | ||
| 963 | |||
| 964 | dbg("%s - numberofendpoints: %d", __FUNCTION__, | ||
| 965 | (int)serial->interface->cur_altsetting->desc.bNumEndpoints); | ||
| 966 | |||
| 967 | /* | ||
| 968 | * a few devices have 4 endpoints, seemingly Yakuma devices, | ||
| 969 | * and we need the second pair, so let them have 2 ports | ||
| 970 | * | ||
| 971 | * TODO: can we drop port 1 ? | ||
| 972 | */ | ||
| 973 | if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) { | ||
| 974 | ipaq_num_ports = 2; | ||
| 975 | } | ||
| 976 | |||
| 977 | return ipaq_num_ports; | ||
| 978 | } | ||
| 979 | |||
| 980 | |||
| 959 | static int ipaq_startup(struct usb_serial *serial) | 981 | static int ipaq_startup(struct usb_serial *serial) |
| 960 | { | 982 | { |
| 961 | dbg("%s", __func__); | 983 | dbg("%s", __func__); |
| 962 | if (serial->dev->actconfig->desc.bConfigurationValue != 1) { | 984 | if (serial->dev->actconfig->desc.bConfigurationValue != 1) { |
| 985 | /* | ||
| 986 | * FIXME: HP iPaq rx3715, possibly others, have 1 config that | ||
| 987 | * is labeled as 2 | ||
| 988 | */ | ||
| 989 | |||
| 963 | dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", | 990 | dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", |
| 964 | serial->dev->actconfig->desc.bConfigurationValue); | 991 | serial->dev->actconfig->desc.bConfigurationValue); |
| 965 | return -ENODEV; | 992 | return -ENODEV; |
| 966 | } | 993 | } |
| 994 | |||
| 995 | dbg("%s - iPAQ module configured for %d ports", | ||
| 996 | __FUNCTION__, serial->num_ports); | ||
| 997 | |||
| 967 | return usb_reset_configuration(serial->dev); | 998 | return usb_reset_configuration(serial->dev); |
| 968 | } | 999 | } |
| 969 | 1000 | ||
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9878c0fb3859..00daa8f7759a 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
| @@ -1507,7 +1507,7 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, | |||
| 1507 | } else { | 1507 | } else { |
| 1508 | dev_warn(&serial->interface->dev, | 1508 | dev_warn(&serial->interface->dev, |
| 1509 | "unsupported endpoint type %x\n", | 1509 | "unsupported endpoint type %x\n", |
| 1510 | ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); | 1510 | usb_endpoint_type(ep_desc)); |
| 1511 | usb_free_urb(urb); | 1511 | usb_free_urb(urb); |
| 1512 | return NULL; | 1512 | return NULL; |
| 1513 | } | 1513 | } |
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index cea326f1f105..839583dc8b6a 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Opticon USB barcode to serial driver | 2 | * Opticon USB barcode to serial driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> | 4 | * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> |
| 5 | * Copyright (C) 2008 Novell Inc. | 5 | * Copyright (C) 2008 - 2009 Novell Inc. |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License version | 8 | * modify it under the terms of the GNU General Public License version |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/tty.h> | 14 | #include <linux/tty.h> |
| 15 | #include <linux/tty_driver.h> | 15 | #include <linux/tty_driver.h> |
| 16 | #include <linux/tty_flip.h> | 16 | #include <linux/tty_flip.h> |
| 17 | #include <linux/serial.h> | ||
| 17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 18 | #include <linux/usb.h> | 19 | #include <linux/usb.h> |
| 19 | #include <linux/usb/serial.h> | 20 | #include <linux/usb/serial.h> |
| @@ -40,8 +41,12 @@ struct opticon_private { | |||
| 40 | bool throttled; | 41 | bool throttled; |
| 41 | bool actually_throttled; | 42 | bool actually_throttled; |
| 42 | bool rts; | 43 | bool rts; |
| 44 | int outstanding_urbs; | ||
| 43 | }; | 45 | }; |
| 44 | 46 | ||
| 47 | /* max number of write urbs in flight */ | ||
| 48 | #define URB_UPPER_LIMIT 4 | ||
| 49 | |||
| 45 | static void opticon_bulk_callback(struct urb *urb) | 50 | static void opticon_bulk_callback(struct urb *urb) |
| 46 | { | 51 | { |
| 47 | struct opticon_private *priv = urb->context; | 52 | struct opticon_private *priv = urb->context; |
| @@ -106,7 +111,6 @@ static void opticon_bulk_callback(struct urb *urb) | |||
| 106 | priv->rts = false; | 111 | priv->rts = false; |
| 107 | else | 112 | else |
| 108 | priv->rts = true; | 113 | priv->rts = true; |
| 109 | /* FIXME change the RTS level */ | ||
| 110 | } else { | 114 | } else { |
| 111 | dev_dbg(&priv->udev->dev, | 115 | dev_dbg(&priv->udev->dev, |
| 112 | "Unknown data packet received from the device:" | 116 | "Unknown data packet received from the device:" |
| @@ -188,6 +192,120 @@ static void opticon_close(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 188 | usb_kill_urb(priv->bulk_read_urb); | 192 | usb_kill_urb(priv->bulk_read_urb); |
| 189 | } | 193 | } |
| 190 | 194 | ||
| 195 | static void opticon_write_bulk_callback(struct urb *urb) | ||
| 196 | { | ||
| 197 | struct opticon_private *priv = urb->context; | ||
| 198 | int status = urb->status; | ||
| 199 | unsigned long flags; | ||
| 200 | |||
| 201 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | ||
| 202 | kfree(urb->transfer_buffer); | ||
| 203 | |||
| 204 | if (status) | ||
| 205 | dbg("%s - nonzero write bulk status received: %d", | ||
| 206 | __func__, status); | ||
| 207 | |||
| 208 | spin_lock_irqsave(&priv->lock, flags); | ||
| 209 | --priv->outstanding_urbs; | ||
| 210 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 211 | |||
| 212 | usb_serial_port_softint(priv->port); | ||
| 213 | } | ||
| 214 | |||
| 215 | static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, | ||
| 216 | const unsigned char *buf, int count) | ||
| 217 | { | ||
| 218 | struct opticon_private *priv = usb_get_serial_data(port->serial); | ||
| 219 | struct usb_serial *serial = port->serial; | ||
| 220 | struct urb *urb; | ||
| 221 | unsigned char *buffer; | ||
| 222 | unsigned long flags; | ||
| 223 | int status; | ||
| 224 | |||
| 225 | dbg("%s - port %d", __func__, port->number); | ||
| 226 | |||
| 227 | spin_lock_irqsave(&priv->lock, flags); | ||
| 228 | if (priv->outstanding_urbs > URB_UPPER_LIMIT) { | ||
| 229 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 230 | dbg("%s - write limit hit\n", __func__); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | priv->outstanding_urbs++; | ||
| 234 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 235 | |||
| 236 | buffer = kmalloc(count, GFP_ATOMIC); | ||
| 237 | if (!buffer) { | ||
| 238 | dev_err(&port->dev, "out of memory\n"); | ||
| 239 | count = -ENOMEM; | ||
| 240 | goto error_no_buffer; | ||
| 241 | } | ||
| 242 | |||
| 243 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 244 | if (!urb) { | ||
| 245 | dev_err(&port->dev, "no more free urbs\n"); | ||
| 246 | count = -ENOMEM; | ||
| 247 | goto error_no_urb; | ||
| 248 | } | ||
| 249 | |||
| 250 | memcpy(buffer, buf, count); | ||
| 251 | |||
| 252 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); | ||
| 253 | |||
| 254 | usb_fill_bulk_urb(urb, serial->dev, | ||
| 255 | usb_sndbulkpipe(serial->dev, | ||
| 256 | port->bulk_out_endpointAddress), | ||
| 257 | buffer, count, opticon_write_bulk_callback, priv); | ||
| 258 | |||
| 259 | /* send it down the pipe */ | ||
| 260 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 261 | if (status) { | ||
| 262 | dev_err(&port->dev, | ||
| 263 | "%s - usb_submit_urb(write bulk) failed with status = %d\n", | ||
| 264 | __func__, status); | ||
| 265 | count = status; | ||
| 266 | goto error; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* we are done with this urb, so let the host driver | ||
| 270 | * really free it when it is finished with it */ | ||
| 271 | usb_free_urb(urb); | ||
| 272 | |||
| 273 | return count; | ||
| 274 | error: | ||
| 275 | usb_free_urb(urb); | ||
| 276 | error_no_urb: | ||
| 277 | kfree(buffer); | ||
| 278 | error_no_buffer: | ||
| 279 | spin_lock_irqsave(&priv->lock, flags); | ||
| 280 | --priv->outstanding_urbs; | ||
| 281 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 282 | return count; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int opticon_write_room(struct tty_struct *tty) | ||
| 286 | { | ||
| 287 | struct usb_serial_port *port = tty->driver_data; | ||
| 288 | struct opticon_private *priv = usb_get_serial_data(port->serial); | ||
| 289 | unsigned long flags; | ||
| 290 | |||
| 291 | dbg("%s - port %d", __func__, port->number); | ||
| 292 | |||
| 293 | /* | ||
| 294 | * We really can take almost anything the user throws at us | ||
| 295 | * but let's pick a nice big number to tell the tty | ||
| 296 | * layer that we have lots of free space, unless we don't. | ||
| 297 | */ | ||
| 298 | spin_lock_irqsave(&priv->lock, flags); | ||
| 299 | if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { | ||
| 300 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 301 | dbg("%s - write limit hit\n", __func__); | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 305 | |||
| 306 | return 2048; | ||
| 307 | } | ||
| 308 | |||
| 191 | static void opticon_throttle(struct tty_struct *tty) | 309 | static void opticon_throttle(struct tty_struct *tty) |
| 192 | { | 310 | { |
| 193 | struct usb_serial_port *port = tty->driver_data; | 311 | struct usb_serial_port *port = tty->driver_data; |
| @@ -223,6 +341,67 @@ static void opticon_unthrottle(struct tty_struct *tty) | |||
| 223 | __func__, result); | 341 | __func__, result); |
| 224 | } | 342 | } |
| 225 | 343 | ||
| 344 | static int opticon_tiocmget(struct tty_struct *tty, struct file *file) | ||
| 345 | { | ||
| 346 | struct usb_serial_port *port = tty->driver_data; | ||
| 347 | struct opticon_private *priv = usb_get_serial_data(port->serial); | ||
| 348 | unsigned long flags; | ||
| 349 | int result = 0; | ||
| 350 | |||
| 351 | dbg("%s - port %d", __func__, port->number); | ||
| 352 | |||
| 353 | spin_lock_irqsave(&priv->lock, flags); | ||
| 354 | if (priv->rts) | ||
| 355 | result = TIOCM_RTS; | ||
| 356 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 357 | |||
| 358 | dbg("%s - %x", __func__, result); | ||
| 359 | return result; | ||
| 360 | } | ||
| 361 | |||
| 362 | static int get_serial_info(struct opticon_private *priv, | ||
| 363 | struct serial_struct __user *serial) | ||
| 364 | { | ||
| 365 | struct serial_struct tmp; | ||
| 366 | |||
| 367 | if (!serial) | ||
| 368 | return -EFAULT; | ||
| 369 | |||
| 370 | memset(&tmp, 0x00, sizeof(tmp)); | ||
| 371 | |||
| 372 | /* fake emulate a 16550 uart to make userspace code happy */ | ||
| 373 | tmp.type = PORT_16550A; | ||
| 374 | tmp.line = priv->serial->minor; | ||
| 375 | tmp.port = 0; | ||
| 376 | tmp.irq = 0; | ||
| 377 | tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; | ||
| 378 | tmp.xmit_fifo_size = 1024; | ||
| 379 | tmp.baud_base = 9600; | ||
| 380 | tmp.close_delay = 5*HZ; | ||
| 381 | tmp.closing_wait = 30*HZ; | ||
| 382 | |||
| 383 | if (copy_to_user(serial, &tmp, sizeof(*serial))) | ||
| 384 | return -EFAULT; | ||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int opticon_ioctl(struct tty_struct *tty, struct file *file, | ||
| 389 | unsigned int cmd, unsigned long arg) | ||
| 390 | { | ||
| 391 | struct usb_serial_port *port = tty->driver_data; | ||
| 392 | struct opticon_private *priv = usb_get_serial_data(port->serial); | ||
| 393 | |||
| 394 | dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); | ||
| 395 | |||
| 396 | switch (cmd) { | ||
| 397 | case TIOCGSERIAL: | ||
| 398 | return get_serial_info(priv, | ||
| 399 | (struct serial_struct __user *)arg); | ||
| 400 | } | ||
| 401 | |||
| 402 | return -ENOIOCTLCMD; | ||
| 403 | } | ||
| 404 | |||
| 226 | static int opticon_startup(struct usb_serial *serial) | 405 | static int opticon_startup(struct usb_serial *serial) |
| 227 | { | 406 | { |
| 228 | struct opticon_private *priv; | 407 | struct opticon_private *priv; |
| @@ -306,11 +485,37 @@ static void opticon_shutdown(struct usb_serial *serial) | |||
| 306 | usb_set_serial_data(serial, NULL); | 485 | usb_set_serial_data(serial, NULL); |
| 307 | } | 486 | } |
| 308 | 487 | ||
| 488 | static int opticon_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 489 | { | ||
| 490 | struct usb_serial *serial = usb_get_intfdata(intf); | ||
| 491 | struct opticon_private *priv = usb_get_serial_data(serial); | ||
| 492 | |||
| 493 | usb_kill_urb(priv->bulk_read_urb); | ||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | static int opticon_resume(struct usb_interface *intf) | ||
| 498 | { | ||
| 499 | struct usb_serial *serial = usb_get_intfdata(intf); | ||
| 500 | struct opticon_private *priv = usb_get_serial_data(serial); | ||
| 501 | struct usb_serial_port *port = serial->port[0]; | ||
| 502 | int result; | ||
| 503 | |||
| 504 | mutex_lock(&port->mutex); | ||
| 505 | if (port->port.count) | ||
| 506 | result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO); | ||
| 507 | else | ||
| 508 | result = 0; | ||
| 509 | mutex_unlock(&port->mutex); | ||
| 510 | return result; | ||
| 511 | } | ||
| 309 | 512 | ||
| 310 | static struct usb_driver opticon_driver = { | 513 | static struct usb_driver opticon_driver = { |
| 311 | .name = "opticon", | 514 | .name = "opticon", |
| 312 | .probe = usb_serial_probe, | 515 | .probe = usb_serial_probe, |
| 313 | .disconnect = usb_serial_disconnect, | 516 | .disconnect = usb_serial_disconnect, |
| 517 | .suspend = opticon_suspend, | ||
| 518 | .resume = opticon_resume, | ||
| 314 | .id_table = id_table, | 519 | .id_table = id_table, |
| 315 | .no_dynamic_id = 1, | 520 | .no_dynamic_id = 1, |
| 316 | }; | 521 | }; |
| @@ -326,9 +531,13 @@ static struct usb_serial_driver opticon_device = { | |||
| 326 | .attach = opticon_startup, | 531 | .attach = opticon_startup, |
| 327 | .open = opticon_open, | 532 | .open = opticon_open, |
| 328 | .close = opticon_close, | 533 | .close = opticon_close, |
| 534 | .write = opticon_write, | ||
| 535 | .write_room = opticon_write_room, | ||
| 329 | .shutdown = opticon_shutdown, | 536 | .shutdown = opticon_shutdown, |
| 330 | .throttle = opticon_throttle, | 537 | .throttle = opticon_throttle, |
| 331 | .unthrottle = opticon_unthrottle, | 538 | .unthrottle = opticon_unthrottle, |
| 539 | .ioctl = opticon_ioctl, | ||
| 540 | .tiocmget = opticon_tiocmget, | ||
| 332 | }; | 541 | }; |
| 333 | 542 | ||
| 334 | static int __init opticon_init(void) | 543 | static int __init opticon_init(void) |
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 61ebddc48497..d560c0b54e6e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
| @@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file); | |||
| 62 | static int option_tiocmset(struct tty_struct *tty, struct file *file, | 62 | static int option_tiocmset(struct tty_struct *tty, struct file *file, |
| 63 | unsigned int set, unsigned int clear); | 63 | unsigned int set, unsigned int clear); |
| 64 | static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); | 64 | static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); |
| 65 | static int option_suspend(struct usb_serial *serial, pm_message_t message); | ||
| 66 | static int option_resume(struct usb_serial *serial); | ||
| 65 | 67 | ||
| 66 | /* Vendor and product IDs */ | 68 | /* Vendor and product IDs */ |
| 67 | #define OPTION_VENDOR_ID 0x0AF0 | 69 | #define OPTION_VENDOR_ID 0x0AF0 |
| @@ -523,6 +525,8 @@ static struct usb_driver option_driver = { | |||
| 523 | .name = "option", | 525 | .name = "option", |
| 524 | .probe = usb_serial_probe, | 526 | .probe = usb_serial_probe, |
| 525 | .disconnect = usb_serial_disconnect, | 527 | .disconnect = usb_serial_disconnect, |
| 528 | .suspend = usb_serial_suspend, | ||
| 529 | .resume = usb_serial_resume, | ||
| 526 | .id_table = option_ids, | 530 | .id_table = option_ids, |
| 527 | .no_dynamic_id = 1, | 531 | .no_dynamic_id = 1, |
| 528 | }; | 532 | }; |
| @@ -551,6 +555,8 @@ static struct usb_serial_driver option_1port_device = { | |||
| 551 | .attach = option_startup, | 555 | .attach = option_startup, |
| 552 | .shutdown = option_shutdown, | 556 | .shutdown = option_shutdown, |
| 553 | .read_int_callback = option_instat_callback, | 557 | .read_int_callback = option_instat_callback, |
| 558 | .suspend = option_suspend, | ||
| 559 | .resume = option_resume, | ||
| 554 | }; | 560 | }; |
| 555 | 561 | ||
| 556 | static int debug; | 562 | static int debug; |
| @@ -821,10 +827,10 @@ static void option_instat_callback(struct urb *urb) | |||
| 821 | req_pkt->bRequestType, req_pkt->bRequest); | 827 | req_pkt->bRequestType, req_pkt->bRequest); |
| 822 | } | 828 | } |
| 823 | } else | 829 | } else |
| 824 | dbg("%s: error %d", __func__, status); | 830 | err("%s: error %d", __func__, status); |
| 825 | 831 | ||
| 826 | /* Resubmit urb so we continue receiving IRQ data */ | 832 | /* Resubmit urb so we continue receiving IRQ data */ |
| 827 | if (status != -ESHUTDOWN) { | 833 | if (status != -ESHUTDOWN && status != -ENOENT) { |
| 828 | urb->dev = serial->dev; | 834 | urb->dev = serial->dev; |
| 829 | err = usb_submit_urb(urb, GFP_ATOMIC); | 835 | err = usb_submit_urb(urb, GFP_ATOMIC); |
| 830 | if (err) | 836 | if (err) |
| @@ -843,7 +849,6 @@ static int option_write_room(struct tty_struct *tty) | |||
| 843 | 849 | ||
| 844 | portdata = usb_get_serial_port_data(port); | 850 | portdata = usb_get_serial_port_data(port); |
| 845 | 851 | ||
| 846 | |||
| 847 | for (i = 0; i < N_OUT_URB; i++) { | 852 | for (i = 0; i < N_OUT_URB; i++) { |
| 848 | this_urb = portdata->out_urbs[i]; | 853 | this_urb = portdata->out_urbs[i]; |
| 849 | if (this_urb && !test_bit(i, &portdata->out_busy)) | 854 | if (this_urb && !test_bit(i, &portdata->out_busy)) |
| @@ -1105,14 +1110,12 @@ bail_out_error: | |||
| 1105 | return 1; | 1110 | return 1; |
| 1106 | } | 1111 | } |
| 1107 | 1112 | ||
| 1108 | static void option_shutdown(struct usb_serial *serial) | 1113 | static void stop_read_write_urbs(struct usb_serial *serial) |
| 1109 | { | 1114 | { |
| 1110 | int i, j; | 1115 | int i, j; |
| 1111 | struct usb_serial_port *port; | 1116 | struct usb_serial_port *port; |
| 1112 | struct option_port_private *portdata; | 1117 | struct option_port_private *portdata; |
| 1113 | 1118 | ||
| 1114 | dbg("%s", __func__); | ||
| 1115 | |||
| 1116 | /* Stop reading/writing urbs */ | 1119 | /* Stop reading/writing urbs */ |
| 1117 | for (i = 0; i < serial->num_ports; ++i) { | 1120 | for (i = 0; i < serial->num_ports; ++i) { |
| 1118 | port = serial->port[i]; | 1121 | port = serial->port[i]; |
| @@ -1122,6 +1125,17 @@ static void option_shutdown(struct usb_serial *serial) | |||
| 1122 | for (j = 0; j < N_OUT_URB; j++) | 1125 | for (j = 0; j < N_OUT_URB; j++) |
| 1123 | usb_kill_urb(portdata->out_urbs[j]); | 1126 | usb_kill_urb(portdata->out_urbs[j]); |
| 1124 | } | 1127 | } |
| 1128 | } | ||
| 1129 | |||
| 1130 | static void option_shutdown(struct usb_serial *serial) | ||
| 1131 | { | ||
| 1132 | int i, j; | ||
| 1133 | struct usb_serial_port *port; | ||
| 1134 | struct option_port_private *portdata; | ||
| 1135 | |||
| 1136 | dbg("%s", __func__); | ||
| 1137 | |||
| 1138 | stop_read_write_urbs(serial); | ||
| 1125 | 1139 | ||
| 1126 | /* Now free them */ | 1140 | /* Now free them */ |
| 1127 | for (i = 0; i < serial->num_ports; ++i) { | 1141 | for (i = 0; i < serial->num_ports; ++i) { |
| @@ -1152,6 +1166,66 @@ static void option_shutdown(struct usb_serial *serial) | |||
| 1152 | } | 1166 | } |
| 1153 | } | 1167 | } |
| 1154 | 1168 | ||
| 1169 | static int option_suspend(struct usb_serial *serial, pm_message_t message) | ||
| 1170 | { | ||
| 1171 | dbg("%s entered", __func__); | ||
| 1172 | stop_read_write_urbs(serial); | ||
| 1173 | |||
| 1174 | return 0; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | static int option_resume(struct usb_serial *serial) | ||
| 1178 | { | ||
| 1179 | int err, i, j; | ||
| 1180 | struct usb_serial_port *port; | ||
| 1181 | struct urb *urb; | ||
| 1182 | struct option_port_private *portdata; | ||
| 1183 | |||
| 1184 | dbg("%s entered", __func__); | ||
| 1185 | /* get the interrupt URBs resubmitted unconditionally */ | ||
| 1186 | for (i = 0; i < serial->num_ports; i++) { | ||
| 1187 | port = serial->port[i]; | ||
| 1188 | if (!port->interrupt_in_urb) { | ||
| 1189 | dbg("%s: No interrupt URB for port %d\n", __func__, i); | ||
| 1190 | continue; | ||
| 1191 | } | ||
| 1192 | port->interrupt_in_urb->dev = serial->dev; | ||
| 1193 | err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); | ||
| 1194 | dbg("Submitted interrupt URB for port %d (result %d)", i, err); | ||
| 1195 | if (err < 0) { | ||
| 1196 | err("%s: Error %d for interrupt URB of port%d", | ||
| 1197 | __func__, err, i); | ||
| 1198 | return err; | ||
| 1199 | } | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | for (i = 0; i < serial->num_ports; i++) { | ||
| 1203 | /* walk all ports */ | ||
| 1204 | port = serial->port[i]; | ||
| 1205 | portdata = usb_get_serial_port_data(port); | ||
| 1206 | mutex_lock(&port->mutex); | ||
| 1207 | |||
| 1208 | /* skip closed ports */ | ||
| 1209 | if (!port->port.count) { | ||
| 1210 | mutex_unlock(&port->mutex); | ||
| 1211 | continue; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | for (j = 0; j < N_IN_URB; j++) { | ||
| 1215 | urb = portdata->in_urbs[j]; | ||
| 1216 | err = usb_submit_urb(urb, GFP_NOIO); | ||
| 1217 | if (err < 0) { | ||
| 1218 | mutex_unlock(&port->mutex); | ||
| 1219 | err("%s: Error %d for bulk URB %d", | ||
| 1220 | __func__, err, i); | ||
| 1221 | return err; | ||
| 1222 | } | ||
| 1223 | } | ||
| 1224 | mutex_unlock(&port->mutex); | ||
| 1225 | } | ||
| 1226 | return 0; | ||
| 1227 | } | ||
| 1228 | |||
| 1155 | MODULE_AUTHOR(DRIVER_AUTHOR); | 1229 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 1156 | MODULE_DESCRIPTION(DRIVER_DESC); | 1230 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 1157 | MODULE_VERSION(DRIVER_VERSION); | 1231 | MODULE_VERSION(DRIVER_VERSION); |
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c new file mode 100644 index 000000000000..e6d6b0c17fd9 --- /dev/null +++ b/drivers/usb/serial/qcserial.c | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | /* | ||
| 2 | * Qualcomm Serial USB driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008 QUALCOMM Incorporated. | ||
| 5 | * Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de> | ||
| 6 | * Copyright (c) 2009 Novell Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License version | ||
| 10 | * 2 as published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/tty.h> | ||
| 15 | #include <linux/tty_flip.h> | ||
| 16 | #include <linux/usb.h> | ||
| 17 | #include <linux/usb/serial.h> | ||
| 18 | |||
| 19 | #define DRIVER_AUTHOR "Qualcomm Inc" | ||
| 20 | #define DRIVER_DESC "Qualcomm USB Serial driver" | ||
| 21 | |||
| 22 | static int debug; | ||
| 23 | |||
| 24 | static struct usb_device_id id_table[] = { | ||
| 25 | {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ | ||
| 26 | {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ | ||
| 27 | {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ | ||
| 28 | {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ | ||
| 29 | { } /* Terminating entry */ | ||
| 30 | }; | ||
| 31 | MODULE_DEVICE_TABLE(usb, id_table); | ||
| 32 | |||
| 33 | static struct usb_driver qcdriver = { | ||
| 34 | .name = "qcserial", | ||
| 35 | .probe = usb_serial_probe, | ||
| 36 | .disconnect = usb_serial_disconnect, | ||
| 37 | .id_table = id_table, | ||
| 38 | .suspend = usb_serial_suspend, | ||
| 39 | .resume = usb_serial_resume, | ||
| 40 | .supports_autosuspend = true, | ||
| 41 | }; | ||
| 42 | |||
| 43 | static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) | ||
| 44 | { | ||
| 45 | int retval = -ENODEV; | ||
| 46 | __u8 nintf; | ||
| 47 | __u8 ifnum; | ||
| 48 | |||
| 49 | dbg("%s", __func__); | ||
| 50 | |||
| 51 | nintf = serial->dev->actconfig->desc.bNumInterfaces; | ||
| 52 | dbg("Num Interfaces = %d", nintf); | ||
| 53 | ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; | ||
| 54 | dbg("This Interface = %d", ifnum); | ||
| 55 | |||
| 56 | switch (nintf) { | ||
| 57 | case 1: | ||
| 58 | /* QDL mode */ | ||
| 59 | if (serial->interface->num_altsetting == 2) { | ||
| 60 | struct usb_host_interface *intf; | ||
| 61 | |||
| 62 | intf = &serial->interface->altsetting[1]; | ||
| 63 | if (intf->desc.bNumEndpoints == 2) { | ||
| 64 | if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && | ||
| 65 | usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { | ||
| 66 | dbg("QDL port found"); | ||
| 67 | retval = usb_set_interface(serial->dev, ifnum, 1); | ||
| 68 | if (retval < 0) { | ||
| 69 | dev_err(&serial->dev->dev, | ||
| 70 | "Could not set interface, error %d\n", | ||
| 71 | retval); | ||
| 72 | retval = -ENODEV; | ||
| 73 | } | ||
| 74 | return retval; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | break; | ||
| 79 | |||
| 80 | case 4: | ||
| 81 | /* Composite mode */ | ||
| 82 | if (ifnum == 2) { | ||
| 83 | dbg("Modem port found"); | ||
| 84 | retval = usb_set_interface(serial->dev, ifnum, 0); | ||
| 85 | if (retval < 0) { | ||
| 86 | dev_err(&serial->dev->dev, | ||
| 87 | "Could not set interface, error %d\n", | ||
| 88 | retval); | ||
| 89 | retval = -ENODEV; | ||
| 90 | } | ||
| 91 | return retval; | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | |||
| 95 | default: | ||
| 96 | dev_err(&serial->dev->dev, | ||
| 97 | "unknown number of interfaces: %d\n", nintf); | ||
| 98 | return -ENODEV; | ||
| 99 | } | ||
| 100 | |||
| 101 | return retval; | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct usb_serial_driver qcdevice = { | ||
| 105 | .driver = { | ||
| 106 | .owner = THIS_MODULE, | ||
| 107 | .name = "qcserial", | ||
| 108 | }, | ||
| 109 | .description = "Qualcomm USB modem", | ||
| 110 | .id_table = id_table, | ||
| 111 | .usb_driver = &qcdriver, | ||
| 112 | .num_ports = 1, | ||
| 113 | .probe = qcprobe, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static int __init qcinit(void) | ||
| 117 | { | ||
| 118 | int retval; | ||
| 119 | |||
| 120 | retval = usb_serial_register(&qcdevice); | ||
| 121 | if (retval) | ||
| 122 | return retval; | ||
| 123 | |||
| 124 | retval = usb_register(&qcdriver); | ||
| 125 | if (retval) { | ||
| 126 | usb_serial_deregister(&qcdevice); | ||
| 127 | return retval; | ||
| 128 | } | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static void __exit qcexit(void) | ||
| 134 | { | ||
| 135 | usb_deregister(&qcdriver); | ||
| 136 | usb_serial_deregister(&qcdevice); | ||
| 137 | } | ||
| 138 | |||
| 139 | module_init(qcinit); | ||
| 140 | module_exit(qcexit); | ||
| 141 | |||
| 142 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 143 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 144 | MODULE_LICENSE("GPL v2"); | ||
| 145 | |||
| 146 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 147 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c new file mode 100644 index 000000000000..8b3cbc87adc7 --- /dev/null +++ b/drivers/usb/serial/symbolserial.c | |||
| @@ -0,0 +1,399 @@ | |||
| 1 | /* | ||
| 2 | * Symbol USB barcode to serial driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de> | ||
| 5 | * Copyright (C) 2009 Novell Inc. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License version | ||
| 9 | * 2 as published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/tty.h> | ||
| 15 | #include <linux/tty_driver.h> | ||
| 16 | #include <linux/tty_flip.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/usb.h> | ||
| 19 | #include <linux/usb/serial.h> | ||
| 20 | #include <linux/uaccess.h> | ||
| 21 | |||
| 22 | static int debug; | ||
| 23 | |||
| 24 | static struct usb_device_id id_table[] = { | ||
| 25 | { USB_DEVICE(0x05e0, 0x0600) }, | ||
| 26 | { }, | ||
| 27 | }; | ||
| 28 | MODULE_DEVICE_TABLE(usb, id_table); | ||
| 29 | |||
| 30 | /* This structure holds all of the individual device information */ | ||
| 31 | struct symbol_private { | ||
| 32 | struct usb_device *udev; | ||
| 33 | struct usb_serial *serial; | ||
| 34 | struct usb_serial_port *port; | ||
| 35 | unsigned char *int_buffer; | ||
| 36 | struct urb *int_urb; | ||
| 37 | int buffer_size; | ||
| 38 | u8 bInterval; | ||
| 39 | u8 int_address; | ||
| 40 | spinlock_t lock; /* protects the following flags */ | ||
| 41 | bool throttled; | ||
| 42 | bool actually_throttled; | ||
| 43 | bool rts; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static void symbol_int_callback(struct urb *urb) | ||
| 47 | { | ||
| 48 | struct symbol_private *priv = urb->context; | ||
| 49 | unsigned char *data = urb->transfer_buffer; | ||
| 50 | struct usb_serial_port *port = priv->port; | ||
| 51 | int status = urb->status; | ||
| 52 | struct tty_struct *tty; | ||
| 53 | int result; | ||
| 54 | int available_room = 0; | ||
| 55 | int data_length; | ||
| 56 | |||
| 57 | dbg("%s - port %d", __func__, port->number); | ||
| 58 | |||
| 59 | switch (status) { | ||
| 60 | case 0: | ||
| 61 | /* success */ | ||
| 62 | break; | ||
| 63 | case -ECONNRESET: | ||
| 64 | case -ENOENT: | ||
| 65 | case -ESHUTDOWN: | ||
| 66 | /* this urb is terminated, clean up */ | ||
| 67 | dbg("%s - urb shutting down with status: %d", | ||
| 68 | __func__, status); | ||
| 69 | return; | ||
| 70 | default: | ||
| 71 | dbg("%s - nonzero urb status received: %d", | ||
| 72 | __func__, status); | ||
| 73 | goto exit; | ||
| 74 | } | ||
| 75 | |||
| 76 | usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, | ||
| 77 | data); | ||
| 78 | |||
| 79 | if (urb->actual_length > 1) { | ||
| 80 | data_length = urb->actual_length - 1; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Data from the device comes with a 1 byte header: | ||
| 84 | * | ||
| 85 | * <size of data>data... | ||
| 86 | * This is real data to be sent to the tty layer | ||
| 87 | * we pretty much just ignore the size and send everything | ||
| 88 | * else to the tty layer. | ||
| 89 | */ | ||
| 90 | tty = tty_port_tty_get(&port->port); | ||
| 91 | if (tty) { | ||
| 92 | available_room = tty_buffer_request_room(tty, | ||
| 93 | data_length); | ||
| 94 | if (available_room) { | ||
| 95 | tty_insert_flip_string(tty, &data[1], | ||
| 96 | available_room); | ||
| 97 | tty_flip_buffer_push(tty); | ||
| 98 | } | ||
| 99 | tty_kref_put(tty); | ||
| 100 | } | ||
| 101 | } else { | ||
| 102 | dev_dbg(&priv->udev->dev, | ||
| 103 | "Improper ammount of data received from the device, " | ||
| 104 | "%d bytes", urb->actual_length); | ||
| 105 | } | ||
| 106 | |||
| 107 | exit: | ||
| 108 | spin_lock(&priv->lock); | ||
| 109 | |||
| 110 | /* Continue trying to always read if we should */ | ||
| 111 | if (!priv->throttled) { | ||
| 112 | usb_fill_int_urb(priv->int_urb, priv->udev, | ||
| 113 | usb_rcvintpipe(priv->udev, | ||
| 114 | priv->int_address), | ||
| 115 | priv->int_buffer, priv->buffer_size, | ||
| 116 | symbol_int_callback, priv, priv->bInterval); | ||
| 117 | result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); | ||
| 118 | if (result) | ||
| 119 | dev_err(&port->dev, | ||
| 120 | "%s - failed resubmitting read urb, error %d\n", | ||
| 121 | __func__, result); | ||
| 122 | } else | ||
| 123 | priv->actually_throttled = true; | ||
| 124 | spin_unlock(&priv->lock); | ||
| 125 | } | ||
| 126 | |||
| 127 | static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port, | ||
| 128 | struct file *filp) | ||
| 129 | { | ||
| 130 | struct symbol_private *priv = usb_get_serial_data(port->serial); | ||
| 131 | unsigned long flags; | ||
| 132 | int result = 0; | ||
| 133 | |||
| 134 | dbg("%s - port %d", __func__, port->number); | ||
| 135 | |||
| 136 | spin_lock_irqsave(&priv->lock, flags); | ||
| 137 | priv->throttled = false; | ||
| 138 | priv->actually_throttled = false; | ||
| 139 | priv->port = port; | ||
| 140 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Force low_latency on so that our tty_push actually forces the data | ||
| 144 | * through, otherwise it is scheduled, and with high data rates (like | ||
| 145 | * with OHCI) data can get lost. | ||
| 146 | */ | ||
| 147 | if (tty) | ||
| 148 | tty->low_latency = 1; | ||
| 149 | |||
| 150 | /* Start reading from the device */ | ||
| 151 | usb_fill_int_urb(priv->int_urb, priv->udev, | ||
| 152 | usb_rcvintpipe(priv->udev, priv->int_address), | ||
| 153 | priv->int_buffer, priv->buffer_size, | ||
| 154 | symbol_int_callback, priv, priv->bInterval); | ||
| 155 | result = usb_submit_urb(priv->int_urb, GFP_KERNEL); | ||
| 156 | if (result) | ||
| 157 | dev_err(&port->dev, | ||
| 158 | "%s - failed resubmitting read urb, error %d\n", | ||
| 159 | __func__, result); | ||
| 160 | return result; | ||
| 161 | } | ||
| 162 | |||
| 163 | static void symbol_close(struct tty_struct *tty, struct usb_serial_port *port, | ||
| 164 | struct file *filp) | ||
| 165 | { | ||
| 166 | struct symbol_private *priv = usb_get_serial_data(port->serial); | ||
| 167 | |||
| 168 | dbg("%s - port %d", __func__, port->number); | ||
| 169 | |||
| 170 | /* shutdown our urbs */ | ||
| 171 | usb_kill_urb(priv->int_urb); | ||
| 172 | } | ||
| 173 | |||
| 174 | static void symbol_throttle(struct tty_struct *tty) | ||
| 175 | { | ||
| 176 | struct usb_serial_port *port = tty->driver_data; | ||
| 177 | struct symbol_private *priv = usb_get_serial_data(port->serial); | ||
| 178 | unsigned long flags; | ||
| 179 | |||
| 180 | dbg("%s - port %d", __func__, port->number); | ||
| 181 | spin_lock_irqsave(&priv->lock, flags); | ||
| 182 | priv->throttled = true; | ||
| 183 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 184 | } | ||
| 185 | |||
| 186 | static void symbol_unthrottle(struct tty_struct *tty) | ||
| 187 | { | ||
| 188 | struct usb_serial_port *port = tty->driver_data; | ||
| 189 | struct symbol_private *priv = usb_get_serial_data(port->serial); | ||
| 190 | unsigned long flags; | ||
| 191 | int result; | ||
| 192 | |||
| 193 | dbg("%s - port %d", __func__, port->number); | ||
| 194 | |||
| 195 | spin_lock_irqsave(&priv->lock, flags); | ||
| 196 | priv->throttled = false; | ||
| 197 | priv->actually_throttled = false; | ||
| 198 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 199 | |||
| 200 | priv->int_urb->dev = port->serial->dev; | ||
| 201 | result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); | ||
| 202 | if (result) | ||
| 203 | dev_err(&port->dev, | ||
| 204 | "%s - failed submitting read urb, error %d\n", | ||
| 205 | __func__, result); | ||
| 206 | } | ||
| 207 | |||
| 208 | static int symbol_ioctl(struct tty_struct *tty, struct file *file, | ||
| 209 | unsigned int cmd, unsigned long arg) | ||
| 210 | { | ||
| 211 | struct usb_serial_port *port = tty->driver_data; | ||
| 212 | struct device *dev = &port->dev; | ||
| 213 | |||
| 214 | /* | ||
| 215 | * Right now we need to figure out what commands | ||
| 216 | * most userspace tools want to see for this driver, | ||
| 217 | * so just log the things. | ||
| 218 | */ | ||
| 219 | switch (cmd) { | ||
| 220 | case TIOCSERGETLSR: | ||
| 221 | dev_info(dev, "%s: TIOCSERGETLSR\n", __func__); | ||
| 222 | break; | ||
| 223 | |||
| 224 | case TIOCGSERIAL: | ||
| 225 | dev_info(dev, "%s: TIOCGSERIAL\n", __func__); | ||
| 226 | break; | ||
| 227 | |||
| 228 | case TIOCMIWAIT: | ||
| 229 | dev_info(dev, "%s: TIOCMIWAIT\n", __func__); | ||
| 230 | break; | ||
| 231 | |||
| 232 | case TIOCGICOUNT: | ||
| 233 | dev_info(dev, "%s: TIOCGICOUNT\n", __func__); | ||
| 234 | break; | ||
| 235 | default: | ||
| 236 | dev_info(dev, "%s: unknown (%d)\n", __func__, cmd); | ||
| 237 | } | ||
| 238 | return -ENOIOCTLCMD; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int symbol_tiocmget(struct tty_struct *tty, struct file *file) | ||
| 242 | { | ||
| 243 | struct usb_serial_port *port = tty->driver_data; | ||
| 244 | struct device *dev = &port->dev; | ||
| 245 | |||
| 246 | /* TODO */ | ||
| 247 | /* probably just need to shadow whatever was sent to us here */ | ||
| 248 | dev_info(dev, "%s\n", __func__); | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int symbol_tiocmset(struct tty_struct *tty, struct file *file, | ||
| 253 | unsigned int set, unsigned int clear) | ||
| 254 | { | ||
| 255 | struct usb_serial_port *port = tty->driver_data; | ||
| 256 | struct device *dev = &port->dev; | ||
| 257 | |||
| 258 | /* TODO */ | ||
| 259 | /* probably just need to shadow whatever was sent to us here */ | ||
| 260 | dev_info(dev, "%s\n", __func__); | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int symbol_startup(struct usb_serial *serial) | ||
| 265 | { | ||
| 266 | struct symbol_private *priv; | ||
| 267 | struct usb_host_interface *intf; | ||
| 268 | int i; | ||
| 269 | int retval = -ENOMEM; | ||
| 270 | bool int_in_found = false; | ||
| 271 | |||
| 272 | /* create our private serial structure */ | ||
| 273 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
| 274 | if (priv == NULL) { | ||
| 275 | dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); | ||
| 276 | return -ENOMEM; | ||
| 277 | } | ||
| 278 | spin_lock_init(&priv->lock); | ||
| 279 | priv->serial = serial; | ||
| 280 | priv->port = serial->port[0]; | ||
| 281 | priv->udev = serial->dev; | ||
| 282 | |||
| 283 | /* find our interrupt endpoint */ | ||
| 284 | intf = serial->interface->altsetting; | ||
| 285 | for (i = 0; i < intf->desc.bNumEndpoints; ++i) { | ||
| 286 | struct usb_endpoint_descriptor *endpoint; | ||
| 287 | |||
| 288 | endpoint = &intf->endpoint[i].desc; | ||
| 289 | if (!usb_endpoint_is_int_in(endpoint)) | ||
| 290 | continue; | ||
| 291 | |||
| 292 | priv->int_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 293 | if (!priv->int_urb) { | ||
| 294 | dev_err(&priv->udev->dev, "out of memory\n"); | ||
| 295 | goto error; | ||
| 296 | } | ||
| 297 | |||
| 298 | priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2; | ||
| 299 | priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); | ||
| 300 | if (!priv->int_buffer) { | ||
| 301 | dev_err(&priv->udev->dev, "out of memory\n"); | ||
| 302 | goto error; | ||
| 303 | } | ||
| 304 | |||
| 305 | priv->int_address = endpoint->bEndpointAddress; | ||
| 306 | priv->bInterval = endpoint->bInterval; | ||
| 307 | |||
| 308 | /* set up our int urb */ | ||
| 309 | usb_fill_int_urb(priv->int_urb, priv->udev, | ||
| 310 | usb_rcvintpipe(priv->udev, | ||
| 311 | endpoint->bEndpointAddress), | ||
| 312 | priv->int_buffer, priv->buffer_size, | ||
| 313 | symbol_int_callback, priv, priv->bInterval); | ||
| 314 | |||
| 315 | int_in_found = true; | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | |||
| 319 | if (!int_in_found) { | ||
| 320 | dev_err(&priv->udev->dev, | ||
| 321 | "Error - the proper endpoints were not found!\n"); | ||
| 322 | goto error; | ||
| 323 | } | ||
| 324 | |||
| 325 | usb_set_serial_data(serial, priv); | ||
| 326 | return 0; | ||
| 327 | |||
| 328 | error: | ||
| 329 | usb_free_urb(priv->int_urb); | ||
| 330 | kfree(priv->int_buffer); | ||
| 331 | kfree(priv); | ||
| 332 | return retval; | ||
| 333 | } | ||
| 334 | |||
| 335 | static void symbol_shutdown(struct usb_serial *serial) | ||
| 336 | { | ||
| 337 | struct symbol_private *priv = usb_get_serial_data(serial); | ||
| 338 | |||
| 339 | dbg("%s", __func__); | ||
| 340 | |||
| 341 | usb_kill_urb(priv->int_urb); | ||
| 342 | usb_free_urb(priv->int_urb); | ||
| 343 | kfree(priv->int_buffer); | ||
| 344 | kfree(priv); | ||
| 345 | usb_set_serial_data(serial, NULL); | ||
| 346 | } | ||
| 347 | |||
| 348 | static struct usb_driver symbol_driver = { | ||
| 349 | .name = "symbol", | ||
| 350 | .probe = usb_serial_probe, | ||
| 351 | .disconnect = usb_serial_disconnect, | ||
| 352 | .id_table = id_table, | ||
| 353 | .no_dynamic_id = 1, | ||
| 354 | }; | ||
| 355 | |||
| 356 | static struct usb_serial_driver symbol_device = { | ||
| 357 | .driver = { | ||
| 358 | .owner = THIS_MODULE, | ||
| 359 | .name = "symbol", | ||
| 360 | }, | ||
| 361 | .id_table = id_table, | ||
| 362 | .usb_driver = &symbol_driver, | ||
| 363 | .num_ports = 1, | ||
| 364 | .attach = symbol_startup, | ||
| 365 | .open = symbol_open, | ||
| 366 | .close = symbol_close, | ||
| 367 | .shutdown = symbol_shutdown, | ||
| 368 | .throttle = symbol_throttle, | ||
| 369 | .unthrottle = symbol_unthrottle, | ||
| 370 | .ioctl = symbol_ioctl, | ||
| 371 | .tiocmget = symbol_tiocmget, | ||
| 372 | .tiocmset = symbol_tiocmset, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int __init symbol_init(void) | ||
| 376 | { | ||
| 377 | int retval; | ||
| 378 | |||
| 379 | retval = usb_serial_register(&symbol_device); | ||
| 380 | if (retval) | ||
| 381 | return retval; | ||
| 382 | retval = usb_register(&symbol_driver); | ||
| 383 | if (retval) | ||
| 384 | usb_serial_deregister(&symbol_device); | ||
| 385 | return retval; | ||
| 386 | } | ||
| 387 | |||
| 388 | static void __exit symbol_exit(void) | ||
| 389 | { | ||
| 390 | usb_deregister(&symbol_driver); | ||
| 391 | usb_serial_deregister(&symbol_device); | ||
| 392 | } | ||
| 393 | |||
| 394 | module_init(symbol_init); | ||
| 395 | module_exit(symbol_exit); | ||
| 396 | MODULE_LICENSE("GPL"); | ||
| 397 | |||
| 398 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 399 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index cfcfd5ab06ce..742a5bc44be8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -204,6 +204,11 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
| 204 | goto bailout_kref_put; | 204 | goto bailout_kref_put; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | if (port->serial->disconnected) { | ||
| 208 | retval = -ENODEV; | ||
| 209 | goto bailout_kref_put; | ||
| 210 | } | ||
| 211 | |||
| 207 | if (mutex_lock_interruptible(&port->mutex)) { | 212 | if (mutex_lock_interruptible(&port->mutex)) { |
| 208 | retval = -ERESTARTSYS; | 213 | retval = -ERESTARTSYS; |
| 209 | goto bailout_kref_put; | 214 | goto bailout_kref_put; |
| @@ -1067,6 +1072,8 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 1067 | struct usb_serial_port *port; | 1072 | struct usb_serial_port *port; |
| 1068 | int i, r = 0; | 1073 | int i, r = 0; |
| 1069 | 1074 | ||
| 1075 | serial->suspending = 1; | ||
| 1076 | |||
| 1070 | for (i = 0; i < serial->num_ports; ++i) { | 1077 | for (i = 0; i < serial->num_ports; ++i) { |
| 1071 | port = serial->port[i]; | 1078 | port = serial->port[i]; |
| 1072 | if (port) | 1079 | if (port) |
| @@ -1083,10 +1090,15 @@ EXPORT_SYMBOL(usb_serial_suspend); | |||
| 1083 | int usb_serial_resume(struct usb_interface *intf) | 1090 | int usb_serial_resume(struct usb_interface *intf) |
| 1084 | { | 1091 | { |
| 1085 | struct usb_serial *serial = usb_get_intfdata(intf); | 1092 | struct usb_serial *serial = usb_get_intfdata(intf); |
| 1093 | int rv; | ||
| 1086 | 1094 | ||
| 1095 | serial->suspending = 0; | ||
| 1087 | if (serial->type->resume) | 1096 | if (serial->type->resume) |
| 1088 | return serial->type->resume(serial); | 1097 | rv = serial->type->resume(serial); |
| 1089 | return 0; | 1098 | else |
| 1099 | rv = usb_serial_generic_resume(serial); | ||
| 1100 | |||
| 1101 | return rv; | ||
| 1090 | } | 1102 | } |
| 1091 | EXPORT_SYMBOL(usb_serial_resume); | 1103 | EXPORT_SYMBOL(usb_serial_resume); |
| 1092 | 1104 | ||
| @@ -1222,7 +1234,6 @@ static void fixup_generic(struct usb_serial_driver *device) | |||
| 1222 | set_to_generic_if_null(device, read_bulk_callback); | 1234 | set_to_generic_if_null(device, read_bulk_callback); |
| 1223 | set_to_generic_if_null(device, write_bulk_callback); | 1235 | set_to_generic_if_null(device, write_bulk_callback); |
| 1224 | set_to_generic_if_null(device, shutdown); | 1236 | set_to_generic_if_null(device, shutdown); |
| 1225 | set_to_generic_if_null(device, resume); | ||
| 1226 | } | 1237 | } |
| 1227 | 1238 | ||
| 1228 | int usb_serial_register(struct usb_serial_driver *driver) | 1239 | int usb_serial_register(struct usb_serial_driver *driver) |
| @@ -1230,6 +1241,9 @@ int usb_serial_register(struct usb_serial_driver *driver) | |||
| 1230 | /* must be called with BKL held */ | 1241 | /* must be called with BKL held */ |
| 1231 | int retval; | 1242 | int retval; |
| 1232 | 1243 | ||
| 1244 | if (usb_disabled()) | ||
| 1245 | return -ENODEV; | ||
| 1246 | |||
| 1233 | fixup_generic(driver); | 1247 | fixup_generic(driver); |
| 1234 | 1248 | ||
| 1235 | if (!driver->description) | 1249 | if (!driver->description) |
