static ssize_t cmm_read()

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;
}