Blame view
drivers/ide/ns87415.c
8.98 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 |
* Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com> * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be> * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2004 Grant Grundler <grundler at parisc-linux.org> * * Inspired by an earlier effort from David S. Miller <davem@redhat.com> */ |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 |
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include <linux/interrupt.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 |
#include <linux/pci.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <asm/io.h> |
ced3ec8aa ide: prefix messa... |
19 |
#define DRV_NAME "ns87415" |
1da177e4c Linux-2.6.12-rc2 |
20 21 22 23 24 25 26 27 |
#ifdef CONFIG_SUPERIO /* SUPERIO 87560 is a PoS chip that NatSem denies exists. * Unfortunately, it's built-in on all Astro-based PA-RISC workstations * which use the integrated NS87514 cell for CD-ROM support. * i.e we have to support for CD-ROM installs. * See drivers/parisc/superio.c for more gory details. */ #include <asm/superio.h> |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 32 33 34 35 |
#define SUPERIO_IDE_MAX_RETRIES 25 /* Because of a defect in Super I/O, all reads of the PCI DMA status * registers, IDE status register and the IDE select register need to be * retried */ static u8 superio_ide_inb (unsigned long port) { |
761052e67 ide: remove ->INB... |
36 37 38 39 |
u8 tmp; int retries = SUPERIO_IDE_MAX_RETRIES; /* printk(" [ reading port 0x%x with retry ] ", port); */ |
1da177e4c Linux-2.6.12-rc2 |
40 |
|
761052e67 ide: remove ->INB... |
41 42 43 44 45 46 47 |
do { tmp = inb(port); if (tmp == 0) udelay(50); } while (tmp == 0 && retries-- > 0); return tmp; |
1da177e4c Linux-2.6.12-rc2 |
48 |
} |
b73c7ee25 ide: add ->read_s... |
49 50 51 52 |
static u8 superio_read_status(ide_hwif_t *hwif) { return superio_ide_inb(hwif->io_ports.status_addr); } |
592b53152 ide: move read_sf... |
53 |
static u8 superio_dma_sff_read_status(ide_hwif_t *hwif) |
b2f951aab ide: add ->read_s... |
54 |
{ |
cab7f8eda ide: remove ->dma... |
55 |
return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS); |
b2f951aab ide: add ->read_s... |
56 |
} |
3153c26b5 ide: refactor tf_... |
57 58 |
static void superio_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) |
ea23b8ba0 ns87415: add ->tf... |
59 60 |
{ struct ide_io_ports *io_ports = &drive->hwif->io_ports; |
ea23b8ba0 ns87415: add ->tf... |
61 |
|
60f85019c ide: replace IDE_... |
62 |
if (valid & IDE_VALID_ERROR) |
676251193 ide: rename IDE_T... |
63 |
tf->error = inb(io_ports->feature_addr); |
60f85019c ide: replace IDE_... |
64 |
if (valid & IDE_VALID_NSECT) |
ea23b8ba0 ns87415: add ->tf... |
65 |
tf->nsect = inb(io_ports->nsect_addr); |
60f85019c ide: replace IDE_... |
66 |
if (valid & IDE_VALID_LBAL) |
ea23b8ba0 ns87415: add ->tf... |
67 |
tf->lbal = inb(io_ports->lbal_addr); |
60f85019c ide: replace IDE_... |
68 |
if (valid & IDE_VALID_LBAM) |
ea23b8ba0 ns87415: add ->tf... |
69 |
tf->lbam = inb(io_ports->lbam_addr); |
60f85019c ide: replace IDE_... |
70 |
if (valid & IDE_VALID_LBAH) |
ea23b8ba0 ns87415: add ->tf... |
71 |
tf->lbah = inb(io_ports->lbah_addr); |
60f85019c ide: replace IDE_... |
72 |
if (valid & IDE_VALID_DEVICE) |
ea23b8ba0 ns87415: add ->tf... |
73 |
tf->device = superio_ide_inb(io_ports->device_addr); |
ea23b8ba0 ns87415: add ->tf... |
74 |
} |
abb596b25 ide: turn selectp... |
75 |
static void ns87415_dev_select(ide_drive_t *drive); |
374e042c3 ide: add struct i... |
76 77 78 79 |
static const struct ide_tp_ops superio_tp_ops = { .exec_command = ide_exec_command, .read_status = superio_read_status, .read_altstatus = ide_read_altstatus, |
ecf3a31d2 ide: turn set_irq... |
80 |
.write_devctl = ide_write_devctl, |
374e042c3 ide: add struct i... |
81 |
|
abb596b25 ide: turn selectp... |
82 |
.dev_select = ns87415_dev_select, |
374e042c3 ide: add struct i... |
83 84 85 86 87 88 89 90 |
.tf_load = ide_tf_load, .tf_read = superio_tf_read, .input_data = ide_input_data, .output_data = ide_output_data, }; static void __devinit superio_init_iops(struct hwif_s *hwif) |
1da177e4c Linux-2.6.12-rc2 |
91 |
{ |
36501650e ide: keep pointer... |
92 |
struct pci_dev *pdev = to_pci_dev(hwif->dev); |
761052e67 ide: remove ->INB... |
93 |
u32 dma_stat; |
36501650e ide: keep pointer... |
94 |
u8 port = hwif->channel, tmp; |
1da177e4c Linux-2.6.12-rc2 |
95 |
|
761052e67 ide: remove ->INB... |
96 |
dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa); |
1da177e4c Linux-2.6.12-rc2 |
97 98 |
/* Clear error/interrupt, enable dma */ |
761052e67 ide: remove ->INB... |
99 100 |
tmp = superio_ide_inb(dma_stat); outb(tmp | 0x66, dma_stat); |
1da177e4c Linux-2.6.12-rc2 |
101 |
} |
592b53152 ide: move read_sf... |
102 103 |
#else #define superio_dma_sff_read_status ide_dma_sff_read_status |
1da177e4c Linux-2.6.12-rc2 |
104 105 106 107 108 |
#endif static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; /* |
97100fc81 ide: add device f... |
109 |
* This routine either enables/disables (according to IDE_DFLAG_PRESENT) |
898ec223f ide: remove HWIF(... |
110 |
* the IRQ associated with the port, |
1da177e4c Linux-2.6.12-rc2 |
111 112 113 114 |
* and selects either PIO or DMA handshaking for the next I/O operation. */ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { |
898ec223f ide: remove HWIF(... |
115 |
ide_hwif_t *hwif = drive->hwif; |
36501650e ide: keep pointer... |
116 |
struct pci_dev *dev = to_pci_dev(hwif->dev); |
1da177e4c Linux-2.6.12-rc2 |
117 |
unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; |
1da177e4c Linux-2.6.12-rc2 |
118 119 120 121 122 123 124 |
unsigned long flags; local_irq_save(flags); new = *old; /* Adjust IRQ enable bit */ bit = 1 << (8 + hwif->channel); |
97100fc81 ide: add device f... |
125 126 127 128 129 |
if (drive->dev_flags & IDE_DFLAG_PRESENT) new &= ~bit; else new |= bit; |
1da177e4c Linux-2.6.12-rc2 |
130 131 |
/* Select PIO or DMA, DMA may only be selected for one drive/channel. */ |
123995b97 ide: use 'drive->... |
132 133 |
bit = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1)); other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1)); |
1da177e4c Linux-2.6.12-rc2 |
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
new = use_dma ? ((new & ~other) | bit) : (new & ~bit); if (new != *old) { unsigned char stat; /* * Don't change DMA engine settings while Write Buffers * are busy. */ (void) pci_read_config_byte(dev, 0x43, &stat); while (stat & 0x03) { udelay(1); (void) pci_read_config_byte(dev, 0x43, &stat); } *old = new; (void) pci_write_config_dword(dev, 0x40, new); /* * And let things settle... */ udelay(10); } local_irq_restore(flags); } |
abb596b25 ide: turn selectp... |
160 |
static void ns87415_dev_select(ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
161 |
{ |
97100fc81 ide: add device f... |
162 163 |
ns87415_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); |
abb596b25 ide: turn selectp... |
164 165 |
outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); |
1da177e4c Linux-2.6.12-rc2 |
166 |
} |
a6d67ffa7 ns87415: use cust... |
167 168 169 170 171 |
static void ns87415_dma_start(ide_drive_t *drive) { ns87415_prepare_drive(drive, 1); ide_dma_start(drive); } |
5e37bdc08 ide: add struct i... |
172 |
static int ns87415_dma_end(ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
173 |
{ |
898ec223f ide: remove HWIF(... |
174 |
ide_hwif_t *hwif = drive->hwif; |
1da177e4c Linux-2.6.12-rc2 |
175 |
u8 dma_stat = 0, dma_cmd = 0; |
592b53152 ide: move read_sf... |
176 |
dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); |
cab7f8eda ide: remove ->dma... |
177 178 |
/* get DMA command mode */ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); |
1da177e4c Linux-2.6.12-rc2 |
179 |
/* stop DMA */ |
cab7f8eda ide: remove ->dma... |
180 |
outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); |
1da177e4c Linux-2.6.12-rc2 |
181 |
/* from ERRATA: clear the INTR & ERROR bits */ |
cab7f8eda ide: remove ->dma... |
182 183 |
dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD); |
1da177e4c Linux-2.6.12-rc2 |
184 |
|
1da177e4c Linux-2.6.12-rc2 |
185 |
ns87415_prepare_drive(drive, 0); |
a6d67ffa7 ns87415: use cust... |
186 187 188 |
/* verify good DMA status */ return (dma_stat & 7) != 4; |
1da177e4c Linux-2.6.12-rc2 |
189 |
} |
c20530ed2 [PATCH] ide: hotp... |
190 |
static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) |
1da177e4c Linux-2.6.12-rc2 |
191 |
{ |
36501650e ide: keep pointer... |
192 |
struct pci_dev *dev = to_pci_dev(hwif->dev); |
1da177e4c Linux-2.6.12-rc2 |
193 194 195 196 197 198 |
unsigned int ctrl, using_inta; u8 progif; #ifdef __sparc_v9__ int timeout; u8 stat; #endif |
1da177e4c Linux-2.6.12-rc2 |
199 200 201 202 203 |
/* * We cannot probe for IRQ: both ports share common IRQ on INTA. * Also, leave IRQ masked during drive probing, to prevent infinite * interrupts from a potentially floating INTA.. * |
abb596b25 ide: turn selectp... |
204 |
* IRQs get unmasked in dev_select() when drive is first used. |
1da177e4c Linux-2.6.12-rc2 |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
*/ (void) pci_read_config_dword(dev, 0x40, &ctrl); (void) pci_read_config_byte(dev, 0x09, &progif); /* is irq in "native" mode? */ using_inta = progif & (1 << (hwif->channel << 1)); if (!using_inta) using_inta = ctrl & (1 << (4 + hwif->channel)); if (hwif->mate) { hwif->select_data = hwif->mate->select_data; } else { hwif->select_data = (unsigned long) &ns87415_control[ns87415_count++]; ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */ if (using_inta) ctrl &= ~(1 << 6); /* unmask INTA */ *((unsigned int *)hwif->select_data) = ctrl; (void) pci_write_config_dword(dev, 0x40, ctrl); /* * Set prefetch size to 512 bytes for both ports, * but don't turn on/off prefetching here. */ pci_write_config_byte(dev, 0x55, 0xee); #ifdef __sparc_v9__ /* |
9d501529b ide: make probe_h... |
231 |
* XXX: Reset the device, if we don't it will not respond to |
fdd88f0af ide: inline SELEC... |
232 |
* dev_select() properly during first ide_probe_port(). |
1da177e4c Linux-2.6.12-rc2 |
233 234 |
*/ timeout = 10000; |
4c3032d8a ide: add struct i... |
235 |
outb(12, hwif->io_ports.ctl_addr); |
1da177e4c Linux-2.6.12-rc2 |
236 |
udelay(10); |
4c3032d8a ide: add struct i... |
237 |
outb(8, hwif->io_ports.ctl_addr); |
1da177e4c Linux-2.6.12-rc2 |
238 239 |
do { udelay(50); |
374e042c3 ide: add struct i... |
240 |
stat = hwif->tp_ops->read_status(hwif); |
3a7d24841 ide: use ATA_* de... |
241 242 243 |
if (stat == 0xff) break; } while ((stat & ATA_BUSY) && --timeout); |
1da177e4c Linux-2.6.12-rc2 |
244 245 246 247 |
#endif } if (!using_inta) |
973d9e743 ns87415: use pci_... |
248 |
hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel); |
1da177e4c Linux-2.6.12-rc2 |
249 250 251 |
if (!hwif->dma_base) return; |
cab7f8eda ide: remove ->dma... |
252 |
outb(0x60, hwif->dma_base + ATA_DMA_STATUS); |
1da177e4c Linux-2.6.12-rc2 |
253 |
} |
abb596b25 ide: turn selectp... |
254 255 256 257 258 259 260 261 262 263 264 265 |
static const struct ide_tp_ops ns87415_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, .write_devctl = ide_write_devctl, .dev_select = ns87415_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, .input_data = ide_input_data, .output_data = ide_output_data, |
ac95beedf ide: add struct i... |
266 |
}; |
f37afdaca ide: constify str... |
267 268 |
static const struct ide_dma_ops ns87415_dma_ops = { .dma_host_set = ide_dma_host_set, |
a6d67ffa7 ns87415: use cust... |
269 270 |
.dma_setup = ide_dma_setup, .dma_start = ns87415_dma_start, |
5e37bdc08 ide: add struct i... |
271 |
.dma_end = ns87415_dma_end, |
f37afdaca ide: constify str... |
272 273 |
.dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, |
22117d6ea ide: add ->dma_ti... |
274 |
.dma_timer_expiry = ide_dma_sff_timer_expiry, |
592b53152 ide: move read_sf... |
275 |
.dma_sff_read_status = superio_dma_sff_read_status, |
5e37bdc08 ide: add struct i... |
276 |
}; |
856204360 ide: constify str... |
277 |
static const struct ide_port_info ns87415_chipset __devinitdata = { |
ced3ec8aa ide: prefix messa... |
278 |
.name = DRV_NAME, |
1da177e4c Linux-2.6.12-rc2 |
279 |
.init_hwif = init_hwif_ns87415, |
abb596b25 ide: turn selectp... |
280 |
.tp_ops = &ns87415_tp_ops, |
5e37bdc08 ide: add struct i... |
281 |
.dma_ops = &ns87415_dma_ops, |
33c1002ed ide: add IDE_HFLA... |
282 |
.host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | |
5e71d9c5a ide: IDE_HFLAG_BO... |
283 |
IDE_HFLAG_NO_ATAPI_DMA, |
1da177e4c Linux-2.6.12-rc2 |
284 285 286 287 |
}; static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id) { |
374e042c3 ide: add struct i... |
288 289 290 291 292 293 294 295 296 |
struct ide_port_info d = ns87415_chipset; #ifdef CONFIG_SUPERIO if (PCI_SLOT(dev->devfn) == 0xE) { /* Built-in - assume it's under superio. */ d.init_iops = superio_init_iops; d.tp_ops = &superio_tp_ops; } #endif |
6cdf6eb35 ide: add ->dev an... |
297 |
return ide_pci_init_one(dev, &d, NULL); |
1da177e4c Linux-2.6.12-rc2 |
298 |
} |
9cbcc5e3c ide: use PCI_VDEV... |
299 300 |
static const struct pci_device_id ns87415_pci_tbl[] = { { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 }, |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 |
{ 0, }, }; MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); |
a9ab09e26 ide: use unique n... |
304 |
static struct pci_driver ns87415_pci_driver = { |
1da177e4c Linux-2.6.12-rc2 |
305 306 307 |
.name = "NS87415_IDE", .id_table = ns87415_pci_tbl, .probe = ns87415_init_one, |
aa6e518d7 ns87415: add ->re... |
308 |
.remove = ide_pci_remove, |
feb22b7f8 ide: add proper P... |
309 310 |
.suspend = ide_pci_suspend, .resume = ide_pci_resume, |
1da177e4c Linux-2.6.12-rc2 |
311 |
}; |
82ab1eece ide: add missing ... |
312 |
static int __init ns87415_ide_init(void) |
1da177e4c Linux-2.6.12-rc2 |
313 |
{ |
a9ab09e26 ide: use unique n... |
314 |
return ide_pci_register_driver(&ns87415_pci_driver); |
1da177e4c Linux-2.6.12-rc2 |
315 |
} |
aa6e518d7 ns87415: add ->re... |
316 317 |
static void __exit ns87415_ide_exit(void) { |
a9ab09e26 ide: use unique n... |
318 |
pci_unregister_driver(&ns87415_pci_driver); |
aa6e518d7 ns87415: add ->re... |
319 |
} |
1da177e4c Linux-2.6.12-rc2 |
320 |
module_init(ns87415_ide_init); |
aa6e518d7 ns87415: add ->re... |
321 |
module_exit(ns87415_ide_exit); |
1da177e4c Linux-2.6.12-rc2 |
322 323 324 325 |
MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick"); MODULE_DESCRIPTION("PCI driver module for NS87415 IDE"); MODULE_LICENSE("GPL"); |