in pcmcia/cm4000_cs.c [926:1048]
static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
loff_t *ppos)
{
struct cm4000_dev *dev = filp->private_data;
unsigned int iobase = dev->p_dev->resource[0]->start;
ssize_t rc;
int i, j, k;
DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid);
if (count == 0) /* according to manpage */
return 0;
if (!pcmcia_dev_present(dev->p_dev) || /* device removed */
test_bit(IS_CMM_ABSENT, &dev->flags))
return -ENODEV;
if (test_bit(IS_BAD_CSUM, &dev->flags))
return -EIO;
/* also see the note about this in cmm_write */
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)
return -EIO;
/* this one implements blocking IO */
if (wait_event_interruptible
(dev->readq,
((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) {
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
return -ERESTARTSYS;
}
/* 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;
}
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 {
rc = -EIO;
}
goto release_io;
}
DEBUGP(4, dev, "begin read answer\n");
j = min(count, (size_t)(dev->rlen - dev->rpos));
k = dev->rpos;
if (k + j > 255)
j = 256 - k;
DEBUGP(4, dev, "read1 j=%d\n", j);
for (i = 0; i < j; i++) {
xoutb(k++, REG_BUF_ADDR(iobase));
dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
}
j = min(count, (size_t)(dev->rlen - dev->rpos));
if (k + j > 255) {
DEBUGP(4, dev, "read2 j=%d\n", j);
dev->flags1 |= 0x10; /* MSB buf addr set */
xoutb(dev->flags1, REG_FLAGS1(iobase));
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 && i) {
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)) {
rc = -ENODEV;
goto release_io;
}
if (test_bit(IS_INVREV, &dev->flags) && count > 0)
str_invert_revert(dev->rbuf, count);
if (copy_to_user(buf, dev->rbuf, count))
rc = -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;
}