]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ide/ide-cd.c
ide-cd: Enable audio play quirk for Optiarc DVD RW AD-5200A drive
[linux-2.6-omap-h63xx.git] / drivers / ide / ide-cd.c
index 0f17117c5aa04717949ea89b3c83096e5433d714..022a029f81c278e7971efc60e7a21f72f3461517 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... */
@@ -797,7 +789,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
        return 0;
 }
 
-static ide_startstop_t cdrom_rw_intr(ide_drive_t *);
+static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
 
 /*
  * Routine to send a read/write packet command to the drive.
@@ -846,7 +838,7 @@ static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
        rq->timeout = ATAPI_WAIT_PC;
 
        /* Send the command to the drive and return. */
-       return cdrom_transfer_packet_command(drive, rq, cdrom_rw_intr);
+       return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
 }
 
 #define IDECD_SEEK_THRESHOLD   (1000)                  /* 1000 blocks */
@@ -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.
@@ -1024,17 +987,12 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq)
        return 1;
 }
 
-/*
- * best way to deal with dma that is not sector aligned right now... note
- * that in this path we are not using ->data or ->buffer at all. this irs
- * can replace cdrom_rw_intr() in the future.
- */
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
        struct request *rq = HWGROUP(drive)->rq;
        xfer_func_t *xferfunc;
-       ide_expiry_t *expiry;
+       ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0;
        int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
        unsigned int timeout;
@@ -1061,6 +1019,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        if (dma) {
                if (dma_error)
                        return ide_error(drive, "dma error", stat);
+               if (blk_fs_request(rq)) {
+                       ide_end_request(drive, 1, rq->nr_sectors);
+                       return ide_stopped;
+               }
                goto end_request;
        }
 
@@ -1072,7 +1034,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
 
        len = lowcyl + (256 * highcyl);
-       thislen = rq->data_len;
+
+       thislen = blk_fs_request(rq) ? len : rq->data_len;
        if (thislen > len)
                thislen = len;
 
@@ -1080,7 +1043,24 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
         * If DRQ is clear, the command has completed.
         */
        if ((stat & DRQ_STAT) == 0) {
-               if (!blk_pc_request(rq)) {
+               if (blk_fs_request(rq)) {
+                       /*
+                        * If we're not done reading/writing, complain.
+                        * Otherwise, complete the command normally.
+                        */
+                       uptodate = 1;
+                       if (rq->current_nr_sectors > 0) {
+                               printk(KERN_ERR "%s: %s: data underrun "
+                                               "(%d blocks)\n",
+                                               drive->name, __FUNCTION__,
+                                               rq->current_nr_sectors);
+                               if (!write)
+                                       rq->cmd_flags |= REQ_FAILED;
+                               uptodate = 0;
+                       }
+                       cdrom_end_request(drive, uptodate);
+                       return ide_stopped;
+               } else if (!blk_pc_request(rq)) {
                        ide_cd_request_sense_fixup(rq);
                        /* Complain if we still have data left to transfer. */
                        uptodate = rq->data_len ? 0 : 1;
@@ -1091,24 +1071,38 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        /*
         * check which way to transfer data
         */
-       if (blk_pc_request(rq) && rq_data_dir(rq) == WRITE) {
-               /*
-                * write to drive
-                */
-               if (cdrom_write_check_ireason(drive, len, ireason))
-                       return ide_stopped;
-       } else if (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) && write == 0) {
+                       int nskip;
+
+                       if (ide_cd_check_transfer_size(drive, len)) {
+                               cdrom_end_request(drive, 0);
+                               return ide_stopped;
+                       }
+
+                       /*
+                        * First, figure out if we need to bit-bucket
+                        * any of the leading sectors.
+                        */
+                       nskip = min_t(int, rq->current_nr_sectors
+                                          - bio_cur_sectors(rq->bio),
+                                          thislen >> 9);
+                       if (nskip > 0) {
+                               ide_cd_drain_data(drive, nskip);
+                               rq->current_nr_sectors -= nskip;
+                               thislen -= (nskip << 9);
+                       }
+               }
        }
 
        if (ireason == 0) {
                write = 1;
                xferfunc = HWIF(drive)->atapi_output_bytes;
-       } else if (ireason == 2 || (ireason == 1 && blk_pc_request(rq))) {
+       } else if (ireason == 2 || (ireason == 1 &&
+                  (blk_fs_request(rq) || blk_pc_request(rq)))) {
                write = 0;
                xferfunc = HWIF(drive)->atapi_input_bytes;
        } else {
@@ -1123,23 +1117,37 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
         * transfer data
         */
        while (thislen > 0) {
-               int blen = blen = rq->data_len;
-               char *ptr = rq->data;
+               u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
+               int blen = rq->data_len;
 
                /*
                 * bio backed?
                 */
                if (rq->bio) {
-                       ptr = bio_data(rq->bio);
-                       blen = bio_iovec(rq->bio)->bv_len;
+                       if (blk_fs_request(rq)) {
+                               ptr = rq->buffer;
+                               blen = rq->current_nr_sectors << 9;
+                       } else {
+                               ptr = bio_data(rq->bio);
+                               blen = bio_iovec(rq->bio)->bv_len;
+                       }
                }
 
                if (!ptr) {
-                       printk(KERN_ERR "%s: confused, missing data\n",
-                                       drive->name);
-                       blk_dump_rq_flags(rq, rq_data_dir(rq)
-                                             ? "cdrom_newpc_intr, write"
-                                             : "cdrom_newpc_intr, read");
+                       if (blk_fs_request(rq) && !write)
+                               /*
+                                * If the buffers are full, cache the rest
+                                * of the data in our internal buffer.
+                                */
+                               cdrom_buffer_sectors(drive, rq->sector,
+                                                    thislen >> 9);
+                       else {
+                               printk(KERN_ERR "%s: confused, missing data\n",
+                                               drive->name);
+                               blk_dump_rq_flags(rq, rq_data_dir(rq)
+                                                 ? "cdrom_newpc_intr, write"
+                                                 : "cdrom_newpc_intr, read");
+                       }
                        break;
                }
 
@@ -1150,19 +1158,30 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
                thislen -= blen;
                len -= blen;
-               rq->data_len -= blen;
 
-               if (rq->bio)
+               if (blk_fs_request(rq)) {
+                       rq->buffer += blen;
+                       rq->nr_sectors -= (blen >> 9);
+                       rq->current_nr_sectors -= (blen >> 9);
+                       rq->sector += (blen >> 9);
+
+                       if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+                               cdrom_end_request(drive, 1);
+               } else {
+                       rq->data_len -= blen;
+
                        /*
                         * The request can't be completed until DRQ is cleared.
                         * So complete the data, but don't complete the request
                         * using the dummy function for the callback feature
                         * of blk_end_request_callback().
                         */
-                       blk_end_request_callback(rq, 0, blen,
+                       if (rq->bio)
+                               blk_end_request_callback(rq, 0, blen,
                                                 cdrom_newpc_intr_dummy_cb);
-               else
-                       rq->data += blen;
+                       else
+                               rq->data += blen;
+               }
        }
 
        if (write && blk_sense_request(rq))
@@ -1171,15 +1190,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        /*
         * pad, if necessary
         */
-       if (len > 0)
+       if (!blk_fs_request(rq) && len > 0)
                ide_cd_pad_transfer(drive, xferfunc, len);
 
        if (blk_pc_request(rq)) {
                timeout = rq->timeout;
-               expiry = NULL;
        } else {
                timeout = ATAPI_WAIT_PC;
-               expiry = cdrom_timer_expiry;
+               if (!blk_fs_request(rq))
+                       expiry = cdrom_timer_expiry;
        }
 
        ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
@@ -1188,9 +1207,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 end_request:
        if (blk_pc_request(rq)) {
                unsigned long flags;
+               unsigned int dlen = rq->data_len;
+
+               if (dma)
+                       rq->data_len = 0;
 
                spin_lock_irqsave(&ide_lock, flags);
-               if (__blk_end_request(rq, 0, rq->data_len))
+               if (__blk_end_request(rq, 0, dlen))
                        BUG();
                HWGROUP(drive)->rq = NULL;
                spin_unlock_irqrestore(&ide_lock, flags);
@@ -1202,148 +1225,6 @@ end_request:
        return ide_stopped;
 }
 
-static ide_startstop_t cdrom_rw_intr(ide_drive_t *drive)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct request *rq = HWGROUP(drive)->rq;
-       xfer_func_t *xferfunc;
-       int stat, ireason, len, sectors_to_transfer, uptodate, nskip;
-       int dma_error = 0, dma = info->dma, write = rq_data_dir(rq) == WRITE;
-       u8 lowcyl = 0, highcyl = 0;
-
-       /* Check for errors. */
-       if (dma) {
-               info->dma = 0;
-               dma_error = HWIF(drive)->ide_dma_end(drive);
-               if (dma_error) {
-                       printk(KERN_ERR "%s: DMA %s error\n", drive->name,
-                                       write ? "write" : "read");
-                       ide_dma_off(drive);
-               }
-       }
-
-       if (cdrom_decode_status(drive, 0, &stat))
-               return ide_stopped;
-
-       /*
-        * using dma, transfer is complete now
-        */
-       if (dma) {
-               if (dma_error)
-                       return ide_error(drive, "dma error", stat);
-
-               ide_end_request(drive, 1, rq->nr_sectors);
-               return ide_stopped;
-       }
-
-       /* Read the interrupt reason and the transfer length. */
-       ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
-       lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-       highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-
-       len = lowcyl + (256 * highcyl);
-
-       /* If DRQ is clear, the command has completed. */
-       if ((stat & DRQ_STAT) == 0) {
-               /*
-                * If we're not done reading/writing, complain.
-                * Otherwise, complete the command normally.
-                */
-               uptodate = 1;
-               if (rq->current_nr_sectors > 0) {
-                       printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n",
-                                       drive->name, __FUNCTION__,
-                                       rq->current_nr_sectors);
-                       if (!write)
-                               rq->cmd_flags |= REQ_FAILED;
-                       uptodate = 0;
-               }
-               cdrom_end_request(drive, uptodate);
-               return ide_stopped;
-       }
-
-       sectors_to_transfer = len / SECTOR_SIZE;
-
-       /* Check that the drive is expecting to do the same thing we are. */
-       if (write) {
-               if (cdrom_write_check_ireason(drive, len, ireason))
-                       return ide_stopped;
-
-               xferfunc = HWIF(drive)->atapi_output_bytes;
-       } else {
-               if (cdrom_read_check_ireason(drive, len, ireason))
-                       return ide_stopped;
-
-               if (ide_cd_check_transfer_size(drive, len)) {
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
-               }
-
-               /*
-                * First, figure out if we need to bit-bucket
-                * any of the leading sectors.
-                */
-               nskip = min_t(int, rq->current_nr_sectors
-                                  - bio_cur_sectors(rq->bio),
-                                  sectors_to_transfer);
-
-               if (nskip > 0) {
-                       ide_cd_drain_data(drive, nskip);
-                       rq->current_nr_sectors -= nskip;
-                       sectors_to_transfer -= nskip;
-               }
-
-               xferfunc = HWIF(drive)->atapi_input_bytes;
-       }
-
-       /*
-        * now loop and read/write the data
-        */
-       while (sectors_to_transfer > 0) {
-               int this_transfer;
-
-               if (!rq->current_nr_sectors) {
-                       if (!write)
-                               /*
-                                * If the buffers are full, cache the rest
-                                * of the data in our internal buffer.
-                                */
-                               cdrom_buffer_sectors(drive, rq->sector,
-                                                    sectors_to_transfer);
-                       else
-                               printk(KERN_ERR "%s: %s: confused, missing "
-                                               "data\n",
-                                               drive->name, __FUNCTION__);
-                       break;
-               }
-
-               /*
-                * Figure out how many sectors we can transfer
-                */
-               this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors);
-
-               while (this_transfer > 0) {
-                       xferfunc(drive, rq->buffer, SECTOR_SIZE);
-                       rq->buffer += SECTOR_SIZE;
-                       --rq->nr_sectors;
-                       --rq->current_nr_sectors;
-                       ++rq->sector;
-                       --this_transfer;
-                       --sectors_to_transfer;
-               }
-
-               /*
-                * current buffer complete, move on
-                */
-               if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                       cdrom_end_request(drive, 1);
-       }
-
-       /* re-arm handler */
-       ide_set_handler(drive, cdrom_rw_intr, ATAPI_WAIT_PC, NULL);
-       return ide_started;
-}
-
 static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *cd = drive->driver_data;
@@ -1450,7 +1331,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) {
@@ -1503,7 +1384,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;
@@ -1524,85 +1405,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)
@@ -1757,7 +1559,7 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
        if (stat)
                return stat;
 
-       toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
+       toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length);
 
        if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
                toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
@@ -1818,53 +1620,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;
@@ -1904,95 +1659,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 | \
@@ -2265,6 +1931,7 @@ static const struct cd_list_entry ide_cd_quirks_list[] = {
        { "MATSHITADVD-ROM SR-8186", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { "MATSHITADVD-ROM SR-8176", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { "MATSHITADVD-ROM SR-8174", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { "Optiarc DVD RW AD-5200A", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { NULL, NULL, 0 }
 };