]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ide/ide-cd.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
[linux-2.6-omap-h63xx.git] / drivers / ide / ide-cd.c
index 50f78eb7dce98c20a6326fc5958b767f2a96ad4b..5e42c19a03e3b7f9e2eec932a929660cb513730d 100644 (file)
@@ -1,14 +1,14 @@
 /*
- * linux/drivers/ide/ide-cd.c
+ * ATAPI CD-ROM driver.
  *
- * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
+ * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * ATAPI CD-ROM driver.  To be used with ide.c.
  * See Documentation/cdrom/ide-cd for usage information.
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
  * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
  * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
  *
- * Drives that deviate from these standards will be accommodated as much
- * as possible via compile time or command-line options.  Since I only have
- * a few drives, you generally need to send me patches...
- *
- * ----------------------------------
- * TO DO LIST:
- * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
- *   boot
- *
  * For historical changelog please see:
  *     Documentation/ide/ChangeLog.ide-cd.1994-2004
  */
 
-#define IDECD_VERSION "4.61"
+#define IDECD_VERSION "5.00"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -304,7 +295,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        int stat, err, sense_key;
        
        /* Check for errors. */
-       stat = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
+
        if (stat_ret)
                *stat_ret = stat;
 
@@ -312,7 +304,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                return 0;
 
        /* Get the IDE error register. */
-       err = HWIF(drive)->INB(IDE_ERROR_REG);
+       err = ide_read_error(drive);
        sense_key = err >> 4;
 
        if (rq == NULL) {
@@ -332,7 +324,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 
        } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
-               unsigned long flags;
 
                /*
                 * if we have an error, pass back CHECK_CONDITION as the
@@ -370,15 +361,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * remove failed request completely and end it when the
                 * request sense has completed
                 */
-               if (stat & ERR_STAT) {
-                       spin_lock_irqsave(&ide_lock, flags);
-                       blkdev_dequeue_request(rq);
-                       HWGROUP(drive)->rq = NULL;
-                       spin_unlock_irqrestore(&ide_lock, flags);
-
-                       cdrom_queue_request_sense(drive, rq->sense, rq);
-               } else
-                       cdrom_end_request(drive, 0);
+               goto end_request;
 
        } else if (blk_fs_request(rq)) {
                int do_end_request = 0;
@@ -458,23 +441,15 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                   sense data. We need this in order to perform end of media
                   processing */
 
-               if (do_end_request) {
-                       if (stat & ERR_STAT) {
-                               unsigned long flags;
-                               spin_lock_irqsave(&ide_lock, flags);
-                               blkdev_dequeue_request(rq);
-                               HWGROUP(drive)->rq = NULL;
-                               spin_unlock_irqrestore(&ide_lock, flags);
+               if (do_end_request)
+                       goto end_request;
 
-                               cdrom_queue_request_sense(drive, rq->sense, rq);
-                       } else
-                               cdrom_end_request(drive, 0);
-               } else {
-                       /* If we got a CHECK_CONDITION status,
-                          queue a request sense command. */
-                       if (stat & ERR_STAT)
-                               cdrom_queue_request_sense(drive, NULL, NULL);
-               }
+               /*
+                * If we got a CHECK_CONDITION status,
+                * queue a request sense command.
+                */
+               if (stat & ERR_STAT)
+                       cdrom_queue_request_sense(drive, NULL, NULL);
        } else {
                blk_dump_rq_flags(rq, "ide-cd: bad rq");
                cdrom_end_request(drive, 0);
@@ -482,6 +457,21 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 
        /* Retry, or handle the next request. */
        return 1;
+
+end_request:
+       if (stat & ERR_STAT) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ide_lock, flags);
+               blkdev_dequeue_request(rq);
+               HWGROUP(drive)->rq = NULL;
+               spin_unlock_irqrestore(&ide_lock, flags);
+
+               cdrom_queue_request_sense(drive, rq->sense, rq);
+       } else
+               cdrom_end_request(drive, 0);
+
+       return 1;
 }
 
 static int cdrom_timer_expiry(ide_drive_t *drive)
@@ -615,8 +605,6 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
  * Block read functions.
  */
 
-typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
-
 static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
 {
        while (len > 0) {
@@ -683,25 +671,29 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  * ok; nonzero if the request has been terminated.
  */
 static
-int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
+int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
 {
-       if (ireason == 2)
+       /*
+        * ireason == 0: the drive wants to receive data from us
+        * ireason == 2: the drive is expecting to transfer data to us
+        */
+       if (ireason == (!rw << 1))
                return 0;
-       else if (ireason == 0) {
+       else if (ireason == (rw << 1)) {
                ide_hwif_t *hwif = drive->hwif;
+               xfer_func_t *xf;
 
-               /* Whoops... The drive is expecting to receive data from us! */
+               /* Whoops... */
                printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
                                drive->name, __FUNCTION__);
 
-               /* Throw some data at the drive so it doesn't hang
-                  and quit this request. */
-               ide_cd_pad_transfer(drive, hwif->atapi_output_bytes, len);
-       } else  if (ireason == 1) {
+               xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes;
+               ide_cd_pad_transfer(drive, xf, len);
+       } else  if (rw == 0 && ireason == 1) {
                /* Some drives (ASUS) seem to tell us that status
                 * info is available. just get it and ignore.
                 */
-               (void) HWIF(drive)->INB(IDE_STATUS_REG);
+               (void)ide_read_status(drive);
                return 0;
        } else {
                /* Drive wants a command packet, or invalid ireason... */
@@ -984,35 +976,6 @@ int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
        return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
 }
 
-/*
- * Write handling
- */
-static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
-{
-       /* Two notes about IDE interrupt reason here - 0 means that
-        * the drive wants to receive data from us, 2 means that
-        * the drive is expecting to transfer data to us.
-        */
-       if (ireason == 0)
-               return 0;
-       else if (ireason == 2) {
-               ide_hwif_t *hwif = drive->hwif;
-
-               /* Whoops... The drive wants to send data. */
-               printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
-                               drive->name, __FUNCTION__);
-
-               ide_cd_pad_transfer(drive, hwif->atapi_input_bytes, len);
-       } else {
-               /* Drive wants a command packet, or invalid ireason... */
-               printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
-                               drive->name, __FUNCTION__, ireason);
-       }
-
-       cdrom_end_request(drive, 0);
-       return 1;
-}
-
 /*
  * Called from blk_end_request_callback() after the data of the request
  * is completed and before the request is completed.
@@ -1108,20 +1071,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        /*
         * check which way to transfer data
         */
-       if ((blk_fs_request(rq) || blk_pc_request(rq)) && write) {
-               /*
-                * write to drive
-                */
-               if (cdrom_write_check_ireason(drive, len, ireason))
-                       return ide_stopped;
-       } else if (blk_fs_request(rq) || blk_pc_request(rq)) {
-               /*
-                * read from drive
-                */
-               if (cdrom_read_check_ireason(drive, len, ireason))
+       if (blk_fs_request(rq) || blk_pc_request(rq)) {
+               if (ide_cd_check_ireason(drive, len, ireason, write))
                        return ide_stopped;
 
-               if (blk_fs_request(rq)) {
+               if (blk_fs_request(rq) && write == 0) {
                        int nskip;
 
                        if (ide_cd_check_transfer_size(drive, len)) {
@@ -1373,7 +1327,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
        if (blk_fs_request(rq)) {
                if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
                        unsigned long elapsed = jiffies - info->start_seek;
-                       int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+                       int stat = ide_read_status(drive);
 
                        if ((stat & SEEK_STAT) != SEEK_STAT) {
                                if (elapsed < IDECD_SEEK_TIMEOUT) {
@@ -1426,7 +1380,7 @@ void msf_from_bcd (struct atapi_msf *msf)
        msf->frame  = BCD2BIN(msf->frame);
 }
 
-static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
+int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
        struct request req;
        struct cdrom_info *info = drive->driver_data;
@@ -1447,85 +1401,6 @@ static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
        return ide_cd_queue_pc(drive, &req);
 }
 
-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
-int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
-                   struct request_sense *sense)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct request_sense my_sense;
-       struct request req;
-       int stat;
-
-       if (sense == NULL)
-               sense = &my_sense;
-
-       /* If the drive cannot lock the door, just pretend. */
-       if (cd->cd_flags & IDE_CD_FLAG_NO_DOORLOCK) {
-               stat = 0;
-       } else {
-               ide_cd_init_rq(drive, &req);
-               req.sense = sense;
-               req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-               req.cmd[4] = lockflag ? 1 : 0;
-               stat = ide_cd_queue_pc(drive, &req);
-       }
-
-       /* If we got an illegal field error, the drive
-          probably cannot lock the door. */
-       if (stat != 0 &&
-           sense->sense_key == ILLEGAL_REQUEST &&
-           (sense->asc == 0x24 || sense->asc == 0x20)) {
-               printk (KERN_ERR "%s: door locking not supported\n",
-                       drive->name);
-               cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
-               stat = 0;
-       }
-       
-       /* no medium, that's alright. */
-       if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
-               stat = 0;
-
-       if (stat == 0) {
-               if (lockflag)
-                       cd->cd_flags |= IDE_CD_FLAG_DOOR_LOCKED;
-               else
-                       cd->cd_flags &= ~IDE_CD_FLAG_DOOR_LOCKED;
-       }
-
-       return stat;
-}
-
-
-/* Eject the disk if EJECTFLAG is 0.
-   If EJECTFLAG is 1, try to reload the disk. */
-static int cdrom_eject(ide_drive_t *drive, int ejectflag,
-                      struct request_sense *sense)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct cdrom_device_info *cdi = &cd->devinfo;
-       struct request req;
-       char loej = 0x02;
-
-       if ((cd->cd_flags & IDE_CD_FLAG_NO_EJECT) && !ejectflag)
-               return -EDRIVE_CANT_DO_THIS;
-
-       /* reload fails on some drives, if the tray is locked */
-       if ((cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) && ejectflag)
-               return 0;
-
-       ide_cd_init_rq(drive, &req);
-
-       /* only tell drive to close tray if open, if it can do that */
-       if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
-               loej = 0;
-
-       req.sense = sense;
-       req.cmd[0] = GPCMD_START_STOP_UNIT;
-       req.cmd[4] = loej | (ejectflag != 0);
-
-       return ide_cd_queue_pc(drive, &req);
-}
-
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
                               unsigned long *sectors_per_frame,
                               struct request_sense *sense)
@@ -1741,53 +1616,6 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
        return 0;
 }
 
-/* the generic packet interface to cdrom.c */
-static int ide_cdrom_packet(struct cdrom_device_info *cdi,
-                           struct packet_command *cgc)
-{
-       struct request req;
-       ide_drive_t *drive = cdi->handle;
-
-       if (cgc->timeout <= 0)
-               cgc->timeout = ATAPI_WAIT_PC;
-
-       /* here we queue the commands from the uniform CD-ROM
-          layer. the packet must be complete, as we do not
-          touch it at all. */
-       ide_cd_init_rq(drive, &req);
-       memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
-       if (cgc->sense)
-               memset(cgc->sense, 0, sizeof(struct request_sense));
-       req.data = cgc->buffer;
-       req.data_len = cgc->buflen;
-       req.timeout = cgc->timeout;
-
-       if (cgc->quiet)
-               req.cmd_flags |= REQ_QUIET;
-
-       req.sense = cgc->sense;
-       cgc->stat = ide_cd_queue_pc(drive, &req);
-       if (!cgc->stat)
-               cgc->buflen -= req.data_len;
-       return cgc->stat;
-}
-
-static
-int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct request_sense sense;
-
-       if (position) {
-               int stat = ide_cd_lockdoor(drive, 0, &sense);
-
-               if (stat)
-                       return stat;
-       }
-
-       return cdrom_eject(drive, !position, &sense);
-}
-
 int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
 {
        struct cdrom_info *info = drive->driver_data;
@@ -1827,95 +1655,6 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
        cd->max_speed = (maxspeed + (176/2)) / 176;
 }
 
-/*
- * add logic to try GET_EVENT command first to check for media and tray
- * status. this should be supported by newer cd-r/w and all DVD etc
- * drives
- */
-static
-int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct media_event_desc med;
-       struct request_sense sense;
-       int stat;
-
-       if (slot_nr != CDSL_CURRENT)
-               return -EINVAL;
-
-       stat = cdrom_check_status(drive, &sense);
-       if (!stat || sense.sense_key == UNIT_ATTENTION)
-               return CDS_DISC_OK;
-
-       if (!cdrom_get_media_event(cdi, &med)) {
-               if (med.media_present)
-                       return CDS_DISC_OK;
-               else if (med.door_open)
-                       return CDS_TRAY_OPEN;
-               else
-                       return CDS_NO_DISC;
-       }
-
-       if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04)
-               return CDS_DISC_OK;
-
-       /*
-        * If not using Mt Fuji extended media tray reports,
-        * just return TRAY_OPEN since ATAPI doesn't provide
-        * any other way to detect this...
-        */
-       if (sense.sense_key == NOT_READY) {
-               if (sense.asc == 0x3a && sense.ascq == 1)
-                       return CDS_NO_DISC;
-               else
-                       return CDS_TRAY_OPEN;
-       }
-       return CDS_DRIVE_NOT_READY;
-}
-
-/****************************************************************************
- * Other driver requests (open, close, check media change).
- */
-
-static
-int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
-                                      int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *cd = drive->driver_data;
-       int retval;
-
-       if (slot_nr == CDSL_CURRENT) {
-               (void) cdrom_check_status(drive, NULL);
-               retval = (cd->cd_flags & IDE_CD_FLAG_MEDIA_CHANGED) ? 1 : 0;
-               cd->cd_flags &= ~IDE_CD_FLAG_MEDIA_CHANGED;
-               return retval;
-       } else {
-               return -EINVAL;
-       }
-}
-
-
-static
-int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose)
-{
-       return 0;
-}
-
-/*
- * Close down the device.  Invalidate all cached blocks.
- */
-
-static
-void ide_cdrom_release_real (struct cdrom_device_info *cdi)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *cd = drive->driver_data;
-
-       if (!cdi->use_count)
-               cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
-}
-
 #define IDE_CD_CAPABILITIES \
        (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
         CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \