patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / usb / serial / kobil_sct.c
1 /*
2  *  KOBIL USB Smart Card Terminal Driver
3  *
4  *  Copyright (C) 2002  KOBIL Systems GmbH 
5  *  Author: Thomas Wahrenbruch
6  *
7  *  Contact: linuxusb@kobil.de
8  *
9  *  This program is largely derived from work by the linux-usb group
10  *  and associated source files.  Please see the usb/serial files for
11  *  individual credits and copyrights.
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
19  *  patience.
20  *
21  * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
22  * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
23  * 
24  * (21/05/2004) tw
25  *      Fix bug with P'n'P readers
26  *
27  * (28/05/2003) tw
28  *      Add support for KAAN SIM
29  *
30  * (12/09/2002) tw
31  *      Adapted to 2.5.
32  *
33  * (11/08/2002) tw
34  *      Initial version.
35  */
36
37
38 #include <linux/config.h>
39 #include <linux/kernel.h>
40 #include <linux/errno.h>
41 #include <linux/init.h>
42 #include <linux/slab.h>
43 #include <linux/tty.h>
44 #include <linux/tty_driver.h>
45 #include <linux/tty_flip.h>
46 #include <linux/module.h>
47 #include <linux/spinlock.h>
48 #include <asm/uaccess.h>
49 #include <linux/usb.h>
50 #include <linux/ioctl.h>
51
52
53 #include "kobil_sct.h"
54 //#include "../core/usb-debug.c"
55
56 #ifdef CONFIG_USB_SERIAL_DEBUG
57         static int debug = 1;
58 #else
59         static int debug;
60 #endif
61
62 #include "usb-serial.h"
63
64 /* Version Information */
65 #define DRIVER_VERSION "21/05/2004"
66 #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
67 #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
68
69 #define KOBIL_VENDOR_ID                 0x0D46
70 #define KOBIL_ADAPTER_B_PRODUCT_ID      0x2011
71 #define KOBIL_ADAPTER_K_PRODUCT_ID      0x2012
72 #define KOBIL_USBTWIN_PRODUCT_ID        0x0078
73 #define KOBIL_KAAN_SIM_PRODUCT_ID       0x0081
74
75 #define KOBIL_TIMEOUT           500
76 #define KOBIL_BUF_LENGTH        300
77
78
79 /* Function prototypes */
80 static int  kobil_startup (struct usb_serial *serial);
81 static void kobil_shutdown (struct usb_serial *serial);
82 static int  kobil_open (struct usb_serial_port *port, struct file *filp);
83 static void kobil_close (struct usb_serial_port *port, struct file *filp);
84 static int  kobil_write (struct usb_serial_port *port, int from_user, 
85                          const unsigned char *buf, int count);
86 static int  kobil_write_room(struct usb_serial_port *port);
87 static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
88                         unsigned int cmd, unsigned long arg);
89 static int  kobil_tiocmget(struct usb_serial_port *port, struct file *file);
90 static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
91                            unsigned int set, unsigned int clear);
92 static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs );
93 static void kobil_write_callback( struct urb *purb, struct pt_regs *regs );
94
95
96 static struct usb_device_id id_table [] = {
97         { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
98         { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
99         { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
100         { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
101         { }                     /* Terminating entry */
102 };
103
104
105 MODULE_DEVICE_TABLE (usb, id_table);
106
107 static struct usb_driver kobil_driver = {
108         .owner =        THIS_MODULE,
109         .name =         "kobil",
110         .probe =        usb_serial_probe,
111         .disconnect =   usb_serial_disconnect,
112         .id_table =     id_table,
113 };
114
115
116 static struct usb_serial_device_type kobil_device = {
117         .owner =                THIS_MODULE,
118         .name =                 "KOBIL USB smart card terminal",
119         .id_table =             id_table,
120         .num_interrupt_in =     NUM_DONT_CARE,
121         .num_bulk_in =          0,
122         .num_bulk_out =         0,
123         .num_ports =            1,
124         .attach =               kobil_startup,
125         .shutdown =             kobil_shutdown,
126         .ioctl =                kobil_ioctl,
127         .tiocmget =             kobil_tiocmget,
128         .tiocmset =             kobil_tiocmset,
129         .open =                 kobil_open,
130         .close =                kobil_close,
131         .write =                kobil_write,
132         .write_room =           kobil_write_room,
133         .read_int_callback =    kobil_read_int_callback,
134 };
135
136
137 struct kobil_private {
138         int write_int_endpoint_address;
139         int read_int_endpoint_address;
140         unsigned char buf[KOBIL_BUF_LENGTH]; // buffer for the APDU to send
141         int filled;  // index of the last char in buf
142         int cur_pos; // index of the next char to send in buf
143         __u16 device_type;
144         int line_state;
145         struct termios internal_termios;
146 };
147
148
149 static int kobil_startup (struct usb_serial *serial)
150 {
151         int i;
152         struct kobil_private *priv;
153         struct usb_device *pdev;
154         struct usb_host_config *actconfig;
155         struct usb_interface *interface;
156         struct usb_host_interface *altsetting;
157         struct usb_host_endpoint *endpoint;
158
159         priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
160         if (!priv){
161                 return -ENOMEM;
162         }
163
164         priv->filled = 0;
165         priv->cur_pos = 0;
166         priv->device_type = serial->product;
167         priv->line_state = 0;
168
169         switch (priv->device_type){
170         case KOBIL_ADAPTER_B_PRODUCT_ID:
171                 printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");
172                 break;
173         case KOBIL_ADAPTER_K_PRODUCT_ID:
174                 printk(KERN_DEBUG "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
175                 break;
176         case KOBIL_USBTWIN_PRODUCT_ID:
177                 printk(KERN_DEBUG "KOBIL USBTWIN detected\n");
178                 break;
179         case KOBIL_KAAN_SIM_PRODUCT_ID:
180                 printk(KERN_DEBUG "KOBIL KAAN SIM detected\n");
181                 break;
182         }
183         usb_set_serial_port_data(serial->port[0], priv);
184
185         // search for the necessary endpoints
186         pdev = serial->dev;
187         actconfig = pdev->actconfig;
188         interface = actconfig->interface[0];
189         altsetting = interface->cur_altsetting;
190         endpoint = altsetting->endpoint;
191   
192         for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
193                 endpoint = &altsetting->endpoint[i];
194                 if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && 
195                     ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
196                         dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);
197                         priv->write_int_endpoint_address = endpoint->desc.bEndpointAddress;
198                 }
199                 if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && 
200                     ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
201                         dbg("%s Found interrupt in  endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);
202                         priv->read_int_endpoint_address = endpoint->desc.bEndpointAddress;
203                 }
204         }
205         return 0;
206 }
207
208
209 static void kobil_shutdown (struct usb_serial *serial)
210 {
211         int i;
212         dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
213
214         for (i=0; i < serial->num_ports; ++i) {
215                 while (serial->port[i]->open_count > 0) {
216                         kobil_close (serial->port[i], NULL);
217                 }
218                 kfree(usb_get_serial_port_data(serial->port[i]));
219                 usb_set_serial_port_data(serial->port[i], NULL);
220         }
221 }
222
223
224 static int kobil_open (struct usb_serial_port *port, struct file *filp)
225 {
226         int i, result = 0;
227         struct kobil_private *priv;
228         unsigned char *transfer_buffer;
229         int transfer_buffer_length = 8;
230         int write_urb_transfer_buffer_length = 8;
231
232         dbg("%s - port %d", __FUNCTION__, port->number);
233         priv = usb_get_serial_port_data(port);
234         priv->line_state = 0;
235
236         // someone sets the dev to 0 if the close method has been called
237         port->interrupt_in_urb->dev = port->serial->dev;
238
239
240         /* force low_latency on so that our tty_push actually forces
241          * the data through, otherwise it is scheduled, and with high
242          * data rates (like with OHCI) data can get lost.
243          */
244         port->tty->low_latency = 1;
245
246         // without this, every push_tty_char is echoed :-(  
247         port->tty->termios->c_lflag = 0;
248         port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
249         port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
250         port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
251         
252         // set up internal termios structure 
253         priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
254         priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
255         priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
256         priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
257
258         for (i=0; i<NCCS; i++) {
259                 priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
260         }
261         
262         // allocate memory for transfer buffer
263         transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
264         if (! transfer_buffer) {
265                 return -ENOMEM;
266         } else {
267                 memset(transfer_buffer, 0, transfer_buffer_length);
268         }
269         
270         // allocate write_urb
271         if (!port->write_urb) { 
272                 dbg("%s - port %d  Allocating port->write_urb", __FUNCTION__, port->number);
273                 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);  
274                 if (!port->write_urb) {
275                         dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
276                         kfree(transfer_buffer);
277                         return -ENOMEM;
278                 }
279         }
280
281         // allocate memory for write_urb transfer buffer
282         port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
283         if (! port->write_urb->transfer_buffer) {
284                 kfree(transfer_buffer);
285                 usb_free_urb(port->write_urb);
286                 port->write_urb = NULL;
287                 return -ENOMEM;
288         } 
289
290         // get hardware version
291         result = usb_control_msg( port->serial->dev, 
292                                   usb_rcvctrlpipe(port->serial->dev, 0 ), 
293                                   SUSBCRequest_GetMisc,
294                                   USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
295                                   SUSBCR_MSC_GetHWVersion,
296                                   0,
297                                   transfer_buffer,
298                                   transfer_buffer_length,
299                                   KOBIL_TIMEOUT
300                 );
301         dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);
302         dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
303         
304         // get firmware version
305         result = usb_control_msg( port->serial->dev, 
306                                   usb_rcvctrlpipe(port->serial->dev, 0 ), 
307                                   SUSBCRequest_GetMisc,
308                                   USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
309                                   SUSBCR_MSC_GetFWVersion,
310                                   0,
311                                   transfer_buffer,
312                                   transfer_buffer_length,
313                                   KOBIL_TIMEOUT
314                 );
315         dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);
316         dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
317
318         if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
319                 // Setting Baudrate, Parity and Stopbits
320                 result = usb_control_msg( port->serial->dev, 
321                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
322                                           SUSBCRequest_SetBaudRateParityAndStopBits,
323                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
324                                           SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit,
325                                           0,
326                                           transfer_buffer,
327                                           0,
328                                           KOBIL_TIMEOUT
329                         );
330                 dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
331                 
332                 // reset all queues
333                 result = usb_control_msg( port->serial->dev, 
334                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
335                                           SUSBCRequest_Misc,
336                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
337                                           SUSBCR_MSC_ResetAllQueues,
338                                           0,
339                                           transfer_buffer,
340                                           0,
341                                           KOBIL_TIMEOUT
342                         );
343                 dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
344         }
345         if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
346             priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
347                 // start reading (Adapter B 'cause PNP string)
348                 result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC  ); 
349                 dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
350         }
351
352         kfree(transfer_buffer);
353         return 0;
354 }
355
356
357 static void kobil_close (struct usb_serial_port *port, struct file *filp)
358 {
359         dbg("%s - port %d", __FUNCTION__, port->number);
360
361         if (port->write_urb){
362                 usb_unlink_urb( port->write_urb );
363                 usb_free_urb( port->write_urb );
364                 port->write_urb = 0;
365         }
366         if (port->interrupt_in_urb){
367                 usb_unlink_urb (port->interrupt_in_urb);
368         }
369 }
370
371
372 static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
373 {
374         int i;
375         int result;
376         struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
377         struct tty_struct *tty;
378         unsigned char *data = purb->transfer_buffer;
379 //      char *dbg_data;
380
381         dbg("%s - port %d", __FUNCTION__, port->number);
382
383         if (purb->status) {
384                 dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);
385                 return;
386         }
387         
388         tty = port->tty; 
389         if (purb->actual_length) {
390                 
391                 // BEGIN DEBUG
392                 /*
393                   dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
394                   if (! dbg_data) {
395                   return;
396                   }
397                   memset(dbg_data, 0, (3 *  purb->actual_length + 10));
398                   for (i = 0; i < purb->actual_length; i++) { 
399                   sprintf(dbg_data +3*i, "%02X ", data[i]); 
400                   }
401                   dbg(" <-- %s", dbg_data );
402                   kfree(dbg_data);
403                 */
404                 // END DEBUG
405
406                 for (i = 0; i < purb->actual_length; ++i) {
407                         // if we insert more than TTY_FLIPBUF_SIZE characters, we drop them.
408                         if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
409                                 tty_flip_buffer_push(tty);
410                         }
411                         // this doesn't actually push the data through unless tty->low_latency is set
412                         tty_insert_flip_char(tty, data[i], 0);
413                 }
414                 tty_flip_buffer_push(tty);
415         }
416
417         // someone sets the dev to 0 if the close method has been called
418         port->interrupt_in_urb->dev = port->serial->dev;
419
420         result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); 
421         dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
422 }
423
424
425 static void kobil_write_callback( struct urb *purb, struct pt_regs *regs )
426 {
427 }
428
429
430 static int kobil_write (struct usb_serial_port *port, int from_user, 
431                         const unsigned char *buf, int count)
432 {
433         int length = 0;
434         int result = 0;
435         int todo = 0;
436         struct kobil_private * priv;
437
438         if (count == 0) {
439                 dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
440                 return 0;
441         }
442
443         priv = usb_get_serial_port_data(port);
444
445         if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
446                 dbg("%s - port %d Error: write request bigger than buffer size", __FUNCTION__, port->number);
447                 return -ENOMEM;
448         }
449
450         // Copy data to buffer
451         if (from_user) {
452                 if (copy_from_user(priv->buf + priv->filled, buf, count)) {
453                         return -EFAULT;
454                 }
455         } else {
456                 memcpy (priv->buf + priv->filled, buf, count);
457         }
458
459         usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->buf + priv->filled);
460
461         priv->filled = priv->filled + count;
462
463
464         // only send complete block. TWIN, KAAN SIM and adapter K use the same protocol.
465         if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
466              ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
467                 
468                 // stop reading (except TWIN and KAAN SIM)
469                 if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
470                         usb_unlink_urb( port->interrupt_in_urb );
471                 }
472
473                 todo = priv->filled - priv->cur_pos;
474
475                 while(todo > 0) {
476                         // max 8 byte in one urb (endpoint size)
477                         length = (todo < 8) ? todo : 8;
478                         // copy data to transfer buffer
479                         memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
480                         usb_fill_int_urb( port->write_urb,
481                                           port->serial->dev,
482                                           usb_sndintpipe(port->serial->dev, priv->write_int_endpoint_address),
483                                           port->write_urb->transfer_buffer,
484                                           length,
485                                           kobil_write_callback,
486                                           port,
487                                           8
488                                 );
489
490                         priv->cur_pos = priv->cur_pos + length;
491                         result = usb_submit_urb( port->write_urb, GFP_NOIO );
492                         dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
493                         todo = priv->filled - priv->cur_pos;
494
495                         if (todo > 0) {
496                                 msleep(24);
497                         }
498
499                 } // end while
500                 
501                 priv->filled = 0;
502                 priv->cur_pos = 0;
503
504                 // someone sets the dev to 0 if the close method has been called
505                 port->interrupt_in_urb->dev = port->serial->dev;
506                 
507                 // start reading (except TWIN and KAAN SIM)
508                 if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
509                         // someone sets the dev to 0 if the close method has been called
510                         port->interrupt_in_urb->dev = port->serial->dev;
511                         
512                         result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO ); 
513                         dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
514                 }
515         }
516         return count;
517 }
518
519
520 static int kobil_write_room (struct usb_serial_port *port)
521 {
522         //dbg("%s - port %d", __FUNCTION__, port->number);
523         return 8;
524 }
525
526
527 static int kobil_tiocmget(struct usb_serial_port *port, struct file *file)
528 {
529         struct kobil_private * priv;
530         int result;
531         unsigned char *transfer_buffer;
532         int transfer_buffer_length = 8;
533
534         priv = usb_get_serial_port_data(port);
535         if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
536                 // This device doesn't support ioctl calls
537                 return -EINVAL;
538         }
539
540         // allocate memory for transfer buffer
541         transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
542         if (!transfer_buffer) {
543                 return -ENOMEM;
544         }
545         memset(transfer_buffer, 0, transfer_buffer_length);
546
547         result = usb_control_msg( port->serial->dev, 
548                                   usb_rcvctrlpipe(port->serial->dev, 0 ), 
549                                   SUSBCRequest_GetStatusLineState,
550                                   USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
551                                   0,
552                                   0,
553                                   transfer_buffer,
554                                   transfer_buffer_length,
555                                   KOBIL_TIMEOUT);
556
557         dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x", 
558             __FUNCTION__, port->number, result, transfer_buffer[0]);
559
560         if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) {
561                 priv->line_state |= TIOCM_DSR;
562         } else {
563                 priv->line_state &= ~TIOCM_DSR; 
564         }
565
566         kfree(transfer_buffer);
567         return priv->line_state;
568 }
569
570 static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
571                            unsigned int set, unsigned int clear)
572 {
573         struct kobil_private * priv;
574         int result;
575         int dtr = 0;
576         int rts = 0;
577         unsigned char *transfer_buffer;
578         int transfer_buffer_length = 8;
579
580         priv = usb_get_serial_port_data(port);
581         if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
582                 // This device doesn't support ioctl calls
583                 return -EINVAL;
584         }
585
586         // allocate memory for transfer buffer
587         transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
588         if (! transfer_buffer) {
589                 return -ENOMEM;
590         }
591         memset(transfer_buffer, 0, transfer_buffer_length);
592
593         if (set & TIOCM_RTS)
594                 rts = 1;
595         if (set & TIOCM_DTR)
596                 dtr = 1;
597         if (clear & TIOCM_RTS)
598                 rts = 0;
599         if (clear & TIOCM_DTR)
600                 dtr = 0;
601
602         if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
603                 if (dtr != 0)
604                         dbg("%s - port %d Setting DTR", __FUNCTION__, port->number);
605                 else
606                         dbg("%s - port %d Clearing DTR", __FUNCTION__, port->number);
607                 result = usb_control_msg( port->serial->dev, 
608                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
609                                           SUSBCRequest_SetStatusLinesOrQueues,
610                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
611                                           ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
612                                           0,
613                                           transfer_buffer,
614                                           0,
615                                           KOBIL_TIMEOUT);
616         } else {
617                 if (rts != 0)
618                         dbg("%s - port %d Setting RTS", __FUNCTION__, port->number);
619                 else
620                         dbg("%s - port %d Clearing RTS", __FUNCTION__, port->number);
621                 result = usb_control_msg( port->serial->dev, 
622                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
623                                           SUSBCRequest_SetStatusLinesOrQueues,
624                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
625                                           ((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
626                                           0,
627                                           transfer_buffer,
628                                           0,
629                                           KOBIL_TIMEOUT);
630         }
631         dbg("%s - port %d Send set_status_line URB returns: %i", __FUNCTION__, port->number, result);
632         kfree(transfer_buffer);
633         return (result < 0) ? result : 0;
634 }
635
636
637 static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
638                         unsigned int cmd, unsigned long arg)
639 {
640         struct kobil_private * priv;
641         int result;
642         unsigned short urb_val = 0;
643         unsigned char *transfer_buffer;
644         int transfer_buffer_length = 8;
645         char *settings;
646
647         priv = usb_get_serial_port_data(port);
648         if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
649                 // This device doesn't support ioctl calls
650                 return 0;
651         }
652
653         switch (cmd) {
654         case TCGETS:   // 0x5401
655                 result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios));
656                 if (result) {
657                         dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
658                         return(result);
659                 }
660                 if (kernel_termios_to_user_termios((struct termios *)arg,
661                                                    &priv->internal_termios))
662                         return -EFAULT;
663                 return 0;
664
665         case TCSETS:   // 0x5402
666                 if (!(port->tty->termios)) {
667                         dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
668                         return -ENOTTY;
669                 }
670                 result = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios));
671                 if (result) {
672                         dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
673                         return result;
674                 }
675                 if (user_termios_to_kernel_termios(&priv->internal_termios,
676                                                    (struct termios *)arg))
677                         return -EFAULT;
678                 
679                 settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
680                 if (! settings) {
681                         return -ENOBUFS;
682                 }
683                 memset(settings, 0, 50);
684
685                 switch (priv->internal_termios.c_cflag & CBAUD) {
686                 case B1200:
687                         urb_val = SUSBCR_SBR_1200;
688                         strcat(settings, "1200 ");
689                         break;
690                 case B9600:
691                 default:
692                         urb_val = SUSBCR_SBR_9600;
693                         strcat(settings, "9600 ");
694                         break;
695                 }
696
697                 urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
698                 strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
699
700                 if (priv->internal_termios.c_cflag & PARENB) {
701                         if  (priv->internal_termios.c_cflag & PARODD) {
702                                 urb_val |= SUSBCR_SPASB_OddParity;
703                                 strcat(settings, "Odd Parity");
704                         } else {
705                                 urb_val |= SUSBCR_SPASB_EvenParity;
706                                 strcat(settings, "Even Parity");
707                         }
708                 } else {
709                         urb_val |= SUSBCR_SPASB_NoParity;
710                         strcat(settings, "No Parity");
711                 }
712                 dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
713
714                 result = usb_control_msg( port->serial->dev, 
715                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
716                                           SUSBCRequest_SetBaudRateParityAndStopBits,
717                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
718                                           urb_val,
719                                           0,
720                                           settings,
721                                           0,
722                                           KOBIL_TIMEOUT
723                         );
724
725                 dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
726                 kfree(settings);
727                 return 0;
728
729         case TCFLSH:   // 0x540B
730                 transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
731                 if (! transfer_buffer) {
732                         return -ENOBUFS;
733                 }
734
735                 result = usb_control_msg( port->serial->dev, 
736                                           usb_rcvctrlpipe(port->serial->dev, 0 ), 
737                                           SUSBCRequest_Misc,
738                                           USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
739                                           SUSBCR_MSC_ResetAllQueues,
740                                           0,
741                                           NULL,//transfer_buffer,
742                                           0,
743                                           KOBIL_TIMEOUT
744                         );
745                 
746                 dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
747
748                 kfree(transfer_buffer);
749                 return ((result < 0) ? -EFAULT : 0);
750
751         }
752         return -ENOIOCTLCMD;
753 }
754
755
756 static int __init kobil_init (void)
757 {
758         int retval;
759         retval = usb_serial_register(&kobil_device);
760         if (retval)
761                 goto failed_usb_serial_register;
762         retval = usb_register(&kobil_driver);
763         if (retval) 
764                 goto failed_usb_register;
765
766         info(DRIVER_VERSION " " DRIVER_AUTHOR);
767         info(DRIVER_DESC);
768
769         return 0;
770 failed_usb_register:
771         usb_serial_deregister(&kobil_device);
772 failed_usb_serial_register:
773         return retval;
774 }
775
776
777 static void __exit kobil_exit (void)
778 {
779         usb_deregister (&kobil_driver);
780         usb_serial_deregister (&kobil_device);
781 }
782
783 module_init(kobil_init);
784 module_exit(kobil_exit);
785
786 MODULE_AUTHOR( DRIVER_AUTHOR );
787 MODULE_DESCRIPTION( DRIVER_DESC );
788 MODULE_LICENSE( "GPL" );
789
790 MODULE_PARM(debug, "i");
791 MODULE_PARM_DESC(debug, "Debug enabled or not");