📄 cm4000_cs.c
字号:
if (copy_to_user(argp, &status, sizeof(int))) return -EFAULT; } return 0; case CM_IOCGATR: DEBUGP(4, dev, "... in CM_IOCGATR\n"); { struct atreq __user *atreq = argp; int tmp; /* allow nonblocking io and being interrupted */ 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; } if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { tmp = -1; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) return -EFAULT; } else { if (copy_to_user(atreq->atr, dev->atr, dev->atr_len)) return -EFAULT; tmp = dev->atr_len; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) return -EFAULT; } return 0; } case CM_IOCARDOFF:#ifdef PCMCIA_DEBUG DEBUGP(4, dev, "... in CM_IOCARDOFF\n"); if (dev->flags0 & 0x01) { DEBUGP(4, dev, " Card inserted\n"); } else { DEBUGP(2, dev, " No card inserted\n"); } if (dev->flags0 & 0x02) { DEBUGP(4, dev, " Card powered\n"); } else { DEBUGP(2, dev, " Card not powered\n"); }#endif /* 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; struct pcmcia_device *link; int rc, minor = iminor(inode); if (minor >= CM4000_MAX_DEV) return -ENODEV; link = dev_table[minor]; if (link == NULL || !pcmcia_dev_present(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; struct pcmcia_device *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(struct pcmcia_device * 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 int cm4000_config(struct pcmcia_device * link, int devno){ struct cm4000_dev *dev; tuple_t tuple; cisparse_t parse; 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(link, &tuple)) != CS_SUCCESS) { fail_fn = GetFirstTuple; goto cs_failed; } if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { fail_fn = GetTupleData; goto cs_failed; } if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { fail_fn = ParseTuple; goto cs_failed; } link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; for (rc = pcmcia_get_first_tuple(link, &tuple); rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) { rc = pcmcia_get_tuple_data(link, &tuple); if (rc != CS_SUCCESS) continue; rc = pcmcia_parse_tuple(link, &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(link, &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(link, &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_node = &dev->node; return 0;cs_failed: cs_error(link, fail_fn, fail_rc);cs_release: cm4000_release(link); return -ENODEV;}static int cm4000_suspend(struct pcmcia_device *link){ struct cm4000_dev *dev; dev = link->priv; stop_monitor(dev); return 0;}static int cm4000_resume(struct pcmcia_device *link){ struct cm4000_dev *dev; dev = link->priv; if (link->open) start_monitor(dev); return 0;}static void cm4000_release(struct pcmcia_device *link){ cmm_cm4000_release(link->priv); /* delay release until device closed */ pcmcia_disable_device(link);}static int cm4000_probe(struct pcmcia_device *link){ struct cm4000_dev *dev; int i, ret; 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 -ENODEV; } /* create a new cm4000_cs device */ dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; dev->p_dev = link; link->priv = dev; link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; init_waitqueue_head(&dev->devq); init_waitqueue_head(&dev->ioq); init_waitqueue_head(&dev->atrq); init_waitqueue_head(&dev->readq); ret = cm4000_config(link, i); if (ret) return ret; class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i); return 0;}static void cm4000_detach(struct pcmcia_device *link){ struct cm4000_dev *dev = link->priv; int devno; /* find device */ for (devno = 0; devno < CM4000_MAX_DEV; devno++) if (dev_table[devno] == link) break; if (devno == CM4000_MAX_DEV) return; stop_monitor(dev); cm4000_release(link); dev_table[devno] = NULL; kfree(dev); class_device_destroy(cmm_class, MKDEV(major, devno)); 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", }, .probe = cm4000_probe, .remove = cm4000_detach, .suspend = cm4000_suspend, .resume = cm4000_resume, .id_table = cm4000_ids,};static int __init cmm_init(void){ int rc; printk(KERN_INFO "%s\n", version); cmm_class = class_create(THIS_MODULE, "cardman_4000"); if (!cmm_class) return -1; major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); return -1; } rc = pcmcia_register_driver(&cm4000_driver); if (rc < 0) { unregister_chrdev(major, DEVICE_NAME); return rc; } return 0;}static void __exit cmm_exit(void){ printk(KERN_INFO MODULE_NAME ": unloading\n"); pcmcia_unregister_driver(&cm4000_driver); unregister_chrdev(major, DEVICE_NAME); class_destroy(cmm_class);};module_init(cmm_init);module_exit(cmm_exit);MODULE_LICENSE("Dual BSD/GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -