]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/ide/ide-gd-floppy.c
ide-floppy: factor out generic disk handling code to ide-gd-floppy.c
[linux-2.6-omap-h63xx.git] / drivers / ide / ide-gd-floppy.c
1 #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>
10
11 #include "ide-floppy.h"
12
13 #define IDEFLOPPY_VERSION "1.00"
14
15 /* module parameters */
16 static unsigned long debug_mask;
17 module_param(debug_mask, ulong, 0644);
18
19 static DEFINE_MUTEX(idefloppy_ref_mutex);
20
21 static void idefloppy_cleanup_obj(struct kref *);
22
23 static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
24 {
25         struct ide_floppy_obj *floppy = NULL;
26
27         mutex_lock(&idefloppy_ref_mutex);
28         floppy = ide_drv_g(disk, ide_floppy_obj);
29         if (floppy) {
30                 if (ide_device_get(floppy->drive))
31                         floppy = NULL;
32                 else
33                         kref_get(&floppy->kref);
34         }
35         mutex_unlock(&idefloppy_ref_mutex);
36         return floppy;
37 }
38
39 static void ide_floppy_put(struct ide_floppy_obj *floppy)
40 {
41         ide_drive_t *drive = floppy->drive;
42
43         mutex_lock(&idefloppy_ref_mutex);
44         kref_put(&floppy->kref, idefloppy_cleanup_obj);
45         ide_device_put(drive);
46         mutex_unlock(&idefloppy_ref_mutex);
47 }
48
49 sector_t ide_floppy_capacity(ide_drive_t *drive)
50 {
51         return drive->capacity64;
52 }
53
54 static void ide_floppy_remove(ide_drive_t *drive)
55 {
56         idefloppy_floppy_t *floppy = drive->driver_data;
57         struct gendisk *g = floppy->disk;
58
59         ide_proc_unregister_driver(drive, floppy->driver);
60
61         del_gendisk(g);
62
63         ide_floppy_put(floppy);
64 }
65
66 static void idefloppy_cleanup_obj(struct kref *kref)
67 {
68         struct ide_floppy_obj *floppy = to_ide_drv(kref, ide_floppy_obj);
69         ide_drive_t *drive = floppy->drive;
70         struct gendisk *g = floppy->disk;
71
72         drive->driver_data = NULL;
73         g->private_data = NULL;
74         put_disk(g);
75         kfree(floppy);
76 }
77
78 static int ide_floppy_probe(ide_drive_t *);
79
80 static ide_driver_t idefloppy_driver = {
81         .gen_driver = {
82                 .owner          = THIS_MODULE,
83                 .name           = "ide-floppy",
84                 .bus            = &ide_bus_type,
85         },
86         .probe                  = ide_floppy_probe,
87         .remove                 = ide_floppy_remove,
88         .version                = IDEFLOPPY_VERSION,
89         .do_request             = ide_floppy_do_request,
90         .end_request            = ide_floppy_end_request,
91         .error                  = __ide_error,
92 #ifdef CONFIG_IDE_PROC_FS
93         .proc                   = ide_floppy_proc,
94         .settings               = ide_floppy_settings,
95 #endif
96 };
97
98 static int idefloppy_open(struct inode *inode, struct file *filp)
99 {
100         struct gendisk *disk = inode->i_bdev->bd_disk;
101         struct ide_floppy_obj *floppy;
102         ide_drive_t *drive;
103         int ret = 0;
104
105         floppy = ide_floppy_get(disk);
106         if (!floppy)
107                 return -ENXIO;
108
109         drive = floppy->drive;
110
111         ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
112
113         floppy->openers++;
114
115         if (floppy->openers == 1) {
116                 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
117                 /* Just in case */
118
119                 if (ide_do_test_unit_ready(drive, disk))
120                         ide_do_start_stop(drive, disk, 1);
121
122                 ret = ide_floppy_get_capacity(drive);
123
124                 set_capacity(disk, ide_floppy_capacity(drive));
125
126                 if (ret && (filp->f_flags & O_NDELAY) == 0) {
127                     /*
128                      * Allow O_NDELAY to open a drive without a disk, or with an
129                      * unreadable disk, so that we can get the format capacity
130                      * of the drive or begin the format - Sam
131                      */
132                         ret = -EIO;
133                         goto out_put_floppy;
134                 }
135
136                 if ((drive->dev_flags & IDE_DFLAG_WP) && (filp->f_mode & 2)) {
137                         ret = -EROFS;
138                         goto out_put_floppy;
139                 }
140
141                 ide_set_media_lock(drive, disk, 1);
142                 drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
143                 check_disk_change(inode->i_bdev);
144         } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
145                 ret = -EBUSY;
146                 goto out_put_floppy;
147         }
148         return 0;
149
150 out_put_floppy:
151         floppy->openers--;
152         ide_floppy_put(floppy);
153         return ret;
154 }
155
156 static int idefloppy_release(struct inode *inode, struct file *filp)
157 {
158         struct gendisk *disk = inode->i_bdev->bd_disk;
159         struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
160         ide_drive_t *drive = floppy->drive;
161
162         ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
163
164         if (floppy->openers == 1) {
165                 ide_set_media_lock(drive, disk, 0);
166                 drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
167         }
168
169         floppy->openers--;
170
171         ide_floppy_put(floppy);
172
173         return 0;
174 }
175
176 static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
177 {
178         struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
179                                                      ide_floppy_obj);
180         ide_drive_t *drive = floppy->drive;
181
182         geo->heads = drive->bios_head;
183         geo->sectors = drive->bios_sect;
184         geo->cylinders = (u16)drive->bios_cyl; /* truncate */
185         return 0;
186 }
187
188 static int idefloppy_media_changed(struct gendisk *disk)
189 {
190         struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
191         ide_drive_t *drive = floppy->drive;
192         int ret;
193
194         /* do not scan partitions twice if this is a removable device */
195         if (drive->dev_flags & IDE_DFLAG_ATTACH) {
196                 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
197                 return 0;
198         }
199
200         ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
201         drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
202
203         return ret;
204 }
205
206 static int idefloppy_revalidate_disk(struct gendisk *disk)
207 {
208         struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
209         set_capacity(disk, ide_floppy_capacity(floppy->drive));
210         return 0;
211 }
212
213 static struct block_device_operations idefloppy_ops = {
214         .owner                  = THIS_MODULE,
215         .open                   = idefloppy_open,
216         .release                = idefloppy_release,
217         .ioctl                  = ide_floppy_ioctl,
218         .getgeo                 = idefloppy_getgeo,
219         .media_changed          = idefloppy_media_changed,
220         .revalidate_disk        = idefloppy_revalidate_disk
221 };
222
223 static int ide_floppy_probe(ide_drive_t *drive)
224 {
225         idefloppy_floppy_t *floppy;
226         struct gendisk *g;
227
228         if (!strstr("ide-floppy", drive->driver_req))
229                 goto failed;
230
231         if (drive->media != ide_floppy)
232                 goto failed;
233
234         if (!ide_check_atapi_device(drive, DRV_NAME)) {
235                 printk(KERN_ERR PFX "%s: not supported by this version of "
236                        DRV_NAME "\n", drive->name);
237                 goto failed;
238         }
239         floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
240         if (!floppy) {
241                 printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n",
242                        drive->name);
243                 goto failed;
244         }
245
246         g = alloc_disk_node(1 << PARTN_BITS, hwif_to_node(drive->hwif));
247         if (!g)
248                 goto out_free_floppy;
249
250         ide_init_disk(g, drive);
251
252         kref_init(&floppy->kref);
253
254         floppy->drive = drive;
255         floppy->driver = &idefloppy_driver;
256         floppy->disk = g;
257
258         g->private_data = &floppy->driver;
259
260         drive->driver_data = floppy;
261
262         drive->debug_mask = debug_mask;
263
264         ide_floppy_setup(drive);
265
266         set_capacity(g, ide_floppy_capacity(drive));
267
268         g->minors = 1 << PARTN_BITS;
269         g->driverfs_dev = &drive->gendev;
270         if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
271                 g->flags = GENHD_FL_REMOVABLE;
272         g->fops = &idefloppy_ops;
273         add_disk(g);
274         return 0;
275
276 out_free_floppy:
277         kfree(floppy);
278 failed:
279         return -ENODEV;
280 }
281
282 static int __init idefloppy_init(void)
283 {
284         printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n");
285         return driver_register(&idefloppy_driver.gen_driver);
286 }
287
288 static void __exit idefloppy_exit(void)
289 {
290         driver_unregister(&idefloppy_driver.gen_driver);
291 }
292
293 MODULE_ALIAS("ide:*m-floppy*");
294 MODULE_ALIAS("ide-floppy");
295 module_init(idefloppy_init);
296 module_exit(idefloppy_exit);
297 MODULE_LICENSE("GPL");
298 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");