in pcmcia/cm4000_cs.c [1403:1620]
static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct cm4000_dev *dev = filp->private_data;
unsigned int iobase = dev->p_dev->resource[0]->start;
struct inode *inode = file_inode(filp);
struct pcmcia_device *link;
int rc;
void __user *argp = (void __user *)arg;
#ifdef CM4000_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",
};
DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
iminor(inode), ioctl_names[_IOC_NR(cmd)]);
#endif
mutex_lock(&cmm_mutex);
rc = -ENODEV;
link = dev_table[iminor(inode)];
if (!pcmcia_dev_present(link)) {
DEBUGP(4, dev, "DEV_OK false\n");
goto out;
}
if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
DEBUGP(4, dev, "CMM_ABSENT flag set\n");
goto out;
}
rc = -EINVAL;
if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) {
DEBUGP(4, dev, "ioctype mismatch\n");
goto out;
}
if (_IOC_NR(cmd) > CM_IOC_MAXNR) {
DEBUGP(4, dev, "iocnr mismatch\n");
goto out;
}
rc = 0;
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)))
rc = -EFAULT;
}
break;
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)
rc = -EAGAIN;
else
rc = -ERESTARTSYS;
break;
}
rc = -EFAULT;
if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {
tmp = -1;
if (copy_to_user(&(atreq->atr_len), &tmp,
sizeof(int)))
break;
} else {
if (copy_to_user(atreq->atr, dev->atr,
dev->atr_len))
break;
tmp = dev->atr_len;
if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int)))
break;
}
rc = 0;
break;
}
case CM_IOCARDOFF:
#ifdef CM4000_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)
rc = -EAGAIN;
else
rc = -ERESTARTSYS;
break;
}
/* 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)
rc = -EAGAIN;
else
rc = -ERESTARTSYS;
break;
}
}
/* release lock */
clear_bit(LOCK_IO, &dev->flags);
wake_up_interruptible(&dev->ioq);
rc = 0;
break;
case CM_IOCSPTS:
{
struct ptsreq krnptsreq;
if (copy_from_user(&krnptsreq, argp,
sizeof(struct ptsreq))) {
rc = -EFAULT;
break;
}
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)
rc = -EAGAIN;
else
rc = -ERESTARTSYS;
break;
}
/* 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)
rc = -EAGAIN;
else
rc = -ERESTARTSYS;
break;
}
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);
}
break;
#ifdef CM4000_DEBUG
case CM_IOSDBGLVL:
rc = -ENOTTY;
break;
#endif
default:
DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");
rc = -ENOTTY;
}
out:
mutex_unlock(&cmm_mutex);
return rc;
}