Skip to content

Commit

Permalink
via82cxxx: workaround h/w bugs
Browse files Browse the repository at this point in the history
Add custom struct ide_tp_ops instance to fix the internal bug of some VIA
chipsets which will reset the device register after changing the nIEN bit
in the device control register.

Based on commit bfce5e0 for pata_via host driver.

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bartlomiej Zolnierkiewicz authored and David S. Miller committed Jan 19, 2010
1 parent a13e486 commit f931a5d
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions drivers/ide/via82cxxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ struct via82cxxx_dev
{
struct via_isa_bridge *via_config;
unsigned int via_80w;
u8 cached_device[2];
};

/**
Expand Down Expand Up @@ -382,10 +383,66 @@ static const struct ide_port_ops via_port_ops = {
.cable_detect = via82cxxx_cable_detect,
};

static void via_write_devctl(ide_hwif_t *hwif, u8 ctl)
{
struct via82cxxx_dev *vdev = hwif->host->host_priv;

outb(ctl, hwif->io_ports.ctl_addr);
outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr);
}

static void __via_dev_select(ide_drive_t *drive, u8 select)
{
ide_hwif_t *hwif = drive->hwif;
struct via82cxxx_dev *vdev = hwif->host->host_priv;

outb(select, hwif->io_ports.device_addr);
vdev->cached_device[hwif->channel] = select;
}

static void via_dev_select(ide_drive_t *drive)
{
__via_dev_select(drive, drive->select | ATA_DEVICE_OBS);
}

static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
{
ide_hwif_t *hwif = drive->hwif;
struct ide_io_ports *io_ports = &hwif->io_ports;

if (valid & IDE_VALID_FEATURE)
outb(tf->feature, io_ports->feature_addr);
if (valid & IDE_VALID_NSECT)
outb(tf->nsect, io_ports->nsect_addr);
if (valid & IDE_VALID_LBAL)
outb(tf->lbal, io_ports->lbal_addr);
if (valid & IDE_VALID_LBAM)
outb(tf->lbam, io_ports->lbam_addr);
if (valid & IDE_VALID_LBAH)
outb(tf->lbah, io_ports->lbah_addr);
if (valid & IDE_VALID_DEVICE)
__via_dev_select(drive, tf->device);
}

const struct ide_tp_ops via_tp_ops = {
.exec_command = ide_exec_command,
.read_status = ide_read_status,
.read_altstatus = ide_read_altstatus,
.write_devctl = via_write_devctl,

.dev_select = via_dev_select,
.tf_load = via_tf_load,
.tf_read = ide_tf_read,

.input_data = ide_input_data,
.output_data = ide_output_data,
};

static const struct ide_port_info via82cxxx_chipset __devinitdata = {
.name = DRV_NAME,
.init_chipset = init_chipset_via82cxxx,
.enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
.tp_ops = &via_tp_ops,
.port_ops = &via_port_ops,
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
IDE_HFLAG_POST_SET_MODE |
Expand Down

0 comments on commit f931a5d

Please sign in to comment.