blob: c32d83996ae1dea17464b5ae9a772c6d0aec06c4 [file] [log] [blame]
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +02001#include <linux/module.h>
2#include <linux/types.h>
3#include <linux/string.h>
4#include <linux/kernel.h>
5#include <linux/errno.h>
6#include <linux/genhd.h>
7#include <linux/mutex.h>
8#include <linux/ide.h>
9#include <linux/hdreg.h>
Bruno Prémontb0aedb02009-04-22 20:33:41 +020010#include <linux/dmi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020012
13#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
14#define IDE_DISK_MINORS (1 << PARTN_BITS)
15#else
16#define IDE_DISK_MINORS 0
17#endif
18
19#include "ide-disk.h"
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020020#include "ide-floppy.h"
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020021
22#define IDE_GD_VERSION "1.18"
23
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020024/* module parameters */
25static unsigned long debug_mask;
26module_param(debug_mask, ulong, 0644);
27
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020028static DEFINE_MUTEX(ide_disk_ref_mutex);
29
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010030static void ide_disk_release(struct device *);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020031
32static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
33{
34 struct ide_disk_obj *idkp = NULL;
35
36 mutex_lock(&ide_disk_ref_mutex);
37 idkp = ide_drv_g(disk, ide_disk_obj);
38 if (idkp) {
39 if (ide_device_get(idkp->drive))
40 idkp = NULL;
41 else
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010042 get_device(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020043 }
44 mutex_unlock(&ide_disk_ref_mutex);
45 return idkp;
46}
47
48static void ide_disk_put(struct ide_disk_obj *idkp)
49{
50 ide_drive_t *drive = idkp->drive;
51
52 mutex_lock(&ide_disk_ref_mutex);
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010053 put_device(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020054 ide_device_put(drive);
55 mutex_unlock(&ide_disk_ref_mutex);
56}
57
58sector_t ide_gd_capacity(ide_drive_t *drive)
59{
60 return drive->capacity64;
61}
62
63static int ide_gd_probe(ide_drive_t *);
64
65static void ide_gd_remove(ide_drive_t *drive)
66{
67 struct ide_disk_obj *idkp = drive->driver_data;
68 struct gendisk *g = idkp->disk;
69
70 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010071 device_del(&idkp->dev);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020072 del_gendisk(g);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020073 drive->disk_ops->flush(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020074
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010075 mutex_lock(&ide_disk_ref_mutex);
76 put_device(&idkp->dev);
77 mutex_unlock(&ide_disk_ref_mutex);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020078}
79
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010080static void ide_disk_release(struct device *dev)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020081{
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +010082 struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020083 ide_drive_t *drive = idkp->drive;
84 struct gendisk *g = idkp->disk;
85
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +020086 drive->disk_ops = NULL;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +020087 drive->driver_data = NULL;
88 g->private_data = NULL;
89 put_disk(g);
90 kfree(idkp);
91}
92
93/*
94 * On HPA drives the capacity needs to be
95 * reinitilized on resume otherwise the disk
96 * can not be used and a hard reset is required
97 */
98static void ide_gd_resume(ide_drive_t *drive)
99{
100 if (ata_id_hpa_enabled(drive->id))
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200101 (void)drive->disk_ops->get_capacity(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200102}
103
Bruno Prémontb0aedb02009-04-22 20:33:41 +0200104static const struct dmi_system_id ide_coldreboot_table[] = {
105 {
106 /* Acer TravelMate 66x cuts power during reboot */
107 .ident = "Acer TravelMate 660",
108 .matches = {
109 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
110 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
111 },
112 },
113
114 { } /* terminate list */
115};
116
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200117static void ide_gd_shutdown(ide_drive_t *drive)
118{
119#ifdef CONFIG_ALPHA
120 /* On Alpha, halt(8) doesn't actually turn the machine off,
121 it puts you into the sort of firmware monitor. Typically,
122 it's used to boot another kernel image, so it's not much
123 different from reboot(8). Therefore, we don't need to
124 spin down the disk in this case, especially since Alpha
125 firmware doesn't handle disks in standby mode properly.
126 On the other hand, it's reasonably safe to turn the power
127 off when the shutdown process reaches the firmware prompt,
128 as the firmware initialization takes rather long time -
129 at least 10 seconds, which should be sufficient for
130 the disk to expire its write cache. */
131 if (system_state != SYSTEM_POWER_OFF) {
132#else
Bruno Prémontb0aedb02009-04-22 20:33:41 +0200133 if (system_state == SYSTEM_RESTART &&
134 !dmi_check_system(ide_coldreboot_table)) {
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200135#endif
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200136 drive->disk_ops->flush(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200137 return;
138 }
139
140 printk(KERN_INFO "Shutdown: %s\n", drive->name);
141
142 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
143}
144
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200145#ifdef CONFIG_IDE_PROC_FS
146static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
147{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200148 return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200149}
150
151static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
152{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200153 return (drive->media == ide_disk) ? ide_disk_settings
154 : ide_floppy_settings;
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200155}
156#endif
157
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200158static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
159 struct request *rq, sector_t sector)
160{
161 return drive->disk_ops->do_request(drive, rq, sector);
162}
163
Bartlomiej Zolnierkiewicz7f3c8682009-01-06 17:20:53 +0100164static struct ide_driver ide_gd_driver = {
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200165 .gen_driver = {
166 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200167 .name = "ide-gd",
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200168 .bus = &ide_bus_type,
169 },
170 .probe = ide_gd_probe,
171 .remove = ide_gd_remove,
172 .resume = ide_gd_resume,
173 .shutdown = ide_gd_shutdown,
174 .version = IDE_GD_VERSION,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200175 .do_request = ide_gd_do_request,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200176#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz79cb3802008-10-17 18:09:13 +0200177 .proc_entries = ide_disk_proc_entries,
178 .proc_devsets = ide_disk_proc_devsets,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200179#endif
180};
181
Al Virob2f21e02008-10-16 10:34:00 -0400182static int ide_gd_open(struct block_device *bdev, fmode_t mode)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200183{
Al Virob2f21e02008-10-16 10:34:00 -0400184 struct gendisk *disk = bdev->bd_disk;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200185 struct ide_disk_obj *idkp;
186 ide_drive_t *drive;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200187 int ret = 0;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200188
189 idkp = ide_disk_get(disk);
190 if (idkp == NULL)
191 return -ENXIO;
192
193 drive = idkp->drive;
194
Borislav Petkov088b1b82009-01-02 13:34:47 +0100195 ide_debug_log(IDE_DBG_FUNC, "enter");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200196
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200197 idkp->openers++;
198
199 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200200 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
201 /* Just in case */
202
203 ret = drive->disk_ops->init_media(drive, disk);
204
205 /*
206 * Allow O_NDELAY to open a drive without a disk, or with an
207 * unreadable disk, so that we can get the format capacity
208 * of the drive or begin the format - Sam
209 */
Al Virob2f21e02008-10-16 10:34:00 -0400210 if (ret && (mode & FMODE_NDELAY) == 0) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200211 ret = -EIO;
212 goto out_put_idkp;
213 }
214
Al Virob2f21e02008-10-16 10:34:00 -0400215 if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200216 ret = -EROFS;
217 goto out_put_idkp;
218 }
219
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200220 /*
221 * Ignore the return code from door_lock,
222 * since the open() has already succeeded,
223 * and the door_lock is irrelevant at this point.
224 */
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200225 drive->disk_ops->set_doorlock(drive, disk, 1);
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200226 drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
Al Virob2f21e02008-10-16 10:34:00 -0400227 check_disk_change(bdev);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200228 } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
229 ret = -EBUSY;
230 goto out_put_idkp;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200231 }
232 return 0;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200233
234out_put_idkp:
235 idkp->openers--;
236 ide_disk_put(idkp);
237 return ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200238}
239
Al Virob2f21e02008-10-16 10:34:00 -0400240static int ide_gd_release(struct gendisk *disk, fmode_t mode)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200241{
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200242 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
243 ide_drive_t *drive = idkp->drive;
244
Borislav Petkov088b1b82009-01-02 13:34:47 +0100245 ide_debug_log(IDE_DBG_FUNC, "enter");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200246
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200247 if (idkp->openers == 1)
248 drive->disk_ops->flush(drive);
249
250 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
251 drive->disk_ops->set_doorlock(drive, disk, 0);
252 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
253 }
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200254
255 idkp->openers--;
256
257 ide_disk_put(idkp);
258
259 return 0;
260}
261
262static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
263{
264 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
265 ide_drive_t *drive = idkp->drive;
266
267 geo->heads = drive->bios_head;
268 geo->sectors = drive->bios_sect;
269 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
270 return 0;
271}
272
273static int ide_gd_media_changed(struct gendisk *disk)
274{
275 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
276 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200277 int ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200278
279 /* do not scan partitions twice if this is a removable device */
280 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
281 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
282 return 0;
283 }
284
Bartlomiej Zolnierkiewiczcedd1202008-10-17 18:09:12 +0200285 ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
286 drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
287
288 return ret;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200289}
290
Bartlomiej Zolnierkiewicze957b602009-06-07 13:52:52 +0200291static unsigned long long ide_gd_set_capacity(struct gendisk *disk,
292 unsigned long long capacity)
293{
294 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
295 ide_drive_t *drive = idkp->drive;
296 const struct ide_disk_ops *disk_ops = drive->disk_ops;
297
298 if (disk_ops->set_capacity)
299 return disk_ops->set_capacity(drive, capacity);
300
301 return drive->capacity64;
302}
303
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200304static int ide_gd_revalidate_disk(struct gendisk *disk)
305{
306 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
Borislav Petkov52ebb432008-11-02 21:40:10 +0100307 ide_drive_t *drive = idkp->drive;
308
309 if (ide_gd_media_changed(disk))
310 drive->disk_ops->get_capacity(drive);
311
312 set_capacity(disk, ide_gd_capacity(drive));
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200313 return 0;
314}
315
Al Virob2f21e02008-10-16 10:34:00 -0400316static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200317 unsigned int cmd, unsigned long arg)
318{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200319 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
320 ide_drive_t *drive = idkp->drive;
321
Al Virob2f21e02008-10-16 10:34:00 -0400322 return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200323}
324
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700325static const struct block_device_operations ide_gd_ops = {
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200326 .owner = THIS_MODULE,
Al Virob2f21e02008-10-16 10:34:00 -0400327 .open = ide_gd_open,
328 .release = ide_gd_release,
329 .locked_ioctl = ide_gd_ioctl,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200330 .getgeo = ide_gd_getgeo,
331 .media_changed = ide_gd_media_changed,
Bartlomiej Zolnierkiewicze957b602009-06-07 13:52:52 +0200332 .set_capacity = ide_gd_set_capacity,
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200333 .revalidate_disk = ide_gd_revalidate_disk
334};
335
336static int ide_gd_probe(ide_drive_t *drive)
337{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200338 const struct ide_disk_ops *disk_ops = NULL;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200339 struct ide_disk_obj *idkp;
340 struct gendisk *g;
341
342 /* strstr("foo", "") is non-NULL */
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200343 if (!strstr("ide-gd", drive->driver_req))
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200344 goto failed;
345
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200346#ifdef CONFIG_IDE_GD_ATA
347 if (drive->media == ide_disk)
348 disk_ops = &ide_ata_disk_ops;
349#endif
350#ifdef CONFIG_IDE_GD_ATAPI
351 if (drive->media == ide_floppy)
352 disk_ops = &ide_atapi_disk_ops;
353#endif
354 if (disk_ops == NULL)
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200355 goto failed;
356
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200357 if (disk_ops->check(drive, DRV_NAME) == 0) {
358 printk(KERN_ERR PFX "%s: not supported by this driver\n",
359 drive->name);
360 goto failed;
361 }
362
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200363 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200364 if (!idkp) {
365 printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
366 drive->name);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200367 goto failed;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200368 }
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200369
370 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
371 if (!g)
372 goto out_free_idkp;
373
374 ide_init_disk(g, drive);
375
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +0100376 idkp->dev.parent = &drive->gendev;
377 idkp->dev.release = ide_disk_release;
378 dev_set_name(&idkp->dev, dev_name(&drive->gendev));
379
380 if (device_register(&idkp->dev))
381 goto out_free_disk;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200382
383 idkp->drive = drive;
384 idkp->driver = &ide_gd_driver;
385 idkp->disk = g;
386
387 g->private_data = &idkp->driver;
388
389 drive->driver_data = idkp;
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200390 drive->debug_mask = debug_mask;
391 drive->disk_ops = disk_ops;
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200392
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200393 disk_ops->setup(drive);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200394
395 set_capacity(g, ide_gd_capacity(drive));
396
397 g->minors = IDE_DISK_MINORS;
398 g->driverfs_dev = &drive->gendev;
399 g->flags |= GENHD_FL_EXT_DEVT;
400 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
401 g->flags = GENHD_FL_REMOVABLE;
402 g->fops = &ide_gd_ops;
403 add_disk(g);
404 return 0;
405
Bartlomiej Zolnierkiewicz8fed4362009-02-25 20:28:24 +0100406out_free_disk:
407 put_disk(g);
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200408out_free_idkp:
409 kfree(idkp);
410failed:
411 return -ENODEV;
412}
413
414static int __init ide_gd_init(void)
415{
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200416 printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200417 return driver_register(&ide_gd_driver.gen_driver);
418}
419
420static void __exit ide_gd_exit(void)
421{
422 driver_unregister(&ide_gd_driver.gen_driver);
423}
424
425MODULE_ALIAS("ide:*m-disk*");
426MODULE_ALIAS("ide-disk");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200427MODULE_ALIAS("ide:*m-floppy*");
428MODULE_ALIAS("ide-floppy");
Bartlomiej Zolnierkiewicz5fef0e52008-10-17 18:09:12 +0200429module_init(ide_gd_init);
430module_exit(ide_gd_exit);
431MODULE_LICENSE("GPL");
Bartlomiej Zolnierkiewicz806f80a2008-10-17 18:09:14 +0200432MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");