forked from mirrors/linux
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									50672e5d74
								
							
						
					
					
						commit
						f74c91413e
					
				
					 4 changed files with 110 additions and 3 deletions
				
			
		
							
								
								
									
										13
									
								
								Documentation/ide/warm-plug-howto.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Documentation/ide/warm-plug-howto.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
 | 
			
		||||
IDE warm-plug HOWTO
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
To warm-plug devices on a port 'idex':
 | 
			
		||||
 | 
			
		||||
# echo -n "1" > /sys/class/ide_port/idex/delete_devices
 | 
			
		||||
 | 
			
		||||
unplug old device(s) and plug new device(s)
 | 
			
		||||
 | 
			
		||||
# echo -n "1" > /sys/class/ide_port/idex/scan
 | 
			
		||||
 | 
			
		||||
done
 | 
			
		||||
| 
						 | 
				
			
			@ -623,7 +623,7 @@ static void hwif_release_dev (struct device *dev)
 | 
			
		|||
	complete(&hwif->gendev_rel_comp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ide_register_port(ide_hwif_t *hwif)
 | 
			
		||||
static int ide_register_port(ide_hwif_t *hwif)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -639,9 +639,23 @@ static void ide_register_port(ide_hwif_t *hwif)
 | 
			
		|||
	}
 | 
			
		||||
	hwif->gendev.release = hwif_release_dev;
 | 
			
		||||
	ret = device_register(&hwif->gendev);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
 | 
			
		||||
			__FUNCTION__, ret);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get_device(&hwif->gendev);
 | 
			
		||||
 | 
			
		||||
	hwif->portdev = device_create(ide_port_class, &hwif->gendev,
 | 
			
		||||
				      MKDEV(0, 0), hwif->name);
 | 
			
		||||
	if (IS_ERR(hwif->portdev)) {
 | 
			
		||||
		ret = PTR_ERR(hwif->portdev);
 | 
			
		||||
		device_unregister(&hwif->gendev);
 | 
			
		||||
	}
 | 
			
		||||
	dev_set_drvdata(hwif->portdev, hwif);
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -1378,6 +1392,58 @@ static void ide_port_cable_detect(ide_hwif_t *hwif)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t store_delete_devices(struct device *portdev,
 | 
			
		||||
				    struct device_attribute *attr,
 | 
			
		||||
				    const char *buf, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	ide_hwif_t *hwif = dev_get_drvdata(portdev);
 | 
			
		||||
 | 
			
		||||
	if (strncmp(buf, "1", n))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	ide_port_unregister_devices(hwif);
 | 
			
		||||
 | 
			
		||||
	return n;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
 | 
			
		||||
 | 
			
		||||
static ssize_t store_scan(struct device *portdev,
 | 
			
		||||
			  struct device_attribute *attr,
 | 
			
		||||
			  const char *buf, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	ide_hwif_t *hwif = dev_get_drvdata(portdev);
 | 
			
		||||
 | 
			
		||||
	if (strncmp(buf, "1", n))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	ide_port_unregister_devices(hwif);
 | 
			
		||||
	ide_port_scan(hwif);
 | 
			
		||||
 | 
			
		||||
	return n;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
 | 
			
		||||
 | 
			
		||||
static struct device_attribute *ide_port_attrs[] = {
 | 
			
		||||
	&dev_attr_delete_devices,
 | 
			
		||||
	&dev_attr_scan,
 | 
			
		||||
	NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ide_sysfs_register_port(ide_hwif_t *hwif)
 | 
			
		||||
{
 | 
			
		||||
	int i, rc;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; ide_port_attrs[i]; i++) {
 | 
			
		||||
		rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
 | 
			
		||||
{
 | 
			
		||||
	ide_hwif_t *hwif, *mate = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1474,6 +1540,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
 | 
			
		|||
		hwif = &ide_hwifs[idx[i]];
 | 
			
		||||
 | 
			
		||||
		if (hwif->present) {
 | 
			
		||||
			ide_sysfs_register_port(hwif);
 | 
			
		||||
			ide_proc_register_port(hwif);
 | 
			
		||||
			ide_proc_port_register_devices(hwif);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,8 @@
 | 
			
		|||
/* default maximum number of failures */
 | 
			
		||||
#define IDE_DEFAULT_MAX_FAILURES 	1
 | 
			
		||||
 | 
			
		||||
struct class *ide_port_class;
 | 
			
		||||
 | 
			
		||||
static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 | 
			
		||||
					IDE2_MAJOR, IDE3_MAJOR,
 | 
			
		||||
					IDE4_MAJOR, IDE5_MAJOR,
 | 
			
		||||
| 
						 | 
				
			
			@ -591,6 +593,7 @@ void ide_unregister(unsigned int index, int init_default, int restore)
 | 
			
		|||
 | 
			
		||||
	ide_remove_port_from_hwgroup(hwif);
 | 
			
		||||
 | 
			
		||||
	device_unregister(hwif->portdev);
 | 
			
		||||
	device_unregister(&hwif->gendev);
 | 
			
		||||
	wait_for_completion(&hwif->gendev_rel_comp);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1590,6 +1593,13 @@ struct bus_type ide_bus_type = {
 | 
			
		|||
 | 
			
		||||
EXPORT_SYMBOL_GPL(ide_bus_type);
 | 
			
		||||
 | 
			
		||||
static void ide_port_class_release(struct device *portdev)
 | 
			
		||||
{
 | 
			
		||||
	ide_hwif_t *hwif = dev_get_drvdata(portdev);
 | 
			
		||||
 | 
			
		||||
	put_device(&hwif->gendev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is gets invoked once during initialization, to set *everything* up
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1610,11 +1620,23 @@ static int __init ide_init(void)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ide_port_class = class_create(THIS_MODULE, "ide_port");
 | 
			
		||||
	if (IS_ERR(ide_port_class)) {
 | 
			
		||||
		ret = PTR_ERR(ide_port_class);
 | 
			
		||||
		goto out_port_class;
 | 
			
		||||
	}
 | 
			
		||||
	ide_port_class->dev_release = ide_port_class_release;
 | 
			
		||||
 | 
			
		||||
	init_ide_data();
 | 
			
		||||
 | 
			
		||||
	proc_ide_create();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_port_class:
 | 
			
		||||
	bus_unregister(&ide_bus_type);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef MODULE
 | 
			
		||||
| 
						 | 
				
			
			@ -1651,6 +1673,8 @@ void __exit cleanup_module (void)
 | 
			
		|||
 | 
			
		||||
	proc_ide_destroy();
 | 
			
		||||
 | 
			
		||||
	class_destroy(ide_port_class);
 | 
			
		||||
 | 
			
		||||
	bus_unregister(&ide_bus_type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -579,7 +579,9 @@ typedef struct hwif_s {
 | 
			
		|||
	unsigned	mmio       : 1; /* host uses MMIO */
 | 
			
		||||
	unsigned	straight8  : 1;	/* Alan's straight 8 check */
 | 
			
		||||
 | 
			
		||||
	struct device	gendev;
 | 
			
		||||
	struct device		gendev;
 | 
			
		||||
	struct device		*portdev;
 | 
			
		||||
 | 
			
		||||
	struct completion gendev_rel_comp; /* To deal with device release() */
 | 
			
		||||
 | 
			
		||||
	void		*hwif_data;	/* extra hwif data */
 | 
			
		||||
| 
						 | 
				
			
			@ -1275,6 +1277,7 @@ extern struct mutex ide_cfg_mtx;
 | 
			
		|||
#define local_irq_set(flags)	do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0)
 | 
			
		||||
 | 
			
		||||
extern struct bus_type ide_bus_type;
 | 
			
		||||
extern struct class *ide_port_class;
 | 
			
		||||
 | 
			
		||||
/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
 | 
			
		||||
#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue