📄 cm4000_cs.c
字号:
/* is a card inserted and powered? */ if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) { /* get IO lock */ if (wait_event_interruptible (dev->ioq, ((filp->f_flags & O_NONBLOCK) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; return -ERESTARTSYS; } /* Set Flags0 = 0x42 */ DEBUGP(4, dev, "Set Flags0=0x42 \n"); xoutb(0x42, REG_FLAGS0(iobase)); clear_bit(IS_ATR_PRESENT, &dev->flags); clear_bit(IS_ATR_VALID, &dev->flags); dev->mstate = M_CARDOFF; clear_bit(LOCK_IO, &dev->flags); if (wait_event_interruptible (dev->atrq, ((filp->f_flags & O_NONBLOCK) || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; return -ERESTARTSYS; } } /* release lock */ clear_bit(LOCK_IO, &dev->flags); wake_up_interruptible(&dev->ioq); return 0; case CM_IOCSPTS: { struct ptsreq krnptsreq; if (copy_from_user(&krnptsreq, argp, sizeof(struct ptsreq))) return -EFAULT; rc = 0; DEBUGP(4, dev, "... in CM_IOCSPTS\n"); /* wait for ATR to get valid */ if (wait_event_interruptible (dev->atrq, ((filp->f_flags & O_NONBLOCK) || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; return -ERESTARTSYS; } /* get IO lock */ if (wait_event_interruptible (dev->ioq, ((filp->f_flags & O_NONBLOCK) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; return -ERESTARTSYS; } if ((rc = set_protocol(dev, &krnptsreq)) != 0) { /* auto power_on again */ dev->mstate = M_FETCH_ATR; clear_bit(IS_ATR_VALID, &dev->flags); } /* release lock */ clear_bit(LOCK_IO, &dev->flags); wake_up_interruptible(&dev->ioq); } return rc;#ifdef PCMCIA_DEBUG case CM_IOSDBGLVL: /* set debug log level */ { int old_pc_debug = 0; old_pc_debug = pc_debug; if (copy_from_user(&pc_debug, argp, sizeof(int))) return -EFAULT; if (old_pc_debug != pc_debug) DEBUGP(0, dev, "Changed debug log level " "to %i\n", pc_debug); } return rc;#endif default: DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); return -EINVAL; }}static int cmm_open(struct inode *inode, struct file *filp){ struct cm4000_dev *dev; dev_link_t *link; int rc, minor = iminor(inode); if (minor >= CM4000_MAX_DEV) return -ENODEV; link = dev_table[minor]; if (link == NULL || !(DEV_OK(link))) return -ENODEV; if (link->open) return -EBUSY; dev = link->priv; filp->private_data = dev; DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n", imajor(inode), minor, current->comm, current->pid); /* init device variables, they may be "polluted" after close * or, the device may never have been closed (i.e. open failed) */ ZERO_DEV(dev); /* opening will always block since the * monitor will be started by open, which * means we have to wait for ATR becoming * vaild = block until valid (or card * inserted) */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; dev->mdelay = T_50MSEC; /* start monitoring the cardstatus */ start_monitor(dev); link->open = 1; /* only one open per device */ rc = 0; DEBUGP(2, dev, "<- cmm_open\n"); return nonseekable_open(inode, filp);}static int cmm_close(struct inode *inode, struct file *filp){ struct cm4000_dev *dev; dev_link_t *link; int minor = iminor(inode); if (minor >= CM4000_MAX_DEV) return -ENODEV; link = dev_table[minor]; if (link == NULL) return -ENODEV; dev = link->priv; DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n", imajor(inode), minor); stop_monitor(dev); ZERO_DEV(dev); link->open = 0; /* only one open per device */ wake_up(&dev->devq); /* socket removed? */ DEBUGP(2, dev, "cmm_close\n"); return 0;}static void cmm_cm4000_release(dev_link_t * link){ struct cm4000_dev *dev = link->priv; /* dont terminate the monitor, rather rely on * close doing that for us. */ DEBUGP(3, dev, "-> cmm_cm4000_release\n"); while (link->open) { printk(KERN_INFO MODULE_NAME ": delaying release until " "process has terminated\n"); /* note: don't interrupt us: * close the applications which own * the devices _first_ ! */ wait_event(dev->devq, (link->open == 0)); } /* dev->devq=NULL; this cannot be zeroed earlier */ DEBUGP(3, dev, "<- cmm_cm4000_release\n"); return;}/*==== Interface to PCMCIA Layer =======================================*/static void cm4000_config(dev_link_t * link, int devno){ client_handle_t handle = link->handle; struct cm4000_dev *dev; tuple_t tuple; cisparse_t parse; config_info_t conf; u_char buf[64]; int fail_fn, fail_rc; int rc; /* read the config-tuples */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; 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; 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; /* Get the IOaddr */ 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); if (rc == CS_SUCCESS) break; /* we are done */ } if (rc != CS_SUCCESS) goto cs_release; link->conf.IntType = 00000002; if ((fail_rc = pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) { fail_fn = RequestConfiguration; goto cs_release; } dev = link->priv; 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; return;cs_failed: cs_error(handle, fail_fn, fail_rc);cs_release: cm4000_release(link); link->state &= ~DEV_CONFIG_PENDING;}static int cm4000_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link; struct cm4000_dev *dev; int devno; link = args->client_data; dev = link->priv; DEBUGP(3, dev, "-> cm4000_event\n"); for (devno = 0; devno < CM4000_MAX_DEV; devno++) if (dev_table[devno] == link) break; if (devno == CM4000_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; cm4000_config(link, devno); break; case CS_EVENT_CARD_REMOVAL: DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n"); link->state &= ~DEV_PRESENT; stop_monitor(dev); break; case CS_EVENT_PM_SUSPEND: DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND " "(fall-through to CS_EVENT_RESET_PHYSICAL)\n"); link->state |= DEV_SUSPEND; /* fall-through */ case CS_EVENT_RESET_PHYSICAL: DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n"); if (link->state & DEV_CONFIG) { DEBUGP(5, dev, "ReleaseConfiguration\n"); pcmcia_release_configuration(link->handle); } stop_monitor(dev); break; case CS_EVENT_PM_RESUME: DEBUGP(5, dev, "CS_EVENT_PM_RESUME " "(fall-through to CS_EVENT_CARD_RESET)\n"); link->state &= ~DEV_SUSPEND; /* fall-through */ case CS_EVENT_CARD_RESET: DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n"); if ((link->state & DEV_CONFIG)) { DEBUGP(5, dev, "RequestConfiguration\n"); pcmcia_request_configuration(link->handle, &link->conf); } if (link->open) start_monitor(dev); break; default: DEBUGP(5, dev, "unknown event %.2x\n", event); break; } DEBUGP(3, dev, "<- cm4000_event\n"); return CS_SUCCESS;}static void cm4000_release(dev_link_t *link){ cmm_cm4000_release(link->priv); /* delay release until device closed */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io);}static dev_link_t *cm4000_attach(void){ struct cm4000_dev *dev; dev_link_t *link; client_reg_t client_reg; int i; for (i = 0; i < CM4000_MAX_DEV; i++) if (dev_table[i] == NULL) break; if (i == CM4000_MAX_DEV) { printk(KERN_NOTICE MODULE_NAME ": all devices in use\n"); return NULL; } /* create a new cm4000_cs device */ dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); if (dev == NULL) return NULL; link = &dev->link; link->priv = dev; link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; /* register with card services */ client_reg.dev_info = &dev_info; 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); cm4000_detach(link); return NULL; } init_waitqueue_head(&dev->devq); init_waitqueue_head(&dev->ioq); init_waitqueue_head(&dev->atrq); init_waitqueue_head(&dev->readq); return link;}static void cm4000_detach_by_devno(int devno, dev_link_t * link){ struct cm4000_dev *dev = link->priv; DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno); if (link->state & DEV_CONFIG) { DEBUGP(5, dev, "device still configured (try to release it)\n"); cm4000_release(link); } if (link->handle) { pcmcia_deregister_client(link->handle); } dev_table[devno] = NULL; kfree(dev); return;}static void cm4000_detach(dev_link_t * link){ int i; /* find device */ for (i = 0; i < CM4000_MAX_DEV; i++) if (dev_table[i] == link) break; if (i == CM4000_MAX_DEV) return; cm4000_detach_by_devno(i, link); return;}static struct file_operations cm4000_fops = { .owner = THIS_MODULE, .read = cmm_read, .write = cmm_write, .ioctl = cmm_ioctl, .open = cmm_open, .release= cmm_close,};static struct pcmcia_device_id cm4000_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002), PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39), PCMCIA_DEVICE_NULL,};MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);static struct pcmcia_driver cm4000_driver = { .owner = THIS_MODULE, .drv = { .name = "cm4000_cs", }, .attach = cm4000_attach, .detach = cm4000_detach, .event = cm4000_event, .id_table = cm4000_ids,};static int __init cmm_init(void){ printk(KERN_INFO "%s\n", version); pcmcia_register_driver(&cm4000_driver); major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); return -1; } return 0;}static void __exit cmm_exit(void){ int i; printk(KERN_INFO MODULE_NAME ": unloading\n"); pcmcia_unregister_driver(&cm4000_driver); for (i = 0; i < CM4000_MAX_DEV; i++) if (dev_table[i]) cm4000_detach_by_devno(i, dev_table[i]); unregister_chrdev(major, DEVICE_NAME);};module_init(cmm_init);module_exit(cmm_exit);MODULE_LICENSE("Dual BSD/GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -