Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * cdrom.c IOCTLs handling for ide-cd driver.
  3  *
  4  * Copyright (C) 1994-1996  Scott Snyder <snyder@fnald0.fnal.gov>
  5  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
  6  * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
  7  */
  8 
  9 #include <linux/kernel.h>
 10 #include <linux/cdrom.h>
 11 #include <linux/ide.h>
 12 #include <scsi/scsi.h>
 13 
 14 #include "ide-cd.h"
 15 
 16 /****************************************************************************
 17  * Other driver requests (open, close, check media change).
 18  */
 19 int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
 20 {
 21         return 0;
 22 }
 23 
 24 /*
 25  * Close down the device.  Invalidate all cached blocks.
 26  */
 27 void ide_cdrom_release_real(struct cdrom_device_info *cdi)
 28 {
 29         ide_drive_t *drive = cdi->handle;
 30         struct cdrom_info *cd = drive->driver_data;
 31 
 32         if (!cdi->use_count)
 33                 cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
 34 }
 35 
 36 /*
 37  * add logic to try GET_EVENT command first to check for media and tray
 38  * status. this should be supported by newer cd-r/w and all DVD etc
 39  * drives
 40  */
 41 int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 42 {
 43         ide_drive_t *drive = cdi->handle;
 44         struct media_event_desc med;
 45         struct request_sense sense;
 46         int stat;
 47 
 48         if (slot_nr != CDSL_CURRENT)
 49                 return -EINVAL;
 50 
 51         stat = cdrom_check_status(drive, &sense);
 52         if (!stat || sense.sense_key == UNIT_ATTENTION)
 53                 return CDS_DISC_OK;
 54 
 55         if (!cdrom_get_media_event(cdi, &med)) {
 56                 if (med.media_present)
 57                         return CDS_DISC_OK;
 58                 else if (med.door_open)
 59                         return CDS_TRAY_OPEN;
 60                 else
 61                         return CDS_NO_DISC;
 62         }
 63 
 64         if (sense.sense_key == NOT_READY && sense.asc == 0x04
 65                         && sense.ascq == 0x04)
 66                 return CDS_DISC_OK;
 67 
 68         /*
 69          * If not using Mt Fuji extended media tray reports,
 70          * just return TRAY_OPEN since ATAPI doesn't provide
 71          * any other way to detect this...
 72          */
 73         if (sense.sense_key == NOT_READY) {
 74                 if (sense.asc == 0x3a && sense.ascq == 1)
 75                         return CDS_NO_DISC;
 76                 else
 77                         return CDS_TRAY_OPEN;
 78         }
 79         return CDS_DRIVE_NOT_READY;
 80 }
 81 
 82 int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
 83                                        int slot_nr)
 84 {
 85         ide_drive_t *drive = cdi->handle;
 86         struct cdrom_info *cd = drive->driver_data;
 87         int retval;
 88 
 89         if (slot_nr == CDSL_CURRENT) {
 90                 (void) cdrom_check_status(drive, NULL);
 91                 retval = (cd->cd_flags & IDE_CD_FLAG_MEDIA_CHANGED) ? 1 : 0;
 92                 cd->cd_flags &= ~IDE_CD_FLAG_MEDIA_CHANGED;
 93                 return retval;
 94         } else {
 95                 return -EINVAL;
 96         }
 97 }
 98 
 99 /* Eject the disk if EJECTFLAG is 0.
100    If EJECTFLAG is 1, try to reload the disk. */
101 static
102 int cdrom_eject(ide_drive_t *drive, int ejectflag,
103                 struct request_sense *sense)
104 {
105         struct cdrom_info *cd = drive->driver_data;
106         struct cdrom_device_info *cdi = &cd->devinfo;
107         struct request req;
108         char loej = 0x02;
109 
110         if ((cd->cd_flags & IDE_CD_FLAG_NO_EJECT) && !ejectflag)
111                 return -EDRIVE_CANT_DO_THIS;
112 
113         /* reload fails on some drives, if the tray is locked */
114         if ((cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) && ejectflag)
115                 return 0;
116 
117         ide_cd_init_rq(drive, &req);
118 
119         /* only tell drive to close tray if open, if it can do that */
120         if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
121                 loej = 0;
122 
123         req.sense = sense;
124         req.cmd[0] = GPCMD_START_STOP_UNIT;
125         req.cmd[4] = loej | (ejectflag != 0);
126 
127         return ide_cd_queue_pc(drive, &req);
128 }
129 
130 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
131 static
132 int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
133                     struct request_sense *sense)
134 {
135         struct cdrom_info *cd = drive->driver_data;
136         struct request_sense my_sense;
137         struct request req;
138         int stat;
139 
140         if (sense == NULL)
141                 sense = &my_sense;
142 
143         /* If the drive cannot lock the door, just pretend. */
144         if (cd->cd_flags & IDE_CD_FLAG_NO_DOORLOCK) {
145                 stat = 0;
146         } else {
147                 ide_cd_init_rq(drive, &req);
148                 req.sense = sense;
149                 req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
150                 req.cmd[4] = lockflag ? 1 : 0;
151                 stat = ide_cd_queue_pc(drive, &req);
152         }
153 
154         /* If we got an illegal field error, the drive
155            probably cannot lock the door. */
156         if (stat != 0 &&
157             sense->sense_key == ILLEGAL_REQUEST &&
158             (sense->asc == 0x24 || sense->asc == 0x20)) {
159                 printk(KERN_ERR "%s: door locking not supported\n",
160                         drive->name);
161                 cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
162                 stat = 0;
163         }
164 
165         /* no medium, that's alright. */
166         if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
167                 stat = 0;
168 
169         if (stat == 0) {
170                 if (lockflag)
171                         cd->cd_flags |= IDE_CD_FLAG_DOOR_LOCKED;
172                 else
173                         cd->cd_flags &= ~IDE_CD_FLAG_DOOR_LOCKED;
174         }
175 
176         return stat;
177 }
178 
179 int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
180 {
181         ide_drive_t *drive = cdi->handle;
182         struct request_sense sense;
183 
184         if (position) {
185                 int stat = ide_cd_lockdoor(drive, 0, &sense);
186 
187                 if (stat)
188                         return stat;
189         }
190 
191         return cdrom_eject(drive, !position, &sense);
192 }
193 
194 int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
195 {
196         ide_drive_t *drive = cdi->handle;
197 
198         return ide_cd_lockdoor(drive, lock, NULL);
199 }
200 
201 /*
202  * ATAPI devices are free to select the speed you request or any slower
203  * rate. :-(  Requesting too fast a speed will _not_ produce an error.
204  */
205 int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
206 {
207         ide_drive_t *drive = cdi->handle;
208         struct cdrom_info *cd = drive->driver_data;
209         struct request rq;
210         struct request_sense sense;
211         u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
212         int stat;
213 
214         ide_cd_init_rq(drive, &rq);
215 
216         rq.sense = &sense;
217 
218         if (speed == 0)
219                 speed = 0xffff; /* set to max */
220         else
221                 speed *= 177;   /* Nx to kbytes/s */
222 
223         rq.cmd[0] = GPCMD_SET_SPEED;
224         /* Read Drive speed in kbytes/second MSB/LSB */
225         rq.cmd[2] = (speed >> 8) & 0xff;
226         rq.cmd[3] = speed & 0xff;
227         if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
228             (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
229                 /* Write Drive speed in kbytes/second MSB/LSB */
230                 rq.cmd[4] = (speed >> 8) & 0xff;
231                 rq.cmd[5] = speed & 0xff;
232         }
233 
234         stat = ide_cd_queue_pc(drive, &rq);
235 
236         if (!ide_cdrom_get_capabilities(drive, buf)) {
237                 ide_cdrom_update_speed(drive, buf);
238                 cdi->speed = cd->current_speed;
239         }
240 
241         return 0;
242 }
243 
244 int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
245                                struct cdrom_multisession *ms_info)
246 {
247         struct atapi_toc *toc;
248         ide_drive_t *drive = cdi->handle;
249         struct cdrom_info *info = drive->driver_data;
250         struct request_sense sense;
251         int ret;
252 
253         if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0 || !info->toc) {
254                 ret = ide_cd_read_toc(drive, &sense);
255                 if (ret)
256                         return ret;
257         }
258 
259         toc = info->toc;
260         ms_info->addr.lba = toc->last_session_lba;
261         ms_info->xa_flag = toc->xa_flag;
262 
263         return 0;
264 }
265 
266 int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
267                       struct cdrom_mcn *mcn_info)
268 {
269         ide_drive_t *drive = cdi->handle;
270         int stat, mcnlen;
271         struct request rq;
272         char buf[24];
273 
274         ide_cd_init_rq(drive, &rq);
275 
276         rq.data = buf;
277         rq.data_len = sizeof(buf);
278 
279         rq.cmd[0] = GPCMD_READ_SUBCHANNEL;
280         rq.cmd[1] = 2;          /* MSF addressing */
281         rq.cmd[2] = 0x40;       /* request subQ data */
282         rq.cmd[3] = 2;          /* format */
283         rq.cmd[8] = sizeof(buf);
284 
285         stat = ide_cd_queue_pc(drive, &rq);
286         if (stat)
287                 return stat;
288 
289         mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
290         memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
291         mcn_info->medium_catalog_number[mcnlen] = '\0';
292 
293         return 0;
294 }
295 
296 int ide_cdrom_reset(struct cdrom_device_info *cdi)
297 {
298         ide_drive_t *drive = cdi->handle;
299         struct cdrom_info *cd = drive->driver_data;
300         struct request_sense sense;
301         struct request req;
302         int ret;
303 
304         ide_cd_init_rq(drive, &req);
305         req.cmd_type = REQ_TYPE_SPECIAL;
306         req.cmd_flags = REQ_QUIET;
307         ret = ide_do_drive_cmd(drive, &req, ide_wait);
308 
309         /*
310          * A reset will unlock the door. If it was previously locked,
311          * lock it again.
312          */
313         if (cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED)
314                 (void)ide_cd_lockdoor(drive, 1, &sense);
315 
316         return ret;
317 }
318 
319 static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
320                                 struct atapi_toc_entry **ent)
321 {
322         struct cdrom_info *info = drive->driver_data;
323         struct atapi_toc *toc = info->toc;
324         int ntracks;
325 
326         /*
327          * don't serve cached data, if the toc isn't valid
328          */
329         if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0)
330                 return -EINVAL;
331 
332         /* Check validity of requested track number. */
333         ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
334 
335         if (toc->hdr.first_track == CDROM_LEADOUT)
336                 ntracks = 0;
337 
338         if (track == CDROM_LEADOUT)
339                 *ent = &toc->ent[ntracks];
340         else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
341                 return -EINVAL;
342         else
343                 *ent = &toc->ent[track - toc->hdr.first_track];
344 
345         return 0;
346 }
347 
348 static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
349 {
350         struct cdrom_ti *ti = arg;
351         struct atapi_toc_entry *first_toc, *last_toc;
352         unsigned long lba_start, lba_end;
353         int stat;
354         struct request rq;
355         struct request_sense sense;
356 
357         stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
358         if (stat)
359                 return stat;
360 
361         stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
362         if (stat)
363                 return stat;
364 
365         if (ti->cdti_trk1 != CDROM_LEADOUT)
366                 ++last_toc;
367         lba_start = first_toc->addr.lba;
368         lba_end   = last_toc->addr.lba;
369 
370         if (lba_end <= lba_start)
371                 return -EINVAL;
372 
373         ide_cd_init_rq(drive, &rq);
374 
375         rq.sense = &sense;
376         rq.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
377         lba_to_msf(lba_start,   &rq.cmd[3], &rq.cmd[4], &rq.cmd[5]);
378         lba_to_msf(lba_end - 1, &rq.cmd[6], &rq.cmd[7], &rq.cmd[8]);
379 
380         return ide_cd_queue_pc(drive, &rq);
381 }
382 
383 static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
384 {
385         struct cdrom_info *cd = drive->driver_data;
386         struct cdrom_tochdr *tochdr = arg;
387         struct atapi_toc *toc;
388         int stat;
389 
390         /* Make sure our saved TOC is valid. */
391         stat = ide_cd_read_toc(drive, NULL);
392         if (stat)
393                 return stat;
394 
395         toc = cd->toc;
396         tochdr->cdth_trk0 = toc->hdr.first_track;
397         tochdr->cdth_trk1 = toc->hdr.last_track;
398 
399         return 0;
400 }
401 
402 static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
403 {
404         struct cdrom_tocentry *tocentry = arg;
405         struct atapi_toc_entry *toce;
406         int stat;
407 
408         stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
409         if (stat)
410                 return stat;
411 
412         tocentry->cdte_ctrl = toce->control;
413         tocentry->cdte_adr  = toce->adr;
414         if (tocentry->cdte_format == CDROM_MSF) {
415                 lba_to_msf(toce->addr.lba,
416                            &tocentry->cdte_addr.msf.minute,
417                            &tocentry->cdte_addr.msf.second,
418                            &tocentry->cdte_addr.msf.frame);
419         } else
420                 tocentry->cdte_addr.lba = toce->addr.lba;
421 
422         return 0;
423 }
424 
425 int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
426                           unsigned int cmd, void *arg)
427 {
428         ide_drive_t *drive = cdi->handle;
429 
430         switch (cmd) {
431         /*
432          * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
433          * atapi doesn't support it
434          */
435         case CDROMPLAYTRKIND:
436                 return ide_cd_fake_play_trkind(drive, arg);
437         case CDROMREADTOCHDR:
438                 return ide_cd_read_tochdr(drive, arg);
439         case CDROMREADTOCENTRY:
440                 return ide_cd_read_tocentry(drive, arg);
441         default:
442                 return -EINVAL;
443         }
444 }
445 
446 /* the generic packet interface to cdrom.c */
447 int ide_cdrom_packet(struct cdrom_device_info *cdi,
448                             struct packet_command *cgc)
449 {
450         struct request req;
451         ide_drive_t *drive = cdi->handle;
452 
453         if (cgc->timeout <= 0)
454                 cgc->timeout = ATAPI_WAIT_PC;
455 
456         /* here we queue the commands from the uniform CD-ROM
457            layer. the packet must be complete, as we do not
458            touch it at all. */
459         ide_cd_init_rq(drive, &req);
460 
461         if (cgc->data_direction == CGC_DATA_WRITE)
462                 req.cmd_flags |= REQ_RW;
463 
464         memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
465         if (cgc->sense)
466                 memset(cgc->sense, 0, sizeof(struct request_sense));
467         req.data = cgc->buffer;
468         req.data_len = cgc->buflen;
469         req.timeout = cgc->timeout;
470 
471         if (cgc->quiet)
472                 req.cmd_flags |= REQ_QUIET;
473 
474         req.sense = cgc->sense;
475         cgc->stat = ide_cd_queue_pc(drive, &req);
476         if (!cgc->stat)
477                 cgc->buflen -= req.data_len;
478         return cgc->stat;
479 }
480 
  This page was automatically generated by the LXR engine.