xref: /openbmc/linux/drivers/usb/serial/kobil_sct.c (revision 87c2ce3b)
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 
54 static 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 */
72 static int  kobil_startup (struct usb_serial *serial);
73 static void kobil_shutdown (struct usb_serial *serial);
74 static int  kobil_open (struct usb_serial_port *port, struct file *filp);
75 static void kobil_close (struct usb_serial_port *port, struct file *filp);
76 static int  kobil_write (struct usb_serial_port *port,
77 			 const unsigned char *buf, int count);
78 static int  kobil_write_room(struct usb_serial_port *port);
79 static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
80 			unsigned int cmd, unsigned long arg);
81 static int  kobil_tiocmget(struct usb_serial_port *port, struct file *file);
82 static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
83 			   unsigned int set, unsigned int clear);
84 static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs );
85 static void kobil_write_callback( struct urb *purb, struct pt_regs *regs );
86 
87 
88 static 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 
97 MODULE_DEVICE_TABLE (usb, id_table);
98 
99 static 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 
108 static 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 
132 struct 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 
144 static 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 
204 static 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 
219 static 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 
352 static 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 
366 static 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 
419 static void kobil_write_callback( struct urb *purb, struct pt_regs *regs )
420 {
421 }
422 
423 
424 static 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 
507 static int kobil_write_room (struct usb_serial_port *port)
508 {
509 	//dbg("%s - port %d", __FUNCTION__, port->number);
510 	return 8;
511 }
512 
513 
514 static 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 
557 static 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 
624 static 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 
742 static 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;
756 failed_usb_register:
757 	usb_serial_deregister(&kobil_device);
758 failed_usb_serial_register:
759 	return retval;
760 }
761 
762 
763 static void __exit kobil_exit (void)
764 {
765 	usb_deregister (&kobil_driver);
766 	usb_serial_deregister (&kobil_device);
767 }
768 
769 module_init(kobil_init);
770 module_exit(kobil_exit);
771 
772 MODULE_AUTHOR( DRIVER_AUTHOR );
773 MODULE_DESCRIPTION( DRIVER_DESC );
774 MODULE_LICENSE( "GPL" );
775 
776 module_param(debug, bool, S_IRUGO | S_IWUSR);
777 MODULE_PARM_DESC(debug, "Debug enabled or not");
778