⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kobil_sct.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  KOBIL USB Smart Card Terminal Driver * *  Copyright (C) 2002  KOBIL Systems GmbH  *  Author: Thomas Wahrenbruch * *  Contact: linuxusb@kobil.de * *  This program is largely derived from work by the linux-usb group *  and associated source files.  Please see the usb/serial files for *  individual credits and copyrights. * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and *  patience. * * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus * (Adapter K), B1 Professional and KAAN Professional (Adapter B) *  * (21/05/2004) tw *      Fix bug with P'n'P readers * * (28/05/2003) tw *      Add support for KAAN SIM * * (12/09/2002) tw *      Adapted to 2.5. * * (11/08/2002) tw *      Initial version. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <linux/usb.h>#include <linux/ioctl.h>#include "usb-serial.h"#include "kobil_sct.h"static int debug;/* Version Information */#define DRIVER_VERSION "21/05/2004"#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"#define KOBIL_VENDOR_ID			0x0D46#define KOBIL_ADAPTER_B_PRODUCT_ID	0x2011#define KOBIL_ADAPTER_K_PRODUCT_ID	0x2012#define KOBIL_USBTWIN_PRODUCT_ID	0x0078#define KOBIL_KAAN_SIM_PRODUCT_ID       0x0081#define KOBIL_TIMEOUT		500#define KOBIL_BUF_LENGTH	300/* Function prototypes */static int  kobil_startup (struct usb_serial *serial);static void kobil_shutdown (struct usb_serial *serial);static int  kobil_open (struct usb_serial_port *port, struct file *filp);static void kobil_close (struct usb_serial_port *port, struct file *filp);static int  kobil_write (struct usb_serial_port *port, 			 const unsigned char *buf, int count);static int  kobil_write_room(struct usb_serial_port *port);static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,			unsigned int cmd, unsigned long arg);static int  kobil_tiocmget(struct usb_serial_port *port, struct file *file);static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,			   unsigned int set, unsigned int clear);static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs );static void kobil_write_callback( struct urb *purb, struct pt_regs *regs );static struct usb_device_id id_table [] = {	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },	{ }			/* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table);static struct usb_driver kobil_driver = {	.owner =	THIS_MODULE,	.name =		"kobil",	.probe =	usb_serial_probe,	.disconnect =	usb_serial_disconnect,	.id_table =	id_table,};static struct usb_serial_driver kobil_device = {	.driver = {		.owner =	THIS_MODULE,		.name =		"kobil",	},	.description =		"KOBIL USB smart card terminal",	.id_table =		id_table,	.num_interrupt_in =	NUM_DONT_CARE,	.num_bulk_in =		0,	.num_bulk_out =		0,	.num_ports =		1,	.attach =		kobil_startup,	.shutdown =		kobil_shutdown,	.ioctl =		kobil_ioctl,	.tiocmget =		kobil_tiocmget,	.tiocmset =		kobil_tiocmset,	.open =			kobil_open,	.close =		kobil_close,	.write =		kobil_write,	.write_room =		kobil_write_room,	.read_int_callback =	kobil_read_int_callback,};struct kobil_private {	int write_int_endpoint_address;	int read_int_endpoint_address;	unsigned char buf[KOBIL_BUF_LENGTH]; // buffer for the APDU to send	int filled;  // index of the last char in buf	int cur_pos; // index of the next char to send in buf	__u16 device_type;	int line_state;	struct termios internal_termios;};static int kobil_startup (struct usb_serial *serial){	int i;	struct kobil_private *priv;	struct usb_device *pdev;	struct usb_host_config *actconfig;	struct usb_interface *interface;	struct usb_host_interface *altsetting;	struct usb_host_endpoint *endpoint;	priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);	if (!priv){		return -ENOMEM;	}	priv->filled = 0;	priv->cur_pos = 0;	priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct);	priv->line_state = 0;	switch (priv->device_type){	case KOBIL_ADAPTER_B_PRODUCT_ID:		printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");		break;	case KOBIL_ADAPTER_K_PRODUCT_ID:		printk(KERN_DEBUG "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");		break;	case KOBIL_USBTWIN_PRODUCT_ID:		printk(KERN_DEBUG "KOBIL USBTWIN detected\n");		break;	case KOBIL_KAAN_SIM_PRODUCT_ID:		printk(KERN_DEBUG "KOBIL KAAN SIM detected\n");		break;	}	usb_set_serial_port_data(serial->port[0], priv);	// search for the necessary endpoints	pdev = serial->dev; 	actconfig = pdev->actconfig; 	interface = actconfig->interface[0];	altsetting = interface->cur_altsetting; 	endpoint = altsetting->endpoint;   	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {		endpoint = &altsetting->endpoint[i];		if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&  		    ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {		 	dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);		 	priv->write_int_endpoint_address = endpoint->desc.bEndpointAddress; 		} 		if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&  		    ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {		 	dbg("%s Found interrupt in  endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);		 	priv->read_int_endpoint_address = endpoint->desc.bEndpointAddress;	 	}	}	return 0;}static void kobil_shutdown (struct usb_serial *serial){	int i;	dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);	for (i=0; i < serial->num_ports; ++i) {		while (serial->port[i]->open_count > 0) {			kobil_close (serial->port[i], NULL);		}		kfree(usb_get_serial_port_data(serial->port[i]));		usb_set_serial_port_data(serial->port[i], NULL);	}}static int kobil_open (struct usb_serial_port *port, struct file *filp){	int i, result = 0;	struct kobil_private *priv;	unsigned char *transfer_buffer;	int transfer_buffer_length = 8;	int write_urb_transfer_buffer_length = 8;	dbg("%s - port %d", __FUNCTION__, port->number);	priv = usb_get_serial_port_data(port);	priv->line_state = 0;	// someone sets the dev to 0 if the close method has been called	port->interrupt_in_urb->dev = port->serial->dev;	/* force low_latency on so that our tty_push actually forces	 * the data through, otherwise it is scheduled, and with high	 * data rates (like with OHCI) data can get lost.	 */	port->tty->low_latency = 1;	// without this, every push_tty_char is echoed :-(  	port->tty->termios->c_lflag = 0;	port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)		// set up internal termios structure 	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;	for (i=0; i<NCCS; i++) {		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];	}		// allocate memory for transfer buffer	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  	if (! transfer_buffer) {		return -ENOMEM;	} else {		memset(transfer_buffer, 0, transfer_buffer_length);	}		// allocate write_urb	if (!port->write_urb) { 		dbg("%s - port %d  Allocating port->write_urb", __FUNCTION__, port->number);		port->write_urb = usb_alloc_urb(0, GFP_KERNEL);  		if (!port->write_urb) {			dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);			kfree(transfer_buffer);			return -ENOMEM;		}	}	// allocate memory for write_urb transfer buffer	port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);	if (! port->write_urb->transfer_buffer) {		kfree(transfer_buffer);		usb_free_urb(port->write_urb);		port->write_urb = NULL;		return -ENOMEM;	} 	// get hardware version	result = usb_control_msg( port->serial->dev, 				  usb_rcvctrlpipe(port->serial->dev, 0 ), 				  SUSBCRequest_GetMisc,				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,				  SUSBCR_MSC_GetHWVersion,				  0,				  transfer_buffer,				  transfer_buffer_length,				  KOBIL_TIMEOUT		);	dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);	dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );		// get firmware version	result = usb_control_msg( port->serial->dev, 				  usb_rcvctrlpipe(port->serial->dev, 0 ), 				  SUSBCRequest_GetMisc,				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,				  SUSBCR_MSC_GetFWVersion,				  0,				  transfer_buffer,				  transfer_buffer_length,				  KOBIL_TIMEOUT		);	dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);	dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {		// Setting Baudrate, Parity and Stopbits		result = usb_control_msg( port->serial->dev, 					  usb_rcvctrlpipe(port->serial->dev, 0 ), 					  SUSBCRequest_SetBaudRateParityAndStopBits,					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,					  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit,					  0,					  transfer_buffer,					  0,					  KOBIL_TIMEOUT			);		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);				// reset all queues		result = usb_control_msg( port->serial->dev, 					  usb_rcvctrlpipe(port->serial->dev, 0 ), 					  SUSBCRequest_Misc,					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,					  SUSBCR_MSC_ResetAllQueues,					  0,					  transfer_buffer,					  0,					  KOBIL_TIMEOUT			);		dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);	}	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||	    priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {		// start reading (Adapter B 'cause PNP string)		result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC  ); 		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);	}	kfree(transfer_buffer);	return 0;}static void kobil_close (struct usb_serial_port *port, struct file *filp){	dbg("%s - port %d", __FUNCTION__, port->number);	if (port->write_urb) {		usb_kill_urb(port->write_urb);		usb_free_urb( port->write_urb );		port->write_urb = NULL;	}	if (port->interrupt_in_urb)		usb_kill_urb(port->interrupt_in_urb);}static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs){	int i;	int result;	struct usb_serial_port *port = (struct usb_serial_port *) purb->context;	struct tty_struct *tty;	unsigned char *data = purb->transfer_buffer;//	char *dbg_data;	dbg("%s - port %d", __FUNCTION__, port->number);	if (purb->status) {		dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);		return;	}		tty = port->tty; 	if (purb->actual_length) {				// BEGIN DEBUG		/*		  dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);		  if (! dbg_data) {		  return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -