Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux...
[pandora-kernel.git] / drivers / ide / ide-iops.c
index dfe47d5..57d9a9a 100644 (file)
@@ -37,11 +37,6 @@ static u8 ide_inb (unsigned long port)
        return (u8) inb(port);
 }
 
-static u16 ide_inw (unsigned long port)
-{
-       return (u16) inw(port);
-}
-
 static void ide_outb (u8 val, unsigned long port)
 {
        outb(val, port);
@@ -52,18 +47,11 @@ static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port)
        outb(addr, port);
 }
 
-static void ide_outw (u16 val, unsigned long port)
-{
-       outw(val, port);
-}
-
 void default_hwif_iops (ide_hwif_t *hwif)
 {
        hwif->OUTB      = ide_outb;
        hwif->OUTBSYNC  = ide_outbsync;
-       hwif->OUTW      = ide_outw;
        hwif->INB       = ide_inb;
-       hwif->INW       = ide_inw;
 }
 
 /*
@@ -75,11 +63,6 @@ static u8 ide_mm_inb (unsigned long port)
        return (u8) readb((void __iomem *) port);
 }
 
-static u16 ide_mm_inw (unsigned long port)
-{
-       return (u16) readw((void __iomem *) port);
-}
-
 static void ide_mm_outb (u8 value, unsigned long port)
 {
        writeb(value, (void __iomem *) port);
@@ -90,20 +73,13 @@ static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
        writeb(value, (void __iomem *) port);
 }
 
-static void ide_mm_outw (u16 value, unsigned long port)
-{
-       writew(value, (void __iomem *) port);
-}
-
 void default_hwif_mmiops (ide_hwif_t *hwif)
 {
        hwif->OUTB      = ide_mm_outb;
        /* Most systems will need to override OUTBSYNC, alas however
           this one is controller specific! */
        hwif->OUTBSYNC  = ide_mm_outbsync;
-       hwif->OUTW      = ide_mm_outw;
        hwif->INB       = ide_mm_inb;
-       hwif->INW       = ide_mm_inw;
 }
 
 EXPORT_SYMBOL(default_hwif_mmiops);
@@ -127,6 +103,123 @@ void SELECT_MASK (ide_drive_t *drive, int mask)
                port_ops->maskproc(drive, mask);
 }
 
+static void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       struct ide_taskfile *tf = &task->tf;
+       void (*tf_outb)(u8 addr, unsigned long port);
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+       u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+       if (mmio)
+               tf_outb = ide_mm_outb;
+       else
+               tf_outb = ide_outb;
+
+       if (task->tf_flags & IDE_TFLAG_FLAGGED)
+               HIHI = 0xFF;
+
+       ide_set_irq(drive, 1);
+
+       if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
+               SELECT_MASK(drive, 0);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+               u16 data = (tf->hob_data << 8) | tf->data;
+
+               if (mmio)
+                       writew(data, (void __iomem *)io_ports->data_addr);
+               else
+                       outw(data, io_ports->data_addr);
+       }
+
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+               tf_outb(tf->hob_feature, io_ports->feature_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+               tf_outb(tf->hob_nsect, io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+               tf_outb(tf->hob_lbal, io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+               tf_outb(tf->hob_lbam, io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+               tf_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+               tf_outb(tf->feature, io_ports->feature_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+               tf_outb(tf->nsect, io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+               tf_outb(tf->lbal, io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+               tf_outb(tf->lbam, io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+               tf_outb(tf->lbah, io_ports->lbah_addr);
+
+       if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+               tf_outb((tf->device & HIHI) | drive->select.all,
+                        io_ports->device_addr);
+}
+
+static void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       struct ide_taskfile *tf = &task->tf;
+       void (*tf_outb)(u8 addr, unsigned long port);
+       u8 (*tf_inb)(unsigned long port);
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+       if (mmio) {
+               tf_outb = ide_mm_outb;
+               tf_inb  = ide_mm_inb;
+       } else {
+               tf_outb = ide_outb;
+               tf_inb  = ide_inb;
+       }
+
+       if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+               u16 data;
+
+               if (mmio)
+                       data = readw((void __iomem *)io_ports->data_addr);
+               else
+                       data = inw(io_ports->data_addr);
+
+               tf->data = data & 0xff;
+               tf->hob_data = (data >> 8) & 0xff;
+       }
+
+       /* be sure we're looking at the low order bits */
+       tf_outb(drive->ctl & ~0x80, io_ports->ctl_addr);
+
+       if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+               tf->nsect  = tf_inb(io_ports->nsect_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+               tf->lbal   = tf_inb(io_ports->lbal_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+               tf->lbam   = tf_inb(io_ports->lbam_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+               tf->lbah   = tf_inb(io_ports->lbah_addr);
+       if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+               tf->device = tf_inb(io_ports->device_addr);
+
+       if (task->tf_flags & IDE_TFLAG_LBA48) {
+               tf_outb(drive->ctl | 0x80, io_ports->ctl_addr);
+
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+                       tf->hob_feature = tf_inb(io_ports->feature_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+                       tf->hob_nsect   = tf_inb(io_ports->nsect_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+                       tf->hob_lbal    = tf_inb(io_ports->lbal_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+                       tf->hob_lbam    = tf_inb(io_ports->lbam_addr);
+               if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+                       tf->hob_lbah    = tf_inb(io_ports->lbah_addr);
+       }
+}
+
 /*
  * Some localbus EIDE interfaces require a special access sequence
  * when using 32-bit I/O instructions to transfer data.  We call this
@@ -134,11 +227,11 @@ void SELECT_MASK (ide_drive_t *drive, int mask)
  * of the sector count register location, with interrupts disabled
  * to ensure that the reads all happen together.
  */
-static void ata_vlb_sync(ide_drive_t *drive, unsigned long port)
+static void ata_vlb_sync(unsigned long port)
 {
-       (void) HWIF(drive)->INB(port);
-       (void) HWIF(drive)->INB(port);
-       (void) HWIF(drive)->INB(port);
+       (void)inb(port);
+       (void)inb(port);
+       (void)inb(port);
 }
 
 /*
@@ -162,9 +255,9 @@ static void ata_input_data(ide_drive_t *drive, struct request *rq,
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
-               if (io_32bit & 2) {
+               if ((io_32bit & 2) && !mmio) {
                        local_irq_save(flags);
-                       ata_vlb_sync(drive, io_ports->nsect_addr);
+                       ata_vlb_sync(io_ports->nsect_addr);
                }
 
                if (mmio)
@@ -172,7 +265,7 @@ static void ata_input_data(ide_drive_t *drive, struct request *rq,
                else
                        insl(data_addr, buf, len / 4);
 
-               if (io_32bit & 2)
+               if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
                if ((len & 3) >= 2) {
@@ -205,9 +298,9 @@ static void ata_output_data(ide_drive_t *drive, struct request *rq,
        if (io_32bit) {
                unsigned long uninitialized_var(flags);
 
-               if (io_32bit & 2) {
+               if ((io_32bit & 2) && !mmio) {
                        local_irq_save(flags);
-                       ata_vlb_sync(drive, io_ports->nsect_addr);
+                       ata_vlb_sync(io_ports->nsect_addr);
                }
 
                if (mmio)
@@ -215,7 +308,7 @@ static void ata_output_data(ide_drive_t *drive, struct request *rq,
                else
                        outsl(data_addr, buf, len / 4);
 
-               if (io_32bit & 2)
+               if ((io_32bit & 2) && !mmio)
                        local_irq_restore(flags);
 
                if ((len & 3) >= 2) {
@@ -235,6 +328,9 @@ static void ata_output_data(ide_drive_t *drive, struct request *rq,
 
 void default_hwif_transport(ide_hwif_t *hwif)
 {
+       hwif->tf_load     = ide_tf_load;
+       hwif->tf_read     = ide_tf_read;
+
        hwif->input_data  = ata_input_data;
        hwif->output_data = ata_output_data;
 }
@@ -529,6 +625,8 @@ static const struct drive_list_entry ivb_list[] = {
        { "TSSTcorp CDDVDW SH-S202J"    , "SB01"        },
        { "TSSTcorp CDDVDW SH-S202N"    , "SB00"        },
        { "TSSTcorp CDDVDW SH-S202N"    , "SB01"        },
+       { "TSSTcorp CDDVDW SH-S202H"    , "SB00"        },
+       { "TSSTcorp CDDVDW SH-S202H"    , "SB01"        },
        { NULL                          , NULL          }
 };