diff options
Diffstat (limited to 'drivers/char/pcmcia/cm4000_cs.c')
-rw-r--r-- | drivers/char/pcmcia/cm4000_cs.c | 118 |
1 files changed, 75 insertions, 43 deletions
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4a933d413423..59ca35156d81 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c | |||
@@ -32,8 +32,9 @@ | |||
32 | #include <linux/fs.h> | 32 | #include <linux/fs.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/bitrev.h> | 34 | #include <linux/bitrev.h> |
35 | #include <asm/uaccess.h> | 35 | #include <linux/smp_lock.h> |
36 | #include <asm/io.h> | 36 | #include <linux/uaccess.h> |
37 | #include <linux/io.h> | ||
37 | 38 | ||
38 | #include <pcmcia/cs_types.h> | 39 | #include <pcmcia/cs_types.h> |
39 | #include <pcmcia/cs.h> | 40 | #include <pcmcia/cs.h> |
@@ -1405,11 +1406,11 @@ static void stop_monitor(struct cm4000_dev *dev) | |||
1405 | DEBUGP(3, dev, "<- stop_monitor\n"); | 1406 | DEBUGP(3, dev, "<- stop_monitor\n"); |
1406 | } | 1407 | } |
1407 | 1408 | ||
1408 | static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 1409 | static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1409 | unsigned long arg) | ||
1410 | { | 1410 | { |
1411 | struct cm4000_dev *dev = filp->private_data; | 1411 | struct cm4000_dev *dev = filp->private_data; |
1412 | unsigned int iobase = dev->p_dev->io.BasePort1; | 1412 | unsigned int iobase = dev->p_dev->io.BasePort1; |
1413 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
1413 | struct pcmcia_device *link; | 1414 | struct pcmcia_device *link; |
1414 | int size; | 1415 | int size; |
1415 | int rc; | 1416 | int rc; |
@@ -1426,38 +1427,42 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1426 | DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), | 1427 | DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), |
1427 | iminor(inode), ioctl_names[_IOC_NR(cmd)]); | 1428 | iminor(inode), ioctl_names[_IOC_NR(cmd)]); |
1428 | 1429 | ||
1430 | lock_kernel(); | ||
1431 | rc = -ENODEV; | ||
1429 | link = dev_table[iminor(inode)]; | 1432 | link = dev_table[iminor(inode)]; |
1430 | if (!pcmcia_dev_present(link)) { | 1433 | if (!pcmcia_dev_present(link)) { |
1431 | DEBUGP(4, dev, "DEV_OK false\n"); | 1434 | DEBUGP(4, dev, "DEV_OK false\n"); |
1432 | return -ENODEV; | 1435 | goto out; |
1433 | } | 1436 | } |
1434 | 1437 | ||
1435 | if (test_bit(IS_CMM_ABSENT, &dev->flags)) { | 1438 | if (test_bit(IS_CMM_ABSENT, &dev->flags)) { |
1436 | DEBUGP(4, dev, "CMM_ABSENT flag set\n"); | 1439 | DEBUGP(4, dev, "CMM_ABSENT flag set\n"); |
1437 | return -ENODEV; | 1440 | goto out; |
1438 | } | 1441 | } |
1442 | rc = EINVAL; | ||
1439 | 1443 | ||
1440 | if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { | 1444 | if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { |
1441 | DEBUGP(4, dev, "ioctype mismatch\n"); | 1445 | DEBUGP(4, dev, "ioctype mismatch\n"); |
1442 | return -EINVAL; | 1446 | goto out; |
1443 | } | 1447 | } |
1444 | if (_IOC_NR(cmd) > CM_IOC_MAXNR) { | 1448 | if (_IOC_NR(cmd) > CM_IOC_MAXNR) { |
1445 | DEBUGP(4, dev, "iocnr mismatch\n"); | 1449 | DEBUGP(4, dev, "iocnr mismatch\n"); |
1446 | return -EINVAL; | 1450 | goto out; |
1447 | } | 1451 | } |
1448 | size = _IOC_SIZE(cmd); | 1452 | size = _IOC_SIZE(cmd); |
1449 | rc = 0; | 1453 | rc = -EFAULT; |
1450 | DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n", | 1454 | DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n", |
1451 | _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd); | 1455 | _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd); |
1452 | 1456 | ||
1453 | if (_IOC_DIR(cmd) & _IOC_READ) { | 1457 | if (_IOC_DIR(cmd) & _IOC_READ) { |
1454 | if (!access_ok(VERIFY_WRITE, argp, size)) | 1458 | if (!access_ok(VERIFY_WRITE, argp, size)) |
1455 | return -EFAULT; | 1459 | goto out; |
1456 | } | 1460 | } |
1457 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 1461 | if (_IOC_DIR(cmd) & _IOC_WRITE) { |
1458 | if (!access_ok(VERIFY_READ, argp, size)) | 1462 | if (!access_ok(VERIFY_READ, argp, size)) |
1459 | return -EFAULT; | 1463 | goto out; |
1460 | } | 1464 | } |
1465 | rc = 0; | ||
1461 | 1466 | ||
1462 | switch (cmd) { | 1467 | switch (cmd) { |
1463 | case CM_IOCGSTATUS: | 1468 | case CM_IOCGSTATUS: |
@@ -1477,9 +1482,9 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1477 | if (test_bit(IS_BAD_CARD, &dev->flags)) | 1482 | if (test_bit(IS_BAD_CARD, &dev->flags)) |
1478 | status |= CM_BAD_CARD; | 1483 | status |= CM_BAD_CARD; |
1479 | if (copy_to_user(argp, &status, sizeof(int))) | 1484 | if (copy_to_user(argp, &status, sizeof(int))) |
1480 | return -EFAULT; | 1485 | rc = -EFAULT; |
1481 | } | 1486 | } |
1482 | return 0; | 1487 | break; |
1483 | case CM_IOCGATR: | 1488 | case CM_IOCGATR: |
1484 | DEBUGP(4, dev, "... in CM_IOCGATR\n"); | 1489 | DEBUGP(4, dev, "... in CM_IOCGATR\n"); |
1485 | { | 1490 | { |
@@ -1492,25 +1497,29 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1492 | || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) | 1497 | || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) |
1493 | != 0)))) { | 1498 | != 0)))) { |
1494 | if (filp->f_flags & O_NONBLOCK) | 1499 | if (filp->f_flags & O_NONBLOCK) |
1495 | return -EAGAIN; | 1500 | rc = -EAGAIN; |
1496 | return -ERESTARTSYS; | 1501 | else |
1502 | rc = -ERESTARTSYS; | ||
1503 | break; | ||
1497 | } | 1504 | } |
1498 | 1505 | ||
1506 | rc = -EFAULT; | ||
1499 | if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { | 1507 | if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { |
1500 | tmp = -1; | 1508 | tmp = -1; |
1501 | if (copy_to_user(&(atreq->atr_len), &tmp, | 1509 | if (copy_to_user(&(atreq->atr_len), &tmp, |
1502 | sizeof(int))) | 1510 | sizeof(int))) |
1503 | return -EFAULT; | 1511 | break; |
1504 | } else { | 1512 | } else { |
1505 | if (copy_to_user(atreq->atr, dev->atr, | 1513 | if (copy_to_user(atreq->atr, dev->atr, |
1506 | dev->atr_len)) | 1514 | dev->atr_len)) |
1507 | return -EFAULT; | 1515 | break; |
1508 | 1516 | ||
1509 | tmp = dev->atr_len; | 1517 | tmp = dev->atr_len; |
1510 | if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) | 1518 | if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) |
1511 | return -EFAULT; | 1519 | break; |
1512 | } | 1520 | } |
1513 | return 0; | 1521 | rc = 0; |
1522 | break; | ||
1514 | } | 1523 | } |
1515 | case CM_IOCARDOFF: | 1524 | case CM_IOCARDOFF: |
1516 | 1525 | ||
@@ -1538,8 +1547,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1538 | || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) | 1547 | || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) |
1539 | == 0)))) { | 1548 | == 0)))) { |
1540 | if (filp->f_flags & O_NONBLOCK) | 1549 | if (filp->f_flags & O_NONBLOCK) |
1541 | return -EAGAIN; | 1550 | rc = -EAGAIN; |
1542 | return -ERESTARTSYS; | 1551 | else |
1552 | rc = -ERESTARTSYS; | ||
1553 | break; | ||
1543 | } | 1554 | } |
1544 | /* Set Flags0 = 0x42 */ | 1555 | /* Set Flags0 = 0x42 */ |
1545 | DEBUGP(4, dev, "Set Flags0=0x42 \n"); | 1556 | DEBUGP(4, dev, "Set Flags0=0x42 \n"); |
@@ -1554,8 +1565,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1554 | || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != | 1565 | || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != |
1555 | 0)))) { | 1566 | 0)))) { |
1556 | if (filp->f_flags & O_NONBLOCK) | 1567 | if (filp->f_flags & O_NONBLOCK) |
1557 | return -EAGAIN; | 1568 | rc = -EAGAIN; |
1558 | return -ERESTARTSYS; | 1569 | else |
1570 | rc = -ERESTARTSYS; | ||
1571 | break; | ||
1559 | } | 1572 | } |
1560 | } | 1573 | } |
1561 | /* release lock */ | 1574 | /* release lock */ |
@@ -1568,8 +1581,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1568 | struct ptsreq krnptsreq; | 1581 | struct ptsreq krnptsreq; |
1569 | 1582 | ||
1570 | if (copy_from_user(&krnptsreq, argp, | 1583 | if (copy_from_user(&krnptsreq, argp, |
1571 | sizeof(struct ptsreq))) | 1584 | sizeof(struct ptsreq))) { |
1572 | return -EFAULT; | 1585 | rc = -EFAULT; |
1586 | break; | ||
1587 | } | ||
1573 | 1588 | ||
1574 | rc = 0; | 1589 | rc = 0; |
1575 | DEBUGP(4, dev, "... in CM_IOCSPTS\n"); | 1590 | DEBUGP(4, dev, "... in CM_IOCSPTS\n"); |
@@ -1580,8 +1595,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1580 | || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) | 1595 | || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) |
1581 | != 0)))) { | 1596 | != 0)))) { |
1582 | if (filp->f_flags & O_NONBLOCK) | 1597 | if (filp->f_flags & O_NONBLOCK) |
1583 | return -EAGAIN; | 1598 | rc = -EAGAIN; |
1584 | return -ERESTARTSYS; | 1599 | else |
1600 | rc = -ERESTARTSYS; | ||
1601 | break; | ||
1585 | } | 1602 | } |
1586 | /* get IO lock */ | 1603 | /* get IO lock */ |
1587 | if (wait_event_interruptible | 1604 | if (wait_event_interruptible |
@@ -1590,8 +1607,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1590 | || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) | 1607 | || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) |
1591 | == 0)))) { | 1608 | == 0)))) { |
1592 | if (filp->f_flags & O_NONBLOCK) | 1609 | if (filp->f_flags & O_NONBLOCK) |
1593 | return -EAGAIN; | 1610 | rc = -EAGAIN; |
1594 | return -ERESTARTSYS; | 1611 | else |
1612 | rc = -ERESTARTSYS; | ||
1613 | break; | ||
1595 | } | 1614 | } |
1596 | 1615 | ||
1597 | if ((rc = set_protocol(dev, &krnptsreq)) != 0) { | 1616 | if ((rc = set_protocol(dev, &krnptsreq)) != 0) { |
@@ -1604,7 +1623,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1604 | wake_up_interruptible(&dev->ioq); | 1623 | wake_up_interruptible(&dev->ioq); |
1605 | 1624 | ||
1606 | } | 1625 | } |
1607 | return rc; | 1626 | break; |
1608 | #ifdef PCMCIA_DEBUG | 1627 | #ifdef PCMCIA_DEBUG |
1609 | case CM_IOSDBGLVL: /* set debug log level */ | 1628 | case CM_IOSDBGLVL: /* set debug log level */ |
1610 | { | 1629 | { |
@@ -1612,18 +1631,20 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
1612 | 1631 | ||
1613 | old_pc_debug = pc_debug; | 1632 | old_pc_debug = pc_debug; |
1614 | if (copy_from_user(&pc_debug, argp, sizeof(int))) | 1633 | if (copy_from_user(&pc_debug, argp, sizeof(int))) |
1615 | return -EFAULT; | 1634 | rc = -EFAULT; |
1616 | 1635 | else if (old_pc_debug != pc_debug) | |
1617 | if (old_pc_debug != pc_debug) | ||
1618 | DEBUGP(0, dev, "Changed debug log level " | 1636 | DEBUGP(0, dev, "Changed debug log level " |
1619 | "to %i\n", pc_debug); | 1637 | "to %i\n", pc_debug); |
1620 | } | 1638 | } |
1621 | return rc; | 1639 | break; |
1622 | #endif | 1640 | #endif |
1623 | default: | 1641 | default: |
1624 | DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); | 1642 | DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); |
1625 | return -EINVAL; | 1643 | rc = -ENOTTY; |
1626 | } | 1644 | } |
1645 | out: | ||
1646 | unlock_kernel(); | ||
1647 | return rc; | ||
1627 | } | 1648 | } |
1628 | 1649 | ||
1629 | static int cmm_open(struct inode *inode, struct file *filp) | 1650 | static int cmm_open(struct inode *inode, struct file *filp) |
@@ -1631,16 +1652,22 @@ static int cmm_open(struct inode *inode, struct file *filp) | |||
1631 | struct cm4000_dev *dev; | 1652 | struct cm4000_dev *dev; |
1632 | struct pcmcia_device *link; | 1653 | struct pcmcia_device *link; |
1633 | int minor = iminor(inode); | 1654 | int minor = iminor(inode); |
1655 | int ret; | ||
1634 | 1656 | ||
1635 | if (minor >= CM4000_MAX_DEV) | 1657 | if (minor >= CM4000_MAX_DEV) |
1636 | return -ENODEV; | 1658 | return -ENODEV; |
1637 | 1659 | ||
1660 | lock_kernel(); | ||
1638 | link = dev_table[minor]; | 1661 | link = dev_table[minor]; |
1639 | if (link == NULL || !pcmcia_dev_present(link)) | 1662 | if (link == NULL || !pcmcia_dev_present(link)) { |
1640 | return -ENODEV; | 1663 | ret = -ENODEV; |
1664 | goto out; | ||
1665 | } | ||
1641 | 1666 | ||
1642 | if (link->open) | 1667 | if (link->open) { |
1643 | return -EBUSY; | 1668 | ret = -EBUSY; |
1669 | goto out; | ||
1670 | } | ||
1644 | 1671 | ||
1645 | dev = link->priv; | 1672 | dev = link->priv; |
1646 | filp->private_data = dev; | 1673 | filp->private_data = dev; |
@@ -1660,8 +1687,10 @@ static int cmm_open(struct inode *inode, struct file *filp) | |||
1660 | * vaild = block until valid (or card | 1687 | * vaild = block until valid (or card |
1661 | * inserted) | 1688 | * inserted) |
1662 | */ | 1689 | */ |
1663 | if (filp->f_flags & O_NONBLOCK) | 1690 | if (filp->f_flags & O_NONBLOCK) { |
1664 | return -EAGAIN; | 1691 | ret = -EAGAIN; |
1692 | goto out; | ||
1693 | } | ||
1665 | 1694 | ||
1666 | dev->mdelay = T_50MSEC; | 1695 | dev->mdelay = T_50MSEC; |
1667 | 1696 | ||
@@ -1671,7 +1700,10 @@ static int cmm_open(struct inode *inode, struct file *filp) | |||
1671 | link->open = 1; /* only one open per device */ | 1700 | link->open = 1; /* only one open per device */ |
1672 | 1701 | ||
1673 | DEBUGP(2, dev, "<- cmm_open\n"); | 1702 | DEBUGP(2, dev, "<- cmm_open\n"); |
1674 | return nonseekable_open(inode, filp); | 1703 | ret = nonseekable_open(inode, filp); |
1704 | out: | ||
1705 | unlock_kernel(); | ||
1706 | return ret; | ||
1675 | } | 1707 | } |
1676 | 1708 | ||
1677 | static int cmm_close(struct inode *inode, struct file *filp) | 1709 | static int cmm_close(struct inode *inode, struct file *filp) |
@@ -1897,7 +1929,7 @@ static const struct file_operations cm4000_fops = { | |||
1897 | .owner = THIS_MODULE, | 1929 | .owner = THIS_MODULE, |
1898 | .read = cmm_read, | 1930 | .read = cmm_read, |
1899 | .write = cmm_write, | 1931 | .write = cmm_write, |
1900 | .ioctl = cmm_ioctl, | 1932 | .unlocked_ioctl = cmm_ioctl, |
1901 | .open = cmm_open, | 1933 | .open = cmm_open, |
1902 | .release= cmm_close, | 1934 | .release= cmm_close, |
1903 | }; | 1935 | }; |