]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/usb/serial/kobil_sct.c
USB: serial: kobil_sct: fix modem-status error handling
[mirror_ubuntu-bionic-kernel.git] / drivers / usb / serial / kobil_sct.c
CommitLineData
5fd54ace 1// SPDX-License-Identifier: GPL-2.0+
1da177e4
LT
2/*
3 * KOBIL USB Smart Card Terminal Driver
4 *
dee0a7cc 5 * Copyright (C) 2002 KOBIL Systems GmbH
1da177e4
LT
6 * Author: Thomas Wahrenbruch
7 *
8 * Contact: linuxusb@kobil.de
9 *
10 * This program is largely derived from work by the linux-usb group
11 * and associated source files. Please see the usb/serial files for
12 * individual credits and copyrights.
13 *
1da177e4
LT
14 * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
15 * patience.
16 *
17 * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
18 * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
1da177e4
LT
19 */
20
21
1da177e4
LT
22#include <linux/kernel.h>
23#include <linux/errno.h>
1da177e4
LT
24#include <linux/slab.h>
25#include <linux/tty.h>
26#include <linux/tty_driver.h>
27#include <linux/tty_flip.h>
28#include <linux/module.h>
29#include <linux/spinlock.h>
dee0a7cc 30#include <linux/uaccess.h>
1da177e4 31#include <linux/usb.h>
a969888c 32#include <linux/usb/serial.h>
1da177e4 33#include <linux/ioctl.h>
1da177e4
LT
34#include "kobil_sct.h"
35
1da177e4
LT
36#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
37#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
38
39#define KOBIL_VENDOR_ID 0x0D46
40#define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011
41#define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012
42#define KOBIL_USBTWIN_PRODUCT_ID 0x0078
43#define KOBIL_KAAN_SIM_PRODUCT_ID 0x0081
44
45#define KOBIL_TIMEOUT 500
46#define KOBIL_BUF_LENGTH 300
47
48
49/* Function prototypes */
95940a04
JH
50static int kobil_port_probe(struct usb_serial_port *probe);
51static int kobil_port_remove(struct usb_serial_port *probe);
a509a7e4 52static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
335f8514 53static void kobil_close(struct usb_serial_port *port);
dee0a7cc 54static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
1da177e4 55 const unsigned char *buf, int count);
95da310e 56static int kobil_write_room(struct tty_struct *tty);
00a0d0d6 57static int kobil_ioctl(struct tty_struct *tty,
1da177e4 58 unsigned int cmd, unsigned long arg);
60b33c13 59static int kobil_tiocmget(struct tty_struct *tty);
20b9d177 60static int kobil_tiocmset(struct tty_struct *tty,
1da177e4 61 unsigned int set, unsigned int clear);
dee0a7cc 62static void kobil_read_int_callback(struct urb *urb);
feb0a36a 63static void kobil_write_int_callback(struct urb *urb);
dee0a7cc 64static void kobil_set_termios(struct tty_struct *tty,
95da310e 65 struct usb_serial_port *port, struct ktermios *old);
fe1ae7fd 66static void kobil_init_termios(struct tty_struct *tty);
1da177e4 67
7d40d7e8 68static const struct usb_device_id id_table[] = {
1da177e4
LT
69 { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
70 { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
71 { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
72 { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
73 { } /* Terminating entry */
74};
dee0a7cc 75MODULE_DEVICE_TABLE(usb, id_table);
1da177e4 76
ea65370d 77static struct usb_serial_driver kobil_device = {
18fcac35
GKH
78 .driver = {
79 .owner = THIS_MODULE,
269bda1c 80 .name = "kobil",
18fcac35 81 },
269bda1c 82 .description = "KOBIL USB smart card terminal",
1da177e4 83 .id_table = id_table,
1da177e4 84 .num_ports = 1,
35194572 85 .num_interrupt_out = 1,
95940a04
JH
86 .port_probe = kobil_port_probe,
87 .port_remove = kobil_port_remove,
1da177e4 88 .ioctl = kobil_ioctl,
94d0f7ea 89 .set_termios = kobil_set_termios,
fe1ae7fd 90 .init_termios = kobil_init_termios,
1da177e4
LT
91 .tiocmget = kobil_tiocmget,
92 .tiocmset = kobil_tiocmset,
93 .open = kobil_open,
94 .close = kobil_close,
95 .write = kobil_write,
96 .write_room = kobil_write_room,
97 .read_int_callback = kobil_read_int_callback,
feb0a36a 98 .write_int_callback = kobil_write_int_callback,
1da177e4
LT
99};
100
4d2a7aff
AS
101static struct usb_serial_driver * const serial_drivers[] = {
102 &kobil_device, NULL
103};
1da177e4
LT
104
105struct kobil_private {
dee0a7cc
AC
106 unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */
107 int filled; /* index of the last char in buf */
108 int cur_pos; /* index of the next char to send in buf */
1da177e4 109 __u16 device_type;
1da177e4
LT
110};
111
112
95940a04 113static int kobil_port_probe(struct usb_serial_port *port)
1da177e4 114{
95940a04 115 struct usb_serial *serial = port->serial;
1da177e4 116 struct kobil_private *priv;
1da177e4
LT
117
118 priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
dee0a7cc 119 if (!priv)
1da177e4 120 return -ENOMEM;
1da177e4
LT
121
122 priv->filled = 0;
123 priv->cur_pos = 0;
124 priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct);
1da177e4 125
dee0a7cc 126 switch (priv->device_type) {
1da177e4 127 case KOBIL_ADAPTER_B_PRODUCT_ID:
6c27ad83 128 dev_dbg(&serial->dev->dev, "KOBIL B1 PRO / KAAN PRO detected\n");
1da177e4
LT
129 break;
130 case KOBIL_ADAPTER_K_PRODUCT_ID:
6c27ad83 131 dev_dbg(&serial->dev->dev, "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
1da177e4
LT
132 break;
133 case KOBIL_USBTWIN_PRODUCT_ID:
6c27ad83 134 dev_dbg(&serial->dev->dev, "KOBIL USBTWIN detected\n");
1da177e4
LT
135 break;
136 case KOBIL_KAAN_SIM_PRODUCT_ID:
6c27ad83 137 dev_dbg(&serial->dev->dev, "KOBIL KAAN SIM detected\n");
1da177e4
LT
138 break;
139 }
95940a04 140 usb_set_serial_port_data(port, priv);
1da177e4 141
1da177e4
LT
142 return 0;
143}
144
145
95940a04 146static int kobil_port_remove(struct usb_serial_port *port)
1da177e4 147{
95940a04 148 struct kobil_private *priv;
1da177e4 149
95940a04
JH
150 priv = usb_get_serial_port_data(port);
151 kfree(priv);
152
153 return 0;
1da177e4
LT
154}
155
fe1ae7fd
AC
156static void kobil_init_termios(struct tty_struct *tty)
157{
158 /* Default to echo off and other sane device settings */
adc8d746 159 tty->termios.c_lflag = 0;
6a6c8b36
AC
160 tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
161 tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF;
fe1ae7fd 162 /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
adc8d746 163 tty->termios.c_oflag &= ~ONLCR;
fe1ae7fd 164}
1da177e4 165
a509a7e4 166static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
1da177e4 167{
b12f7a1c 168 struct device *dev = &port->dev;
94d0f7ea 169 int result = 0;
1da177e4
LT
170 struct kobil_private *priv;
171 unsigned char *transfer_buffer;
172 int transfer_buffer_length = 8;
1da177e4 173
1da177e4 174 priv = usb_get_serial_port_data(port);
1da177e4 175
dee0a7cc 176 /* allocate memory for transfer buffer */
80b6ca48 177 transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
dee0a7cc 178 if (!transfer_buffer)
1da177e4 179 return -ENOMEM;
dee0a7cc 180
dee0a7cc
AC
181 /* get hardware version */
182 result = usb_control_msg(port->serial->dev,
183 usb_rcvctrlpipe(port->serial->dev, 0),
184 SUSBCRequest_GetMisc,
185 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
186 SUSBCR_MSC_GetHWVersion,
187 0,
188 transfer_buffer,
189 transfer_buffer_length,
190 KOBIL_TIMEOUT
191 );
b12f7a1c 192 dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result);
8faaaead 193 dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],
b12f7a1c 194 transfer_buffer[1], transfer_buffer[2]);
dee0a7cc
AC
195
196 /* get firmware version */
197 result = usb_control_msg(port->serial->dev,
198 usb_rcvctrlpipe(port->serial->dev, 0),
199 SUSBCRequest_GetMisc,
200 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
201 SUSBCR_MSC_GetFWVersion,
202 0,
203 transfer_buffer,
204 transfer_buffer_length,
205 KOBIL_TIMEOUT
206 );
b12f7a1c
GKH
207 dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result);
208 dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0],
209 transfer_buffer[1], transfer_buffer[2]);
dee0a7cc
AC
210
211 if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
212 priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
213 /* Setting Baudrate, Parity and Stopbits */
214 result = usb_control_msg(port->serial->dev,
90419cfc 215 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
216 SUSBCRequest_SetBaudRateParityAndStopBits,
217 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
218 SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity |
219 SUSBCR_SPASB_1StopBit,
220 0,
90419cfc 221 NULL,
dee0a7cc
AC
222 0,
223 KOBIL_TIMEOUT
1da177e4 224 );
b12f7a1c 225 dev_dbg(dev, "%s - Send set_baudrate URB returns: %i\n", __func__, result);
dee0a7cc
AC
226
227 /* reset all queues */
228 result = usb_control_msg(port->serial->dev,
90419cfc 229 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
230 SUSBCRequest_Misc,
231 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
232 SUSBCR_MSC_ResetAllQueues,
233 0,
90419cfc 234 NULL,
dee0a7cc
AC
235 0,
236 KOBIL_TIMEOUT
1da177e4 237 );
b12f7a1c 238 dev_dbg(dev, "%s - Send reset_all_queues URB returns: %i\n", __func__, result);
1da177e4 239 }
dee0a7cc
AC
240 if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
241 priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
1da177e4 242 priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
dee0a7cc 243 /* start reading (Adapter B 'cause PNP string) */
811c3707 244 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
b12f7a1c 245 dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result);
1da177e4
LT
246 }
247
248 kfree(transfer_buffer);
249 return 0;
250}
251
252
335f8514 253static void kobil_close(struct usb_serial_port *port)
1da177e4 254{
335f8514 255 /* FIXME: Add rts/dtr methods */
feb0a36a 256 usb_kill_urb(port->interrupt_out_urb);
5505c226 257 usb_kill_urb(port->interrupt_in_urb);
1da177e4
LT
258}
259
260
6fcdcf04 261static void kobil_read_int_callback(struct urb *urb)
1da177e4 262{
1da177e4 263 int result;
6fcdcf04 264 struct usb_serial_port *port = urb->context;
6fcdcf04
GKH
265 unsigned char *data = urb->transfer_buffer;
266 int status = urb->status;
1da177e4 267
6fcdcf04 268 if (status) {
b12f7a1c 269 dev_dbg(&port->dev, "%s - Read int status not zero: %d\n", __func__, status);
1da177e4
LT
270 return;
271 }
6fcdcf04 272
2e124b4a 273 if (urb->actual_length) {
8e34c6c2
JH
274 usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
275 data);
05c7cd39 276 tty_insert_flip_string(&port->port, data, urb->actual_length);
2e124b4a 277 tty_flip_buffer_push(&port->port);
1da177e4 278 }
1da177e4 279
6fcdcf04 280 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
b12f7a1c 281 dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
1da177e4
LT
282}
283
284
feb0a36a 285static void kobil_write_int_callback(struct urb *urb)
1da177e4
LT
286{
287}
288
289
dee0a7cc 290static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
1da177e4
LT
291 const unsigned char *buf, int count)
292{
293 int length = 0;
294 int result = 0;
295 int todo = 0;
dee0a7cc 296 struct kobil_private *priv;
1da177e4
LT
297
298 if (count == 0) {
b12f7a1c 299 dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__);
1da177e4
LT
300 return 0;
301 }
302
303 priv = usb_get_serial_port_data(port);
304
305 if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
b12f7a1c 306 dev_dbg(&port->dev, "%s - Error: write request bigger than buffer size\n", __func__);
1da177e4
LT
307 return -ENOMEM;
308 }
309
dee0a7cc
AC
310 /* Copy data to buffer */
311 memcpy(priv->buf + priv->filled, buf, count);
59d33f2f 312 usb_serial_debug_data(&port->dev, __func__, count, priv->buf + priv->filled);
1da177e4
LT
313 priv->filled = priv->filled + count;
314
dee0a7cc
AC
315 /* only send complete block. TWIN, KAAN SIM and adapter K
316 use the same protocol. */
317 if (((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) ||
318 ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4)))) {
319 /* stop reading (except TWIN and KAAN SIM) */
320 if ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID)
321 || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID))
1da177e4
LT
322 usb_kill_urb(port->interrupt_in_urb);
323
324 todo = priv->filled - priv->cur_pos;
325
dee0a7cc
AC
326 while (todo > 0) {
327 /* max 8 byte in one urb (endpoint size) */
feb0a36a 328 length = min(todo, port->interrupt_out_size);
dee0a7cc 329 /* copy data to transfer buffer */
feb0a36a 330 memcpy(port->interrupt_out_buffer,
dee0a7cc 331 priv->buf + priv->cur_pos, length);
feb0a36a 332 port->interrupt_out_urb->transfer_buffer_length = length;
1da177e4
LT
333
334 priv->cur_pos = priv->cur_pos + length;
19125283
JH
335 result = usb_submit_urb(port->interrupt_out_urb,
336 GFP_ATOMIC);
b12f7a1c 337 dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result);
1da177e4
LT
338 todo = priv->filled - priv->cur_pos;
339
dee0a7cc 340 if (todo > 0)
1da177e4 341 msleep(24);
dee0a7cc 342 }
1da177e4 343
1da177e4
LT
344 priv->filled = 0;
345 priv->cur_pos = 0;
346
dee0a7cc
AC
347 /* start reading (except TWIN and KAAN SIM) */
348 if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
349 priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
dee0a7cc 350 result = usb_submit_urb(port->interrupt_in_urb,
19125283 351 GFP_ATOMIC);
b12f7a1c 352 dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
1da177e4
LT
353 }
354 }
355 return count;
356}
357
358
dee0a7cc 359static int kobil_write_room(struct tty_struct *tty)
1da177e4 360{
95da310e 361 /* FIXME */
1da177e4
LT
362 return 8;
363}
364
365
60b33c13 366static int kobil_tiocmget(struct tty_struct *tty)
1da177e4 367{
95da310e 368 struct usb_serial_port *port = tty->driver_data;
dee0a7cc 369 struct kobil_private *priv;
1da177e4
LT
370 int result;
371 unsigned char *transfer_buffer;
372 int transfer_buffer_length = 8;
373
374 priv = usb_get_serial_port_data(port);
dee0a7cc
AC
375 if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID
376 || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
377 /* This device doesn't support ioctl calls */
1da177e4
LT
378 return -EINVAL;
379 }
380
dee0a7cc 381 /* allocate memory for transfer buffer */
80b6ca48 382 transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
dee0a7cc 383 if (!transfer_buffer)
1da177e4 384 return -ENOMEM;
1da177e4 385
dee0a7cc
AC
386 result = usb_control_msg(port->serial->dev,
387 usb_rcvctrlpipe(port->serial->dev, 0),
388 SUSBCRequest_GetStatusLineState,
389 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
390 0,
391 0,
392 transfer_buffer,
393 transfer_buffer_length,
394 KOBIL_TIMEOUT);
395
606cd7ee
JH
396 dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n",
397 result);
398 if (result < 1) {
399 if (result >= 0)
400 result = -EIO;
401 goto out_free;
402 }
403
404 dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]);
1da177e4 405
a40d8540
AC
406 result = 0;
407 if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
408 result = TIOCM_DSR;
606cd7ee 409out_free:
1da177e4 410 kfree(transfer_buffer);
a40d8540 411 return result;
1da177e4
LT
412}
413
20b9d177 414static int kobil_tiocmset(struct tty_struct *tty,
1da177e4
LT
415 unsigned int set, unsigned int clear)
416{
95da310e 417 struct usb_serial_port *port = tty->driver_data;
b12f7a1c 418 struct device *dev = &port->dev;
dee0a7cc 419 struct kobil_private *priv;
1da177e4
LT
420 int result;
421 int dtr = 0;
422 int rts = 0;
1da177e4 423
a40d8540 424 /* FIXME: locking ? */
1da177e4 425 priv = usb_get_serial_port_data(port);
dee0a7cc
AC
426 if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID
427 || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
428 /* This device doesn't support ioctl calls */
1da177e4
LT
429 return -EINVAL;
430 }
431
1da177e4
LT
432 if (set & TIOCM_RTS)
433 rts = 1;
434 if (set & TIOCM_DTR)
435 dtr = 1;
436 if (clear & TIOCM_RTS)
437 rts = 0;
438 if (clear & TIOCM_DTR)
439 dtr = 0;
440
441 if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
442 if (dtr != 0)
b12f7a1c 443 dev_dbg(dev, "%s - Setting DTR\n", __func__);
1da177e4 444 else
b12f7a1c 445 dev_dbg(dev, "%s - Clearing DTR\n", __func__);
dee0a7cc 446 result = usb_control_msg(port->serial->dev,
90419cfc 447 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
448 SUSBCRequest_SetStatusLinesOrQueues,
449 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
450 ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
451 0,
90419cfc 452 NULL,
dee0a7cc
AC
453 0,
454 KOBIL_TIMEOUT);
1da177e4
LT
455 } else {
456 if (rts != 0)
b12f7a1c 457 dev_dbg(dev, "%s - Setting RTS\n", __func__);
1da177e4 458 else
b12f7a1c 459 dev_dbg(dev, "%s - Clearing RTS\n", __func__);
dee0a7cc 460 result = usb_control_msg(port->serial->dev,
90419cfc 461 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
462 SUSBCRequest_SetStatusLinesOrQueues,
463 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
464 ((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
465 0,
90419cfc 466 NULL,
dee0a7cc
AC
467 0,
468 KOBIL_TIMEOUT);
1da177e4 469 }
b12f7a1c 470 dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result);
1da177e4
LT
471 return (result < 0) ? result : 0;
472}
473
95da310e
AC
474static void kobil_set_termios(struct tty_struct *tty,
475 struct usb_serial_port *port, struct ktermios *old)
1da177e4 476{
dee0a7cc 477 struct kobil_private *priv;
1da177e4
LT
478 int result;
479 unsigned short urb_val = 0;
adc8d746 480 int c_cflag = tty->termios.c_cflag;
94d0f7ea 481 speed_t speed;
1da177e4
LT
482
483 priv = usb_get_serial_port_data(port);
dee0a7cc 484 if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
b31f658b 485 priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
dee0a7cc 486 /* This device doesn't support ioctl calls */
6a6c8b36 487 tty_termios_copy_hw(&tty->termios, old);
94d0f7ea 488 return;
b31f658b 489 }
1da177e4 490
dee0a7cc
AC
491 speed = tty_get_baud_rate(tty);
492 switch (speed) {
493 case 1200:
494 urb_val = SUSBCR_SBR_1200;
495 break;
496 default:
497 speed = 9600;
fe1f68a0 498 /* fall through */
dee0a7cc
AC
499 case 9600:
500 urb_val = SUSBCR_SBR_9600;
501 break;
94d0f7ea 502 }
dee0a7cc
AC
503 urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits :
504 SUSBCR_SPASB_1StopBit;
94d0f7ea 505 if (c_cflag & PARENB) {
96679f6b 506 if (c_cflag & PARODD)
94d0f7ea 507 urb_val |= SUSBCR_SPASB_OddParity;
96679f6b 508 else
94d0f7ea 509 urb_val |= SUSBCR_SPASB_EvenParity;
96679f6b 510 } else
94d0f7ea 511 urb_val |= SUSBCR_SPASB_NoParity;
adc8d746 512 tty->termios.c_cflag &= ~CMSPAR;
95da310e 513 tty_encode_baud_rate(tty, speed, speed);
1da177e4 514
dee0a7cc 515 result = usb_control_msg(port->serial->dev,
90419cfc 516 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
517 SUSBCRequest_SetBaudRateParityAndStopBits,
518 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
519 urb_val,
520 0,
96679f6b 521 NULL,
dee0a7cc
AC
522 0,
523 KOBIL_TIMEOUT
94d0f7ea 524 );
94d0f7ea 525}
1da177e4 526
00a0d0d6 527static int kobil_ioctl(struct tty_struct *tty,
dee0a7cc 528 unsigned int cmd, unsigned long arg)
94d0f7ea 529{
95da310e 530 struct usb_serial_port *port = tty->driver_data;
dee0a7cc 531 struct kobil_private *priv = usb_get_serial_port_data(port);
94d0f7ea
AC
532 int result;
533
dee0a7cc
AC
534 if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
535 priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
536 /* This device doesn't support ioctl calls */
b31f658b 537 return -ENOIOCTLCMD;
1da177e4 538
94d0f7ea 539 switch (cmd) {
95da310e 540 case TCFLSH:
dee0a7cc 541 result = usb_control_msg(port->serial->dev,
90419cfc 542 usb_sndctrlpipe(port->serial->dev, 0),
dee0a7cc
AC
543 SUSBCRequest_Misc,
544 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
545 SUSBCR_MSC_ResetAllQueues,
546 0,
90419cfc 547 NULL,
dee0a7cc
AC
548 0,
549 KOBIL_TIMEOUT
1da177e4 550 );
dee0a7cc 551
b12f7a1c 552 dev_dbg(&port->dev,
d9a38a87
JH
553 "%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
554 __func__, result);
95da310e 555 return (result < 0) ? -EIO: 0;
94d0f7ea
AC
556 default:
557 return -ENOIOCTLCMD;
1da177e4 558 }
1da177e4
LT
559}
560
68e24113 561module_usb_serial_driver(serial_drivers, id_table);
1da177e4 562
dee0a7cc
AC
563MODULE_AUTHOR(DRIVER_AUTHOR);
564MODULE_DESCRIPTION(DRIVER_DESC);
565MODULE_LICENSE("GPL");