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