Commit f74c91413ec6140ee0553180c5f56fdd27c22a2e
1 parent
50672e5d74
Exists in
master
and in
20 other branches
ide: add warm-plug support for IDE devices (take 2)
* Add 'struct class ide_port_class' ('ide_port' class) and a 'struct device *portdev' ('ide_port' class device) in ide_hwif_t. * Register 'ide_port' class in ide_init() and unregister it in cleanup_module(). * Create ->portdev in ide_register_port () and unregister it in ide_unregister(). * Add "delete_devices" class device attribute for unregistering IDE devices on a port and "scan" one for probing+registering IDE devices on a port. * Add ide_sysfs_register_port() helper for registering "delete_devices" and "scan" attributes with ->portdev. Call it in ide_device_add_all(). * Document IDE warm-plug support in Documentation/ide/warm-plug-howto.txt. v2: * Convert patch from using 'struct class_device' to use 'struct device'. (thanks to Kay Sievers for doing it) Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Showing 4 changed files with 110 additions and 3 deletions Side-by-side Diff
Documentation/ide/warm-plug-howto.txt
drivers/ide/ide-probe.c
... | ... | @@ -623,7 +623,7 @@ |
623 | 623 | complete(&hwif->gendev_rel_comp); |
624 | 624 | } |
625 | 625 | |
626 | -static void ide_register_port(ide_hwif_t *hwif) | |
626 | +static int ide_register_port(ide_hwif_t *hwif) | |
627 | 627 | { |
628 | 628 | int ret; |
629 | 629 | |
630 | 630 | |
... | ... | @@ -639,9 +639,23 @@ |
639 | 639 | } |
640 | 640 | hwif->gendev.release = hwif_release_dev; |
641 | 641 | ret = device_register(&hwif->gendev); |
642 | - if (ret < 0) | |
642 | + if (ret < 0) { | |
643 | 643 | printk(KERN_WARNING "IDE: %s: device_register error: %d\n", |
644 | 644 | __FUNCTION__, ret); |
645 | + goto out; | |
646 | + } | |
647 | + | |
648 | + get_device(&hwif->gendev); | |
649 | + | |
650 | + hwif->portdev = device_create(ide_port_class, &hwif->gendev, | |
651 | + MKDEV(0, 0), hwif->name); | |
652 | + if (IS_ERR(hwif->portdev)) { | |
653 | + ret = PTR_ERR(hwif->portdev); | |
654 | + device_unregister(&hwif->gendev); | |
655 | + } | |
656 | + dev_set_drvdata(hwif->portdev, hwif); | |
657 | +out: | |
658 | + return ret; | |
645 | 659 | } |
646 | 660 | |
647 | 661 | /** |
... | ... | @@ -1378,6 +1392,58 @@ |
1378 | 1392 | } |
1379 | 1393 | } |
1380 | 1394 | |
1395 | +static ssize_t store_delete_devices(struct device *portdev, | |
1396 | + struct device_attribute *attr, | |
1397 | + const char *buf, size_t n) | |
1398 | +{ | |
1399 | + ide_hwif_t *hwif = dev_get_drvdata(portdev); | |
1400 | + | |
1401 | + if (strncmp(buf, "1", n)) | |
1402 | + return -EINVAL; | |
1403 | + | |
1404 | + ide_port_unregister_devices(hwif); | |
1405 | + | |
1406 | + return n; | |
1407 | +}; | |
1408 | + | |
1409 | +static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices); | |
1410 | + | |
1411 | +static ssize_t store_scan(struct device *portdev, | |
1412 | + struct device_attribute *attr, | |
1413 | + const char *buf, size_t n) | |
1414 | +{ | |
1415 | + ide_hwif_t *hwif = dev_get_drvdata(portdev); | |
1416 | + | |
1417 | + if (strncmp(buf, "1", n)) | |
1418 | + return -EINVAL; | |
1419 | + | |
1420 | + ide_port_unregister_devices(hwif); | |
1421 | + ide_port_scan(hwif); | |
1422 | + | |
1423 | + return n; | |
1424 | +}; | |
1425 | + | |
1426 | +static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); | |
1427 | + | |
1428 | +static struct device_attribute *ide_port_attrs[] = { | |
1429 | + &dev_attr_delete_devices, | |
1430 | + &dev_attr_scan, | |
1431 | + NULL | |
1432 | +}; | |
1433 | + | |
1434 | +static int ide_sysfs_register_port(ide_hwif_t *hwif) | |
1435 | +{ | |
1436 | + int i, rc; | |
1437 | + | |
1438 | + for (i = 0; ide_port_attrs[i]; i++) { | |
1439 | + rc = device_create_file(hwif->portdev, ide_port_attrs[i]); | |
1440 | + if (rc) | |
1441 | + break; | |
1442 | + } | |
1443 | + | |
1444 | + return rc; | |
1445 | +} | |
1446 | + | |
1381 | 1447 | int ide_device_add_all(u8 *idx, const struct ide_port_info *d) |
1382 | 1448 | { |
1383 | 1449 | ide_hwif_t *hwif, *mate = NULL; |
... | ... | @@ -1474,6 +1540,7 @@ |
1474 | 1540 | hwif = &ide_hwifs[idx[i]]; |
1475 | 1541 | |
1476 | 1542 | if (hwif->present) { |
1543 | + ide_sysfs_register_port(hwif); | |
1477 | 1544 | ide_proc_register_port(hwif); |
1478 | 1545 | ide_proc_port_register_devices(hwif); |
1479 | 1546 | } |
drivers/ide/ide.c
... | ... | @@ -78,6 +78,8 @@ |
78 | 78 | /* default maximum number of failures */ |
79 | 79 | #define IDE_DEFAULT_MAX_FAILURES 1 |
80 | 80 | |
81 | +struct class *ide_port_class; | |
82 | + | |
81 | 83 | static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, |
82 | 84 | IDE2_MAJOR, IDE3_MAJOR, |
83 | 85 | IDE4_MAJOR, IDE5_MAJOR, |
... | ... | @@ -591,6 +593,7 @@ |
591 | 593 | |
592 | 594 | ide_remove_port_from_hwgroup(hwif); |
593 | 595 | |
596 | + device_unregister(hwif->portdev); | |
594 | 597 | device_unregister(&hwif->gendev); |
595 | 598 | wait_for_completion(&hwif->gendev_rel_comp); |
596 | 599 | |
... | ... | @@ -1590,6 +1593,13 @@ |
1590 | 1593 | |
1591 | 1594 | EXPORT_SYMBOL_GPL(ide_bus_type); |
1592 | 1595 | |
1596 | +static void ide_port_class_release(struct device *portdev) | |
1597 | +{ | |
1598 | + ide_hwif_t *hwif = dev_get_drvdata(portdev); | |
1599 | + | |
1600 | + put_device(&hwif->gendev); | |
1601 | +} | |
1602 | + | |
1593 | 1603 | /* |
1594 | 1604 | * This is gets invoked once during initialization, to set *everything* up |
1595 | 1605 | */ |
1596 | 1606 | |
... | ... | @@ -1610,11 +1620,23 @@ |
1610 | 1620 | return ret; |
1611 | 1621 | } |
1612 | 1622 | |
1623 | + ide_port_class = class_create(THIS_MODULE, "ide_port"); | |
1624 | + if (IS_ERR(ide_port_class)) { | |
1625 | + ret = PTR_ERR(ide_port_class); | |
1626 | + goto out_port_class; | |
1627 | + } | |
1628 | + ide_port_class->dev_release = ide_port_class_release; | |
1629 | + | |
1613 | 1630 | init_ide_data(); |
1614 | 1631 | |
1615 | 1632 | proc_ide_create(); |
1616 | 1633 | |
1617 | 1634 | return 0; |
1635 | + | |
1636 | +out_port_class: | |
1637 | + bus_unregister(&ide_bus_type); | |
1638 | + | |
1639 | + return ret; | |
1618 | 1640 | } |
1619 | 1641 | |
1620 | 1642 | #ifdef MODULE |
... | ... | @@ -1650,6 +1672,8 @@ |
1650 | 1672 | ide_unregister(index, 0, 0); |
1651 | 1673 | |
1652 | 1674 | proc_ide_destroy(); |
1675 | + | |
1676 | + class_destroy(ide_port_class); | |
1653 | 1677 | |
1654 | 1678 | bus_unregister(&ide_bus_type); |
1655 | 1679 | } |
include/linux/ide.h
... | ... | @@ -579,7 +579,9 @@ |
579 | 579 | unsigned mmio : 1; /* host uses MMIO */ |
580 | 580 | unsigned straight8 : 1; /* Alan's straight 8 check */ |
581 | 581 | |
582 | - struct device gendev; | |
582 | + struct device gendev; | |
583 | + struct device *portdev; | |
584 | + | |
583 | 585 | struct completion gendev_rel_comp; /* To deal with device release() */ |
584 | 586 | |
585 | 587 | void *hwif_data; /* extra hwif data */ |
... | ... | @@ -1275,6 +1277,7 @@ |
1275 | 1277 | #define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0) |
1276 | 1278 | |
1277 | 1279 | extern struct bus_type ide_bus_type; |
1280 | +extern struct class *ide_port_class; | |
1278 | 1281 | |
1279 | 1282 | /* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ |
1280 | 1283 | #define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) |