OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [cdrom/] [cdrom.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*-
2
   Copyright (c) 1996 David van Leeuwen.
3
 
4
   The routines in the file should provide an interface between
5
   software accessing cdroms and the various drivers that implement
6
   specific hardware devices.
7
 
8
 */
9
 
10
#include <linux/module.h>
11
#include <linux/fs.h>
12
#include <linux/major.h>
13
#include <linux/types.h>
14
#include <linux/errno.h>
15
#include <linux/kernel.h>
16
#include <linux/mm.h>
17
#include <asm/fcntl.h>
18
 
19
#include <linux/cdrom.h>
20
#include <linux/ucdrom.h>
21
 
22
#define FM_WRITE        0x2                 /* file mode write bit */
23
 
24
#define VERSION "$Id: cdrom.c,v 1.1.1.1 2001-09-10 07:44:13 simons Exp $"
25
 
26
/* Not-exported routines. */
27
int cdrom_open(struct inode *ip, struct file *fp);
28
void cdrom_release(struct inode *ip, struct file *fp);
29
int cdrom_ioctl(struct inode *ip, struct file *fp,
30
                                unsigned int cmd, unsigned long arg);
31
int cdrom_media_changed(kdev_t dev);
32
 
33
struct file_operations cdrom_fops =
34
{
35
        NULL,                           /* lseek */
36
        block_read,                     /* read - general block-dev read */
37
        block_write,                    /* write - general block-dev write */
38
        NULL,                           /* readdir */
39
        NULL,                           /* select */
40
        cdrom_ioctl,                    /* ioctl */
41
        NULL,                           /* mmap */
42
        cdrom_open,                     /* open */
43
        cdrom_release,                  /* release */
44
        NULL,                           /* fsync */
45
        NULL,                           /* fasync */
46
        cdrom_media_changed,            /* media_change */
47
        NULL                            /* revalidate */
48
};
49
 
50
static struct cdrom_device_ops *cdromdevs[MAX_BLKDEV] = {
51
        NULL,
52
};
53
 
54
/* This macro makes sure we don't have to check on cdrom_device_ops
55
 * existence in the run-time routines below. Change_capability is a
56
 * hack to have the capability flags defined const, while we can still
57
 * change it here without gcc complaining at every line.
58
 */
59
 
60
#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
61
 
62
/* We don't use $name$ yet, but it could be used for the /proc
63
 * filesystem in the future, or for other purposes.
64
 */
65
int register_cdrom(int major, char *name, struct cdrom_device_ops *cdo)
66
{
67
        int *change_capability = &cdo->capability; /* hack, gcc complains OK */
68
 
69
        if (major < 0 || major >= MAX_BLKDEV)
70
                return -1;
71
        if (cdo->open_files == NULL || cdo->open == NULL ||
72
            cdo->release == NULL)
73
                return -2;
74
        ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
75
        ENSURE(lock_door, CDC_LOCK);
76
        ENSURE(select_speed, CDC_SELECT_SPEED);
77
        ENSURE(select_disc, CDC_SELECT_DISC);
78
        ENSURE(get_last_session, CDC_MULTI_SESSION);
79
        ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
80
        ENSURE(media_changed, CDC_MEDIA_CHANGED);
81
        cdromdevs[major] = cdo;
82
        cdo->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
83
        cdo->mc_flags = 0;
84
        return 0;
85
}
86
#undef ENSURE
87
 
88
int unregister_cdrom(int major, char *name)
89
{
90
        if (major < 0 || major >= MAX_BLKDEV)
91
                return -1;
92
        if (cdromdevs[major] == NULL)
93
                return -2;
94
        cdromdevs[major] = NULL;
95
        return 0;
96
}
97
 
98
/* We need our own cdrom error types! This is a temporary solution. */
99
 
100
#ifndef ENOMEDIUM
101
#define ENOMEDIUM EAGAIN                                /* no medium in removable device */
102
#endif
103
 
104
/* We use the open-option O_NONBLOCK to indicate that the
105
 * purpose of opening is only for subsequent ioctl() calls; no device
106
 * integrity checks are performed.
107
 *
108
 * We hope that all cd-player programs will adopt this convention. It
109
 * is in their own interest: device control becomes a lot easier
110
 * this way.
111
 */
112
int open_for_data(struct cdrom_device_ops *, kdev_t);
113
 
114
int cdrom_open(struct inode *ip, struct file *fp)
115
{
116
        kdev_t dev = ip->i_rdev;
117
        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
118
        int purpose = !!(fp->f_flags & O_NONBLOCK);
119
 
120
        if (cdo == NULL || MINOR(dev) >= cdo->minors)
121
                return -ENODEV;
122
        if (fp->f_mode & FM_WRITE)
123
                return -EROFS;
124
        purpose = purpose || !(cdo->options & CDO_USE_FFLAGS);
125
        if (cdo->open_files(dev) || purpose)
126
                return cdo->open(dev, purpose);
127
        else
128
                return open_for_data(cdo, dev);
129
}
130
 
131
int open_for_data(struct cdrom_device_ops * cdo, kdev_t dev)
132
{
133
        int ret;
134
        if (cdo->drive_status != NULL) {
135
                int ds = cdo->drive_status(dev);
136
                if (ds == CDS_TRAY_OPEN) {
137
                        /* can/may i close it? */
138
                        if (cdo->capability & ~cdo->mask & CDC_CLOSE_TRAY &&
139
                            cdo->options & CDO_AUTO_CLOSE) {
140
                                if (cdo->tray_move(dev, 0))
141
                                        return -EIO;
142
                        } else
143
                                return -ENOMEDIUM; /* can't close: too bad */
144
                        ds = cdo->drive_status(dev);
145
                        if (ds == CDS_NO_DISC)
146
                                return -ENOMEDIUM;
147
                }
148
        }
149
        if (cdo->disc_status != NULL) {
150
                int ds = cdo->disc_status(dev);
151
                if (ds == CDS_NO_DISC)
152
                        return -ENOMEDIUM;
153
                if (cdo->options & CDO_CHECK_TYPE &&
154
                    ds != CDS_DATA_1)
155
                        return -ENODATA;
156
        }
157
        /* all is well, we can open the device */
158
        ret = cdo->open(dev, 0); /* open for data */
159
        if (cdo->capability & ~cdo->mask & CDC_LOCK &&
160
            cdo->options & CDO_LOCK)
161
                cdo->lock_door(dev, 1);
162
        return ret;
163
}
164
 
165
/* Admittedly, the logic below could be performed in a nicer way. */
166
void cdrom_release(struct inode *ip, struct file *fp)
167
{
168
        kdev_t dev = ip->i_rdev;
169
        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
170
 
171
        if (cdo == NULL || MINOR(dev) >= cdo->minors)
172
                return;
173
        if (cdo->open_files(dev) == 1 && /* last process that closes dev */
174
            cdo->options & CDO_LOCK &&
175
            cdo->capability & ~cdo->mask & CDC_LOCK)
176
                cdo->lock_door(dev, 0);
177
        cdo->release(dev);
178
        if (cdo->open_files(dev) == 0) { /* last process that closes dev */
179
                sync_dev(dev);
180
                invalidate_buffers(dev);
181
                if (cdo->options & CDO_AUTO_EJECT &&
182
                    cdo->capability & ~cdo->mask & CDC_OPEN_TRAY)
183
                        cdo->tray_move(dev, 1);
184
        }
185
}
186
 
187
/* We want to make media_changed accessible to the user through an
188
 * ioctl. The main problem now is that we must double-buffer the
189
 * low-level implementation, to assure that the VFS and the user both
190
 * see a medium change once.
191
 *
192
 * For now, i've implemented only 16 minor devs (half a long), i have to
193
 * think of a better solution... $Queue$ is either 0 or 1. Queue 0 is
194
 * in the lower 16 bits, queue 1 in the higher 16 bits.
195
 */
196
 
197
int media_changed(kdev_t dev, int queue)
198
{
199
        unsigned int major = MAJOR(dev);
200
        unsigned int minor = MINOR(dev);
201
        struct cdrom_device_ops *cdo = cdromdevs[major];
202
        int ret;
203
        unsigned long mask = 1 << (16 * queue + minor);
204
 
205
        queue &= 1;
206
        if (cdo == NULL || minor >= 16)
207
                return -1;
208
        ret = !!(cdo->mc_flags & mask); /* changed since last call? */
209
        if (cdo->media_changed(dev)) {
210
                cdo->mc_flags |= 0x10001 << minor; /* set bit on both queues */
211
                ret |= 1;
212
        }
213
        cdo->mc_flags &= ~mask;         /* clear bit */
214
        return ret;
215
}
216
 
217
int cdrom_media_changed(kdev_t dev)
218
{
219
        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
220
        if (cdo == NULL || MINOR(dev) >= cdo->minors)
221
                return -ENODEV;
222
        if (cdo->media_changed == NULL)
223
                return -EINVAL;
224
        return media_changed(dev, 0);
225
}
226
 
227
/* Requests to the low-level drivers will /always/ be done in the
228
   following format convention:
229
 
230
   CDROM_LBA: all data-related requests.
231
   CDROM_MSF: all audio-related requests.
232
 
233
   However, a low-level implementation is allowed to refuse this
234
   request, and return information in its own favorite format.
235
 
236
   It doesn't make sense /at all/ to ask for a play_audio in LBA
237
   format, or ask for multi-session info in MSF format. However, for
238
   backward compatibility these format requests will be satisfied, but
239
   the requests to the low-level drivers will be sanitized in the more
240
   meaningful format indicated above.
241
 */
242
 
243
#undef current                                                  /* set in sched.h */
244
 
245
void sanitize_format(union cdrom_addr *addr,
246
                     u_char * current, u_char requested)
247
{
248
        if (*current == requested)
249
                return;                 /* nothing to be done! */
250
        if (requested == CDROM_LBA) {
251
                addr->lba = (int) addr->msf.frame +
252
                        75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
253
        } else {                        /* CDROM_MSF */
254
                int lba = addr->lba;
255
                addr->msf.frame = lba % 75;
256
                lba /= 75;
257
                lba += 2;
258
                addr->msf.second = lba % 60;
259
                addr->msf.minute = lba / 60;
260
        }
261
        *current = requested;
262
}
263
 
264
/* All checking and format change makes this code really hard to read!
265
 * So let's make some check and memory move macros.  These macros are
266
 * a little inefficient when both used in the same piece of code, as
267
 * verify_area is used twice, but who cares, as ioctl() calls
268
 * shouldn't be in inner loops.
269
 */
270
#define GETARG(type, x) { \
271
        int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
272
            if (ret) return ret; \
273
            memcpy_fromfs(&x, (type *) arg, sizeof x); }
274
#define PUTARG(type, x) { \
275
            int ret=verify_area(VERIFY_WRITE, (void *) arg, sizeof x); \
276
            if (ret) return ret; \
277
            memcpy_tofs((type *) arg, &x, sizeof x); }
278
 
279
/* Some of the cdrom ioctls are not implemented here, because these
280
 * appear to be either too device-specific, or it is not clear to me
281
 * what use they are. These are (number of drivers that support them
282
 * in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide),
283
 * CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2),
284
 * CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio,
285
 * OK (although i guess the record companies aren't too happy with
286
 * this, most drives therefore refuse to transport audio data).  But
287
 * why are there 5 different READs defined? For now, these functions
288
 * are left over to the device-specific ioctl routine,
289
 * cdo->dev_ioctl. Note that as a result of this, no
290
 * memory-verification is performed for these ioctls.
291
 */
292
int cdrom_ioctl(struct inode *ip, struct file *fp,
293
                unsigned int cmd, unsigned long arg)
294
{
295
        kdev_t dev = ip->i_rdev;
296
        struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
297
 
298
        if (cdo == NULL || MINOR(dev) >= cdo->minors)
299
                return -ENODEV;
300
        /* the first few commands do not deal with audio capabilities, but
301
           only with routines in cdrom device operations. */
302
        switch (cmd) {
303
                /* maybe we should order cases after statistics of use? */
304
 
305
        case CDROMMULTISESSION:
306
        {
307
                struct cdrom_multisession ms_info;
308
                u_char requested_format;
309
                if (!(cdo->capability & CDC_MULTI_SESSION))
310
                        return -EINVAL;
311
                GETARG(struct cdrom_multisession, ms_info);
312
                requested_format = ms_info.addr_format;
313
                ms_info.addr_format = CDROM_LBA;
314
                cdo->get_last_session(dev, &ms_info);
315
                sanitize_format(&ms_info.addr, &ms_info.addr_format,
316
                                requested_format);
317
                PUTARG(struct cdrom_multisession, ms_info);
318
                return 0;
319
        }
320
 
321
        case CDROMEJECT:
322
                if (cdo->open_files(dev) == 1 &&
323
                    cdo->capability & ~cdo->mask & CDC_OPEN_TRAY)
324
                        return cdo->tray_move(dev, 1);
325
                else
326
                        return -EINVAL;
327
 
328
        case CDROMCLOSETRAY:
329
                if (cdo->open_files(dev) == 1 &&
330
                    cdo->capability & ~cdo->mask & CDC_CLOSE_TRAY)
331
                        return cdo->tray_move(dev, 0);
332
                else
333
                        return -EINVAL;
334
 
335
        case CDROMEJECT_SW:
336
                cdo->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
337
                if (arg)
338
                        cdo->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
339
                return 0;
340
 
341
        case CDROM_MEDIA_CHANGED:
342
                if (cdo->capability & ~cdo->mask & CDC_MEDIA_CHANGED)
343
                        return media_changed(dev, 1);
344
                else
345
                        return -EINVAL;
346
 
347
        case CDROM_SET_OPTIONS:
348
                cdo->options |= (int) arg;
349
                return cdo->options;
350
 
351
        case CDROM_CLEAR_OPTIONS:
352
                cdo->options &= ~(int) arg;
353
                return cdo->options;
354
 
355
        case CDROM_SELECT_SPEED:
356
                if (0 <= arg && arg <= cdo->speed &&
357
                    cdo->capability & ~cdo->mask & CDC_SELECT_SPEED)
358
                        return cdo->select_speed(dev, arg);
359
                else
360
                        return -EINVAL;
361
 
362
        case CDROM_SELECT_DISC:
363
                if (0 <= arg && arg <= cdo->capacity &&
364
                    cdo->capability & ~cdo->mask & CDC_SELECT_DISC)
365
                        return cdo->select_disc(dev, arg);
366
                else
367
                        return -EINVAL;
368
 
369
/* The following function is implemented, although very few audio
370
 * discs give Universal Product Code information, which should just be
371
 * the Medium Catalog Number on the box.  Note, that the way the code
372
 * is written on the CD is /not/ uniform across all discs!
373
 */
374
        case CDROM_GET_MCN: {
375
                struct cdrom_mcn mcn;
376
                if (!(cdo->capability & CDC_MCN))
377
                        return -EINVAL;
378
                if (!cdo->get_mcn(dev, &mcn)) {
379
                        PUTARG(struct cdrom_mcn, mcn);
380
                        return 0;
381
                }
382
                return -EINVAL;
383
        }
384
 
385
        case CDROM_DRIVE_STATUS:
386
                if (cdo->drive_status == NULL)
387
                        return -EINVAL;
388
                else
389
                        return cdo->drive_status(dev);
390
 
391
        case CDROM_DISC_STATUS:
392
                if (cdo->disc_status == NULL)
393
                        return -EINVAL;
394
                else
395
                        return cdo->disc_status(dev);
396
 
397
/* The following is not implemented, because there are too many
398
 * different data type. We could support /1/ raw mode, that is large
399
 * enough to hold everything.
400
 */
401
 
402
#if 0
403
        case CDROMREADMODE1: {
404
                struct cdrom_msf msf;
405
                char buf[CD_FRAMESIZE];
406
                GETARG(struct cdrom_msf, msf);
407
                if (!cdo->read_audio(dev, cmd, &msf, &buf)) {
408
                        PUTARG(char *, buf);
409
                        return 0;
410
                }
411
                return -EINVAL;
412
        }
413
#endif
414
        } /* switch */
415
 
416
/* Now all the audio-ioctls follow, they are all routed through the
417
   same call audio_ioctl(). */
418
 
419
        if (cdo->capability & CDC_PLAY_AUDIO)
420
                switch (cmd) {
421
                case CDROMSUBCHNL:
422
                {
423
                        struct cdrom_subchnl q;
424
                        u_char requested, back;
425
                        GETARG(struct cdrom_subchnl, q);
426
                        requested = q.cdsc_format;
427
                        q.cdsc_format = CDROM_MSF;
428
                        if (!cdo->audio_ioctl(dev, cmd, &q)) {
429
                                back = q.cdsc_format; /* local copy */
430
                                sanitize_format(&q.cdsc_absaddr, &back, requested);
431
                                sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
432
                                PUTARG(struct cdrom_subchnl, q);
433
                                return 0;
434
                        } else
435
                                return -EINVAL;
436
                }
437
                case CDROMREADTOCHDR: {
438
                        struct cdrom_tochdr header;
439
                        GETARG(struct cdrom_tochdr, header);
440
                        if (!cdo->audio_ioctl(dev, cmd, &header)) {
441
                                PUTARG(struct cdrom_tochdr, header);
442
                                return 0;
443
                        } else
444
                                return -EINVAL;
445
                }
446
                case CDROMREADTOCENTRY: {
447
                        struct cdrom_tocentry entry;
448
                        u_char requested_format;
449
                        GETARG(struct cdrom_tocentry, entry);
450
                        requested_format = entry.cdte_format;
451
                        /* make interface to low-level uniform */
452
                        entry.cdte_format = CDROM_MSF;
453
                        if (!(cdo->audio_ioctl(dev, cmd, &entry))) {
454
                                sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
455
                                PUTARG(struct cdrom_tocentry, entry);
456
                                return 0;
457
                        } else
458
                                return -EINVAL;
459
                }
460
                case CDROMPLAYMSF: {
461
                        struct cdrom_msf msf;
462
                        GETARG(struct cdrom_msf, msf);
463
                        return cdo->audio_ioctl(dev, cmd, &msf);
464
                }
465
                case CDROMPLAYTRKIND: {
466
                        struct cdrom_ti track_index;
467
                        GETARG(struct cdrom_ti, track_index);
468
                        return cdo->audio_ioctl(dev, cmd, &track_index);
469
                }
470
                case CDROMVOLCTRL: {
471
                        struct cdrom_volctrl volume;
472
                        GETARG(struct cdrom_volctrl, volume);
473
                        return cdo->audio_ioctl(dev, cmd, &volume);
474
                }
475
                case CDROMVOLREAD: {
476
                        struct cdrom_volctrl volume;
477
                        if (!cdo->audio_ioctl(dev, cmd, &volume)) {
478
                                PUTARG(struct cdrom_volctrl, volume);
479
                                return 0;
480
                        }
481
                        return -EINVAL;
482
                }
483
                case CDROMSTART:
484
                case CDROMSTOP:
485
                case CDROMPAUSE:
486
                case CDROMRESUME:
487
                        return cdo->audio_ioctl(dev, cmd, NULL);
488
                } /* switch */
489
 
490
        if (cdo->dev_ioctl != NULL)     /* device specific ioctls? */
491
                return cdo->dev_ioctl(dev, cmd, arg);
492
        return -EINVAL;
493
}
494
 
495
#ifdef MODULE
496
int init_module(void)
497
{
498
        printk(KERN_INFO "Module inserted " VERSION "\n");
499
        return 0;
500
}
501
 
502
void cleanup_module(void)
503
{
504
        printk(KERN_INFO "Module cdrom removed\n");
505
}
506
 
507
#endif
508
/*
509
 * Local variables:
510
 * comment-column: 40
511
 * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o"
512
 * End:
513
 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.