📄 cm4000_cs.c
字号:
for (; i < j; i++) { xoutb(k++, REG_BUF_ADDR(iobase)); dev->rbuf[i] = xinb(REG_BUF_DATA(iobase)); } } if (dev->proto == 0 && count > dev->rlen - dev->rpos) { DEBUGP(4, dev, "T=0 and count > buffer\n"); dev->rbuf[i] = dev->rbuf[i - 1]; dev->rbuf[i - 1] = dev->procbyte; j++; } count = j; dev->rpos = dev->rlen + 1; /* Clear T1Active */ DEBUGP(4, dev, "Clear T1Active\n"); dev->flags1 &= 0xdf; xoutb(dev->flags1, REG_FLAGS1(iobase)); xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */ /* last check before exit */ if (!io_detect_cm4000(iobase, dev)) count = -ENODEV; if (test_bit(IS_INVREV, &dev->flags) && count > 0) str_invert_revert(dev->rbuf, count); if (copy_to_user(buf, dev->rbuf, count)) return -EFAULT;release_io: clear_bit(LOCK_IO, &dev->flags); wake_up_interruptible(&dev->ioq); DEBUGP(2, dev, "<- cmm_read returns: rc = %Zi\n", (rc < 0 ? rc : count)); return rc < 0 ? rc : count;}static ssize_t cmm_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data; ioaddr_t iobase = dev->link.io.BasePort1; unsigned short s; unsigned char tmp; unsigned char infolen; unsigned char sendT0; unsigned short nsend; unsigned short nr; ssize_t rc; int i; DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid); if (count == 0) /* according to manpage */ return 0; if (dev->proto == 0 && count < 4) { /* T0 must have at least 4 bytes */ DEBUGP(4, dev, "T0 short write\n"); return -EIO; } nr = count & 0x1ff; /* max bytes to write */ sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0; if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */ test_bit(IS_CMM_ABSENT, &dev->flags)) return -ENODEV; if (test_bit(IS_BAD_CSUM, &dev->flags)) { DEBUGP(4, dev, "bad csum\n"); return -EIO; } /* * wait for atr to become valid. * note: it is important to lock this code. if we dont, the monitor * could be run between test_bit and the the call the sleep on the * atr-queue. if *then* the monitor detects atr valid, it will wake up * any process on the atr-queue, *but* since we have been interrupted, * we do not yet sleep on this queue. this would result in a missed * wake_up and the calling process would sleep forever (until * interrupted). also, do *not* restore_flags before sleep_on, because * this could result in the same situation! */ 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) { /* invalid atr */ DEBUGP(4, dev, "invalid ATR\n"); return -EIO; } /* lock io */ 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 (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count))) return -EFAULT; rc = 0; dev->flags0 = inb(REG_FLAGS0(iobase)); if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ || dev->flags0 == 0xff) { /* no cardman inserted */ clear_bit(IS_ATR_VALID, &dev->flags); if (dev->flags0 & 1) { set_bit(IS_CMM_ABSENT, &dev->flags); rc = -ENODEV; } else { DEBUGP(4, dev, "IO error\n"); rc = -EIO; } goto release_io; } xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ if (!io_detect_cm4000(iobase, dev)) { rc = -ENODEV; goto release_io; } /* reflect T=0 send/read mode in flags1 */ dev->flags1 |= (sendT0); set_cardparameter(dev); /* dummy read, reset flag procedure received */ tmp = inb(REG_FLAGS1(iobase)); dev->flags1 = 0x20 /* T_Active */ | (sendT0) | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity */ | (((dev->baudv - 1) & 0x0100) >> 8); /* MSB-Baud */ DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1); xoutb(dev->flags1, REG_FLAGS1(iobase)); /* xmit data */ DEBUGP(4, dev, "Xmit data\n"); for (i = 0; i < nr; i++) { if (i >= 256) { dev->flags1 = 0x20 /* T_Active */ | (sendT0) /* SendT0 */ /* inverse parity: */ | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0) | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */ | 0x10; /* set address high */ DEBUGP(4, dev, "dev->flags = 0x%.2x - set address " "high\n", dev->flags1); xoutb(dev->flags1, REG_FLAGS1(iobase)); } if (test_bit(IS_INVREV, &dev->flags)) { DEBUGP(4, dev, "Apply inverse convention for 0x%.2x " "-> 0x%.2x\n", (unsigned char)dev->sbuf[i], invert_revert(dev->sbuf[i])); xoutb(i, REG_BUF_ADDR(iobase)); xoutb(invert_revert(dev->sbuf[i]), REG_BUF_DATA(iobase)); } else { xoutb(i, REG_BUF_ADDR(iobase)); xoutb(dev->sbuf[i], REG_BUF_DATA(iobase)); } } DEBUGP(4, dev, "Xmit done\n"); if (dev->proto == 0) { /* T=0 proto: 0 byte reply */ if (nr == 4) { DEBUGP(4, dev, "T=0 assumes 0 byte reply\n"); xoutb(i, REG_BUF_ADDR(iobase)); if (test_bit(IS_INVREV, &dev->flags)) xoutb(0xff, REG_BUF_DATA(iobase)); else xoutb(0x00, REG_BUF_DATA(iobase)); } /* numSendBytes */ if (sendT0) nsend = nr; else { if (nr == 4) nsend = 5; else { nsend = 5 + (unsigned char)dev->sbuf[4]; if (dev->sbuf[4] == 0) nsend += 0x100; } } } else nsend = nr; /* T0: output procedure byte */ if (test_bit(IS_INVREV, &dev->flags)) { DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) " "0x%.2x\n", invert_revert(dev->sbuf[1])); xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase)); } else { DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]); xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase)); } DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n", (unsigned char)(nsend & 0xff)); xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase)); DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n", 0x40 /* SM_Active */ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ |(nsend & 0x100) >> 8 /* MSB numSendBytes */ ); xoutb(0x40 /* SM_Active */ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ |(nsend & 0x100) >> 8, /* MSB numSendBytes */ REG_FLAGS0(iobase)); /* wait for xmit done */ if (dev->proto == 1) { DEBUGP(4, dev, "Wait for xmit done\n"); for (i = 0; i < 1000; i++) { if (inb(REG_FLAGS0(iobase)) & 0x08) break; msleep_interruptible(10); } if (i == 1000) { DEBUGP(4, dev, "timeout waiting for xmit done\n"); rc = -EIO; goto release_io; } } /* T=1: wait for infoLen */ infolen = 0; if (dev->proto) { /* wait until infoLen is valid */ for (i = 0; i < 6000; i++) { /* max waiting time of 1 min */ io_read_num_rec_bytes(iobase, &s); if (s >= 3) { infolen = inb(REG_FLAGS1(iobase)); DEBUGP(4, dev, "infolen=%d\n", infolen); break; } msleep_interruptible(10); } if (i == 6000) { DEBUGP(4, dev, "timeout waiting for infoLen\n"); rc = -EIO; goto release_io; } } else clear_bit(IS_PROCBYTE_PRESENT, &dev->flags); /* numRecBytes | bit9 of numRecytes */ io_read_num_rec_bytes(iobase, &dev->rlen); for (i = 0; i < 600; i++) { /* max waiting time of 2 sec */ if (dev->proto) { if (dev->rlen >= infolen + 4) break; } msleep_interruptible(10); /* numRecBytes | bit9 of numRecytes */ io_read_num_rec_bytes(iobase, &s); if (s > dev->rlen) { DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n"); i = 0; /* reset timeout */ dev->rlen = s; } /* T=0: we are done when numRecBytes doesn't * increment any more and NoProcedureByte * is set and numRecBytes == bytes sent + 6 * (header bytes + data + 1 for sw2) * except when the card replies an error * which means, no data will be sent back. */ else if (dev->proto == 0) { if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) { /* no procedure byte received since last read */ DEBUGP(1, dev, "NoProcedure byte set\n"); /* i=0; */ } else { /* procedure byte received since last read */ DEBUGP(1, dev, "NoProcedure byte unset " "(reset timeout)\n"); dev->procbyte = inb(REG_FLAGS1(iobase)); DEBUGP(1, dev, "Read procedure byte 0x%.2x\n", dev->procbyte); i = 0; /* resettimeout */ } if (inb(REG_FLAGS0(iobase)) & 0x08) { DEBUGP(1, dev, "T0Done flag (read reply)\n"); break; } } if (dev->proto) infolen = inb(REG_FLAGS1(iobase)); } if (i == 600) { DEBUGP(1, dev, "timeout waiting for numRecBytes\n"); rc = -EIO; goto release_io; } else { if (dev->proto == 0) { DEBUGP(1, dev, "Wait for T0Done bit to be set\n"); for (i = 0; i < 1000; i++) { if (inb(REG_FLAGS0(iobase)) & 0x08) break; msleep_interruptible(10); } if (i == 1000) { DEBUGP(1, dev, "timeout waiting for T0Done\n"); rc = -EIO; goto release_io; } dev->procbyte = inb(REG_FLAGS1(iobase)); DEBUGP(4, dev, "Read procedure byte 0x%.2x\n", dev->procbyte); io_read_num_rec_bytes(iobase, &dev->rlen); DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen); } } /* T=1: read offset=zero, T=0: read offset=after challenge */ dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr; DEBUGP(4, dev, "dev->rlen = %i, dev->rpos = %i, nr = %i\n", dev->rlen, dev->rpos, nr);release_io: DEBUGP(4, dev, "Reset SM\n"); xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ if (rc < 0) { DEBUGP(4, dev, "Write failed but clear T_Active\n"); dev->flags1 &= 0xdf; xoutb(dev->flags1, REG_FLAGS1(iobase)); } clear_bit(LOCK_IO, &dev->flags); wake_up_interruptible(&dev->ioq); wake_up_interruptible(&dev->readq); /* tell read we have data */ /* ITSEC E2: clear write buffer */ memset((char *)dev->sbuf, 0, 512); /* return error or actually written bytes */ DEBUGP(2, dev, "<- cmm_write\n"); return rc < 0 ? rc : nr;}static void start_monitor(struct cm4000_dev *dev){ DEBUGP(3, dev, "-> start_monitor\n"); if (!dev->monitor_running) { DEBUGP(5, dev, "create, init and add timer\n"); init_timer(&dev->timer); dev->monitor_running = 1; dev->timer.expires = jiffies; dev->timer.data = (unsigned long) dev; dev->timer.function = monitor_card; add_timer(&dev->timer); } else DEBUGP(5, dev, "monitor already running\n"); DEBUGP(3, dev, "<- start_monitor\n");}static void stop_monitor(struct cm4000_dev *dev){ DEBUGP(3, dev, "-> stop_monitor\n"); if (dev->monitor_running) { DEBUGP(5, dev, "stopping monitor\n"); terminate_monitor(dev); /* reset monitor SM */ clear_bit(IS_ATR_VALID, &dev->flags); clear_bit(IS_ATR_PRESENT, &dev->flags); } else DEBUGP(5, dev, "monitor already stopped\n"); DEBUGP(3, dev, "<- stop_monitor\n");}static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ struct cm4000_dev *dev = filp->private_data; ioaddr_t iobase = dev->link.io.BasePort1; dev_link_t *link; int size; int rc; void __user *argp = (void __user *)arg;#ifdef PCMCIA_DEBUG char *ioctl_names[CM_IOC_MAXNR + 1] = { [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS", [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR", [_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF", [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS", [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", };#endif DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), iminor(inode), ioctl_names[_IOC_NR(cmd)]); link = dev_table[iminor(inode)]; if (!(DEV_OK(link))) { DEBUGP(4, dev, "DEV_OK false\n"); return -ENODEV; } if (test_bit(IS_CMM_ABSENT, &dev->flags)) { DEBUGP(4, dev, "CMM_ABSENT flag set\n"); return -ENODEV; } if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { DEBUGP(4, dev, "ioctype mismatch\n"); return -EINVAL; } if (_IOC_NR(cmd) > CM_IOC_MAXNR) { DEBUGP(4, dev, "iocnr mismatch\n"); return -EINVAL; } size = _IOC_SIZE(cmd); rc = 0; DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n", _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd); if (_IOC_DIR(cmd) & _IOC_READ) { if (!access_ok(VERIFY_WRITE, argp, size)) return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_WRITE) { if (!access_ok(VERIFY_READ, argp, size)) return -EFAULT; } switch (cmd) { case CM_IOCGSTATUS: DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n"); { int status; /* clear other bits, but leave inserted & powered as * they are */ status = dev->flags0 & 3; if (test_bit(IS_ATR_PRESENT, &dev->flags)) status |= CM_ATR_PRESENT; if (test_bit(IS_ATR_VALID, &dev->flags)) status |= CM_ATR_VALID; if (test_bit(IS_CMM_ABSENT, &dev->flags)) status |= CM_NO_READER; if (test_bit(IS_BAD_CARD, &dev->flags)) status |= CM_BAD_CARD; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -