X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fchar%2Fpcmcia%2Fcm4040_cs.c;h=a6a70e476beaf4babb7446643775d92ed5866635;hb=07a71415d5f790385695784a9b0e554412ee95c3;hp=3622fd39c47b5fdc9048559a6d703f6f89db0ebd;hpb=98e4c28b7ec390c2dad6a4c69d69629c0f7e8b10;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 3622fd3..a6a70e4 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -3,12 +3,13 @@ * * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/) * - * (C) 2005 Harald Welte + * (C) 2005-2006 Harald Welte * - add support for poll() * - driver cleanup * - add waitqueues * - adhere to linux kernel coding style and policies * - support 2.6.13 "new style" pcmcia interface + * - add class interface for udev device creation * * The device basically is a USB CCID compliant device that has been * attached to an I/O-Mapped FIFO. @@ -16,8 +17,6 @@ * All rights reserved, Dual BSD/GPL Licensed. */ -/* #define PCMCIA_DEBUG 6 */ - #include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,21 +39,19 @@ #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); \ +#define reader_to_dev(x) (&x->p_dev->dev) + +/* n (debug level) is ignored */ +/* additional debug output may be enabled by re-compiling with + * CM4040_DEBUG set */ +/* #define CM4040_DEBUG */ +#define DEBUGP(n, rdr, x, args...) do { \ + dev_dbg(reader_to_dev(rdr), "%s:" x, \ + __func__ , ## args); \ } while (0) -#else -#define DEBUGP(n, rdr, x, args...) -#endif static char *version = -"OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte"; +"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte"; #define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ) #define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ) @@ -64,16 +62,16 @@ static char *version = /* 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 void reader_release(struct pcmcia_device *link); static int major; +static struct class *cmx_class; #define BS_READABLE 0x01 #define BS_WRITABLE 0x02 struct reader_dev { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; wait_queue_head_t devq; wait_queue_head_t poll_wait; @@ -86,17 +84,15 @@ struct reader_dev { struct timer_list poll_timer; }; -static dev_info_t dev_info = MODULE_NAME; -static dev_link_t *dev_table[CM_MAX_DEV]; +static struct pcmcia_device *dev_table[CM_MAX_DEV]; -#ifndef PCMCIA_DEBUG +#ifndef CM4040_DEBUG #define xoutb outb #define xinb inb #else static inline void xoutb(unsigned char val, unsigned short port) { - if (pc_debug >= 7) - printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port); + pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); outb(val, port); } @@ -105,8 +101,7 @@ 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); + pr_debug("%.2x=inb(%.4x)\n", val, port); return val; } #endif @@ -116,7 +111,7 @@ static inline unsigned char xinb(unsigned short port) static void cm4040_do_poll(unsigned long dummy) { struct reader_dev *dev = (struct reader_dev *) dummy; - unsigned int obs = xinb(dev->link.io.BasePort1 + unsigned int obs = xinb(dev->p_dev->io.BasePort1 + REG_OFFSET_BUFFER_STATUS); if ((obs & BSR_BULK_IN_FULL)) { @@ -147,7 +142,7 @@ static void cm4040_stop_poll(struct reader_dev *dev) static int wait_for_bulk_out_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -177,7 +172,7 @@ static int wait_for_bulk_out_ready(struct reader_dev *dev) /* Write to Sync Control Register */ static int write_sync_reg(unsigned char val, struct reader_dev *dev) { - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; int rc; rc = wait_for_bulk_out_ready(dev); @@ -195,7 +190,7 @@ static int write_sync_reg(unsigned char val, struct reader_dev *dev) static int wait_for_bulk_in_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -225,7 +220,7 @@ 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; + int iobase = dev->p_dev->io.BasePort1; size_t bytes_to_read; unsigned long i; size_t min_bytes_to_read; @@ -246,7 +241,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, return -EAGAIN; } - if ((dev->link.state & DEV_PRESENT)==0) + if (!pcmcia_dev_present(dev->p_dev)) return -ENODEV; for (i = 0; i < 5; i++) { @@ -259,22 +254,22 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, 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]); +#ifdef CM4040_DEBUG + pr_debug("%lu:%2x ", i, dev->r_buf[i]); } - printk("\n"); + pr_debug("\n"); #else } #endif bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]); - DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read); + DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read); min_bytes_to_read = min(count, bytes_to_read + 5); + min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE); - DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read); + DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read); for (i = 0; i < (min_bytes_to_read-5); i++) { rc = wait_for_bulk_in_ready(dev); @@ -286,11 +281,10 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, 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]); +#ifdef CM4040_DEBUG + pr_debug("%lu:%2x ", i, dev->r_buf[i]); } - printk("\n"); + pr_debug("\n"); #else } #endif @@ -328,7 +322,7 @@ 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; + int iobase = dev->p_dev->io.BasePort1; ssize_t rc; int i; unsigned int bytes_to_write; @@ -340,7 +334,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, return 0; } - if (count < 5) { + if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) { DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count); return -EIO; } @@ -351,7 +345,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, return -EAGAIN; } - if ((dev->link.state & DEV_PRESENT) == 0) + if (!pcmcia_dev_present(dev->p_dev)) return -ENODEV; bytes_to_write = count; @@ -445,25 +439,32 @@ static unsigned int cm4040_poll(struct file *filp, poll_table *wait) static int cm4040_open(struct inode *inode, struct file *filp) { struct reader_dev *dev; - dev_link_t *link; + struct pcmcia_device *link; int minor = iminor(inode); + int ret; if (minor >= CM_MAX_DEV) return -ENODEV; + lock_kernel(); link = dev_table[minor]; - if (link == NULL || !(DEV_OK(link))) - return -ENODEV; + if (link == NULL || !pcmcia_dev_present(link)) { + ret = -ENODEV; + goto out; + } - if (link->open) - return -EBUSY; + if (link->open) { + ret = -EBUSY; + goto out; + } dev = link->priv; filp->private_data = dev; if (filp->f_flags & O_NONBLOCK) { DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - return -EAGAIN; + ret = -EAGAIN; + goto out; } link->open = 1; @@ -472,13 +473,16 @@ static int cm4040_open(struct inode *inode, struct file *filp) mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); - return nonseekable_open(inode, filp); + ret = nonseekable_open(inode, filp); +out: + unlock_kernel(); + return ret; } static int cm4040_close(struct inode *inode, struct file *filp) { struct reader_dev *dev = filp->private_data; - dev_link_t *link; + struct pcmcia_device *link; int minor = iminor(inode); DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode), @@ -500,7 +504,7 @@ static int cm4040_close(struct inode *inode, struct file *filp) return 0; } -static void cm4040_reader_release(dev_link_t *link) +static void cm4040_reader_release(struct pcmcia_device *link) { struct reader_dev *dev = link->priv; @@ -514,95 +518,50 @@ static void cm4040_reader_release(dev_link_t *link) return; } -static void reader_config(dev_link_t *link, int devno) +static int cm4040_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) { - client_handle_t handle; - struct reader_dev *dev; - tuple_t tuple; - cisparse_t parse; - config_info_t conf; - u_char buf[64]; - int fail_fn, fail_rc; int rc; + if (!cfg->io.nwin) + return -ENODEV; - handle = link->handle; - - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; + /* Get the IOaddr */ + p_dev->io.BasePort1 = cfg->io.win[0].base; + p_dev->io.NumPorts1 = cfg->io.win[0].len; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(cfg->io.flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(cfg->io.flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; + + rc = pcmcia_request_io(p_dev, &p_dev->io); + dev_printk(KERN_INFO, &p_dev->dev, + "pcmcia_request_io returned 0x%x\n", rc); + return rc; +} - if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) { - fail_fn = GetFirstTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) { - fail_fn = GetTupleData; - goto cs_failed; - } - if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse)) - != CS_SUCCESS) { - fail_fn = ParseTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_configuration_info(handle, &conf)) - != CS_SUCCESS) { - fail_fn = GetConfigurationInfo; - goto cs_failed; - } - link->state |= DEV_CONFIG; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->conf.Vcc = conf.Vcc; +static int reader_config(struct pcmcia_device *link, int devno) +{ + struct reader_dev *dev; + int fail_rc; link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (rc = pcmcia_get_first_tuple(handle, &tuple); - rc == CS_SUCCESS; - rc = pcmcia_get_next_tuple(handle, &tuple)) { - rc = pcmcia_get_tuple_data(handle, &tuple); - if (rc != CS_SUCCESS) - continue; - rc = pcmcia_parse_tuple(handle, &tuple, &parse); - if (rc != CS_SUCCESS) - continue; - - link->conf.ConfigIndex = parse.cftable_entry.index; - - if (!parse.cftable_entry.io.nwin) - continue; - - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = parse.cftable_entry.io.flags - & CISTPL_IO_LINES_MASK; - rc = pcmcia_request_io(handle, &link->io); - - dev_printk(KERN_INFO, &handle_to_dev(handle), "foo"); - if (rc == CS_SUCCESS) - break; - else - dev_printk(KERN_INFO, &handle_to_dev(handle), - "pcmcia_request_io failed 0x%x\n", rc); - } - if (rc != CS_SUCCESS) + + if (pcmcia_loop_config(link, cm4040_config_check, NULL)) goto cs_release; link->conf.IntType = 00000002; - if ((fail_rc = pcmcia_request_configuration(handle,&link->conf)) - !=CS_SUCCESS) { - fail_fn = RequestConfiguration; - dev_printk(KERN_INFO, &handle_to_dev(handle), + fail_rc = pcmcia_request_configuration(link, &link->conf); + if (fail_rc != 0) { + dev_printk(KERN_INFO, &link->dev, "pcmcia_request_configuration failed 0x%x\n", fail_rc); goto cs_release; @@ -612,95 +571,29 @@ static void reader_config(dev_link_t *link, int devno) sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno); dev->node.major = major; dev->node.minor = devno; - dev->node.next = NULL; - link->dev = &dev->node; - link->state &= ~DEV_CONFIG_PENDING; + dev->node.next = &dev->node; DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno, link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1); DEBUGP(2, dev, "<- reader_config (succ)\n"); - return; + return 0; -cs_failed: - cs_error(handle, fail_fn, fail_rc); cs_release: reader_release(link); - link->state &= ~DEV_CONFIG_PENDING; -} - -static int reader_event(event_t event, int priority, - event_callback_args_t *args) -{ - dev_link_t *link; - struct reader_dev *dev; - int devno; - - link = args->client_data; - dev = link->priv; - DEBUGP(3, dev, "-> reader_event\n"); - for (devno = 0; devno < CM_MAX_DEV; devno++) { - if (dev_table[devno] == link) - break; - } - if (devno == CM_MAX_DEV) - return CS_BAD_ADAPTER; - - switch (event) { - case CS_EVENT_CARD_INSERTION: - DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n"); - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - reader_config(link, devno); - break; - case CS_EVENT_CARD_REMOVAL: - DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n"); - link->state &= ~DEV_PRESENT; - break; - - default: - DEBUGP(5, dev, "reader_event: unknown event %.2x\n", - event); - break; - } - DEBUGP(3, dev, "<- reader_event\n"); - return CS_SUCCESS; + return -ENODEV; } -static int reader_suspend(struct pcmcia_device *p_dev) +static void reader_release(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; + cm4040_reader_release(link); + pcmcia_disable_device(link); } -static int reader_resume(struct pcmcia_device *p_dev) -{ - dev_link_t *link = dev_to_instance(p_dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - -static void reader_release(dev_link_t *link) -{ - cm4040_reader_release(link->priv); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); -} - -static dev_link_t *reader_attach(void) +static int reader_probe(struct pcmcia_device *link) { struct reader_dev *dev; - dev_link_t *link; - client_reg_t client_reg; - int i; + int i, ret; for (i = 0; i < CM_MAX_DEV; i++) { if (dev_table[i] == NULL) @@ -708,79 +601,63 @@ static dev_link_t *reader_attach(void) } if (i == CM_MAX_DEV) - return NULL; + return -ENODEV; dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL); if (dev == NULL) - return NULL; + return -ENOMEM; dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; dev->buffer_status = 0; - link = &dev->link; link->priv = dev; + dev->p_dev = link; link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask= - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - i = pcmcia_register_client(&link->handle, &client_reg); - if (i) { - cs_error(link->handle, RegisterClient, i); - reader_detach(link); - return NULL; - } init_waitqueue_head(&dev->devq); init_waitqueue_head(&dev->poll_wait); init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); - init_timer(&dev->poll_timer); - dev->poll_timer.function = &cm4040_do_poll; - - return link; -} - -static void reader_detach_by_devno(int devno, dev_link_t *link) -{ - struct reader_dev *dev = link->priv; + setup_timer(&dev->poll_timer, cm4040_do_poll, 0); - if (link->state & DEV_CONFIG) { - DEBUGP(5, dev, "device still configured (try to release it)\n"); - reader_release(link); + ret = reader_config(link, i); + if (ret) { + dev_table[i] = NULL; + kfree(dev); + return ret; } - pcmcia_deregister_client(link->handle); - dev_table[devno] = NULL; - DEBUGP(5, dev, "freeing dev=%p\n", dev); - cm4040_stop_poll(dev); - kfree(dev); - return; + device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i); + + return 0; } -static void reader_detach(dev_link_t *link) +static void reader_detach(struct pcmcia_device *link) { - int i; + struct reader_dev *dev = link->priv; + int devno; /* find device */ - for (i = 0; i < CM_MAX_DEV; i++) { - if (dev_table[i] == link) + for (devno = 0; devno < CM_MAX_DEV; devno++) { + if (dev_table[devno] == link) break; } - if (i == CM_MAX_DEV) + if (devno == CM_MAX_DEV) return; - reader_detach_by_devno(i, link); + reader_release(link); + + dev_table[devno] = NULL; + kfree(dev); + + device_destroy(cmx_class, MKDEV(major, devno)); + return; } -static struct file_operations reader_fops = { +static const struct file_operations reader_fops = { .owner = THIS_MODULE, .read = cm4040_read, .write = cm4040_write, @@ -802,38 +679,44 @@ static struct pcmcia_driver reader_driver = { .drv = { .name = "cm4040_cs", }, - .attach = reader_attach, - .detach = reader_detach, - .suspend = reader_suspend, - .resume = reader_resume, - .event = reader_event, + .probe = reader_probe, + .remove = reader_detach, .id_table = cm4040_ids, }; static int __init cm4040_init(void) { + int rc; + printk(KERN_INFO "%s\n", version); - pcmcia_register_driver(&reader_driver); + cmx_class = class_create(THIS_MODULE, "cardman_4040"); + if (IS_ERR(cmx_class)) + return PTR_ERR(cmx_class); + major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); - return -1; + class_destroy(cmx_class); + return major; + } + + rc = pcmcia_register_driver(&reader_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + class_destroy(cmx_class); + return rc; } + return 0; } static void __exit cm4040_exit(void) { - int i; - printk(KERN_INFO MODULE_NAME ": unloading\n"); pcmcia_unregister_driver(&reader_driver); - for (i = 0; i < CM_MAX_DEV; i++) { - if (dev_table[i]) - reader_detach_by_devno(i, dev_table[i]); - } unregister_chrdev(major, DEVICE_NAME); + class_destroy(cmx_class); } module_init(cm4040_init);