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

📄 cm4040_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040 * * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/) * * (C) 2005 Harald Welte <laforge@gnumonks.org> * 	- add support for poll() * 	- driver cleanup * 	- add waitqueues * 	- adhere to linux kernel coding style and policies * 	- support 2.6.13 "new style" pcmcia interface * * The device basically is a USB CCID compliant device that has been * attached to an I/O-Mapped FIFO. * * All rights reserved, Dual BSD/GPL Licensed. *//* #define PCMCIA_DEBUG 6 */#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/wait.h>#include <asm/uaccess.h>#include <asm/io.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ciscode.h>#include <pcmcia/ds.h>#include "cm4040_cs.h"#ifdef PCMCIA_DEBUG#define reader_to_dev(x)	(&handle_to_dev(x->link.handle))static int pc_debug = PCMCIA_DEBUG;module_param(pc_debug, int, 0600);#define DEBUGP(n, rdr, x, args...) do { 				\	if (pc_debug >= (n)) 						\		dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, 	\			   __FUNCTION__ , ##args); 			\	} while (0)#else#define DEBUGP(n, rdr, x, args...)#endifstatic char *version ="OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte";#define	CCID_DRIVER_BULK_DEFAULT_TIMEOUT  	(150*HZ)#define	CCID_DRIVER_ASYNC_POWERUP_TIMEOUT 	(35*HZ)#define	CCID_DRIVER_MINIMUM_TIMEOUT 		(3*HZ)#define READ_WRITE_BUFFER_SIZE 512#define POLL_LOOP_COUNT				1000/* how often to poll for fifo status change */#define POLL_PERIOD 				msecs_to_jiffies(10)static void reader_release(dev_link_t *link);static void reader_detach(dev_link_t *link);static int major;#define		BS_READABLE	0x01#define		BS_WRITABLE	0x02struct reader_dev {	dev_link_t		link;	dev_node_t		node;	wait_queue_head_t	devq;	wait_queue_head_t	poll_wait;	wait_queue_head_t	read_wait;	wait_queue_head_t	write_wait;	unsigned long 	  	buffer_status;	unsigned long     	timeout;	unsigned char     	s_buf[READ_WRITE_BUFFER_SIZE];	unsigned char     	r_buf[READ_WRITE_BUFFER_SIZE];	struct timer_list 	poll_timer;};static dev_info_t dev_info = MODULE_NAME;static dev_link_t *dev_table[CM_MAX_DEV];#ifndef PCMCIA_DEBUG#define	xoutb	outb#define	xinb	inb#elsestatic inline void xoutb(unsigned char val, unsigned short port){	if (pc_debug >= 7)		printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);	outb(val, port);}static inline unsigned char xinb(unsigned short port){	unsigned char val;	val = inb(port);	if (pc_debug >= 7)		printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);	return val;}#endif/* poll the device fifo status register.  not to be confused with * the poll syscall. */static void cm4040_do_poll(unsigned long dummy){	struct reader_dev *dev = (struct reader_dev *) dummy;	unsigned int obs = xinb(dev->link.io.BasePort1				+ REG_OFFSET_BUFFER_STATUS);	if ((obs & BSR_BULK_IN_FULL)) {		set_bit(BS_READABLE, &dev->buffer_status);		DEBUGP(4, dev, "waking up read_wait\n");		wake_up_interruptible(&dev->read_wait);	} else		clear_bit(BS_READABLE, &dev->buffer_status);	if (!(obs & BSR_BULK_OUT_FULL)) {		set_bit(BS_WRITABLE, &dev->buffer_status);		DEBUGP(4, dev, "waking up write_wait\n");		wake_up_interruptible(&dev->write_wait);	} else		clear_bit(BS_WRITABLE, &dev->buffer_status);	if (dev->buffer_status)		wake_up_interruptible(&dev->poll_wait);	mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);}static void cm4040_stop_poll(struct reader_dev *dev){	del_timer_sync(&dev->poll_timer);}static int wait_for_bulk_out_ready(struct reader_dev *dev){	int i, rc;	int iobase = dev->link.io.BasePort1;	for (i = 0; i < POLL_LOOP_COUNT; i++) {		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)		    & BSR_BULK_OUT_FULL) == 0) {			DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i);			return 1;		}	}	DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",		dev->timeout);	rc = wait_event_interruptible_timeout(dev->write_wait,					      test_and_clear_bit(BS_WRITABLE,						       &dev->buffer_status),					      dev->timeout);	if (rc > 0)		DEBUGP(4, dev, "woke up: BulkOut empty\n");	else if (rc == 0)		DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n");	else if (rc < 0)		DEBUGP(4, dev, "woke up: signal arrived\n");	return rc;}/* Write to Sync Control Register */static int write_sync_reg(unsigned char val, struct reader_dev *dev){	int iobase = dev->link.io.BasePort1;	int rc;	rc = wait_for_bulk_out_ready(dev);	if (rc <= 0)		return rc;	xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL);	rc = wait_for_bulk_out_ready(dev);	if (rc <= 0)		return rc;	return 1;}static int wait_for_bulk_in_ready(struct reader_dev *dev){	int i, rc;	int iobase = dev->link.io.BasePort1;	for (i = 0; i < POLL_LOOP_COUNT; i++) {		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)		    & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) {			DEBUGP(3, dev, "BulkIn full (i=%d)\n", i);			return 1;		}	}	DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",		dev->timeout);	rc = wait_event_interruptible_timeout(dev->read_wait,					      test_and_clear_bit(BS_READABLE,						 	&dev->buffer_status),					      dev->timeout);	if (rc > 0)		DEBUGP(4, dev, "woke up: BulkIn full\n");	else if (rc == 0)		DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n");	else if (rc < 0)		DEBUGP(4, dev, "woke up: signal arrived\n");	return rc;}static ssize_t cm4040_read(struct file *filp, char __user *buf,			size_t count, loff_t *ppos){	struct reader_dev *dev = filp->private_data;	int iobase = dev->link.io.BasePort1;	size_t bytes_to_read;	unsigned long i;	size_t min_bytes_to_read;	int rc;	unsigned char uc;	DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);	if (count == 0)		return 0;	if (count < 10)		return -EFAULT;	if (filp->f_flags & O_NONBLOCK) {		DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");		DEBUGP(2, dev, "<- cm4040_read (failure)\n");		return -EAGAIN;	}	if ((dev->link.state & DEV_PRESENT)==0)		return -ENODEV;	for (i = 0; i < 5; i++) {		rc = wait_for_bulk_in_ready(dev);		if (rc <= 0) {			DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);			DEBUGP(2, dev, "<- cm4040_read (failed)\n");			if (rc == -ERESTARTSYS)				return rc;			return -EIO;		}	  	dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);#ifdef PCMCIA_DEBUG		if (pc_debug >= 6)			printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);	}	printk("\n");#else	}#endif	bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);	DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);	min_bytes_to_read = min(count, bytes_to_read + 5);	DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);	for (i = 0; i < (min_bytes_to_read-5); i++) {		rc = wait_for_bulk_in_ready(dev);		if (rc <= 0) {			DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);			DEBUGP(2, dev, "<- cm4040_read (failed)\n");			if (rc == -ERESTARTSYS)				return rc;			return -EIO;		}		dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);#ifdef PCMCIA_DEBUG		if (pc_debug >= 6)			printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);	}	printk("\n");#else	}#endif	*ppos = min_bytes_to_read;	if (copy_to_user(buf, dev->r_buf, min_bytes_to_read))		return -EFAULT;	rc = wait_for_bulk_in_ready(dev);	if (rc <= 0) {		DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);		DEBUGP(2, dev, "<- cm4040_read (failed)\n");		if (rc == -ERESTARTSYS)			return rc;		return -EIO;	}	rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev);	if (rc <= 0) {		DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc);		DEBUGP(2, dev, "<- cm4040_read (failed)\n");		if (rc == -ERESTARTSYS)			return rc;		else			return -EIO;	}	uc = xinb(iobase + REG_OFFSET_BULK_IN);	DEBUGP(2, dev, "<- cm4040_read (successfully)\n");	return min_bytes_to_read;}static ssize_t cm4040_write(struct file *filp, const char __user *buf,			 size_t count, loff_t *ppos){	struct reader_dev *dev = filp->private_data;	int iobase = dev->link.io.BasePort1;	ssize_t rc;	int i;	unsigned int bytes_to_write;	DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid);	if (count == 0) {		DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n");		return 0;	}	if (count < 5) {		DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count);		return -EIO;	}	if (filp->f_flags & O_NONBLOCK) {		DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");		DEBUGP(4, dev, "<- cm4040_write (failure)\n");		return -EAGAIN;	}	if ((dev->link.state & DEV_PRESENT) == 0)		return -ENODEV;	bytes_to_write = count;	if (copy_from_user(dev->s_buf, buf, bytes_to_write))		return -EFAULT;	switch (dev->s_buf[0]) {		case CMD_PC_TO_RDR_XFRBLOCK:		case CMD_PC_TO_RDR_SECURE:		case CMD_PC_TO_RDR_TEST_SECURE:		case CMD_PC_TO_RDR_OK_SECURE:			dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT;			break;		case CMD_PC_TO_RDR_ICCPOWERON:			dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;			break;		case CMD_PC_TO_RDR_GETSLOTSTATUS:		case CMD_PC_TO_RDR_ICCPOWEROFF:		case CMD_PC_TO_RDR_GETPARAMETERS:		case CMD_PC_TO_RDR_RESETPARAMETERS:		case CMD_PC_TO_RDR_SETPARAMETERS:		case CMD_PC_TO_RDR_ESCAPE:		case CMD_PC_TO_RDR_ICCCLOCK:		default:			dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;			break;	}	rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);	if (rc <= 0) {		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);		DEBUGP(2, dev, "<- cm4040_write (failed)\n");		if (rc == -ERESTARTSYS)			return rc;		else			return -EIO;	}	DEBUGP(4, dev, "start \n");	for (i = 0; i < bytes_to_write; i++) {		rc = wait_for_bulk_out_ready(dev);		if (rc <= 0) {			DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",			       rc);			DEBUGP(2, dev, "<- cm4040_write (failed)\n");			if (rc == -ERESTARTSYS)				return rc;			else				return -EIO;		}		xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT);	}	DEBUGP(4, dev, "end\n");	rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);	if (rc <= 0) {		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);		DEBUGP(2, dev, "<- cm4040_write (failed)\n");		if (rc == -ERESTARTSYS)			return rc;		else			return -EIO;

⌨️ 快捷键说明

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