1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#define TRM290_NO_DMA_WRITES
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131#include <linux/types.h>
132#include <linux/module.h>
133#include <linux/kernel.h>
134#include <linux/ioport.h>
135#include <linux/interrupt.h>
136#include <linux/blkdev.h>
137#include <linux/init.h>
138#include <linux/pci.h>
139#include <linux/ide.h>
140
141#include <asm/io.h>
142
143#define DRV_NAME "trm290"
144
145static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
146{
147 ide_hwif_t *hwif = drive->hwif;
148 u16 reg = 0;
149 unsigned long flags;
150
151
152 reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
153
154 local_irq_save(flags);
155
156 if (reg != hwif->select_data) {
157 hwif->select_data = reg;
158
159 outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
160 outw(reg & 0xff, hwif->config_data);
161 }
162
163
164 if (drive->dev_flags & IDE_DFLAG_PRESENT) {
165 reg = inw(hwif->config_data + 3);
166 reg &= 0x13;
167 reg &= ~(1 << hwif->channel);
168 outw(reg, hwif->config_data + 3);
169 }
170
171 local_irq_restore(flags);
172}
173
174static void trm290_dev_select(ide_drive_t *drive)
175{
176 trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
177
178 outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
179}
180
181static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
182{
183 if (cmd->tf_flags & IDE_TFLAG_WRITE) {
184#ifdef TRM290_NO_DMA_WRITES
185
186 return 1;
187#endif
188 }
189 return 0;
190}
191
192static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
193{
194 ide_hwif_t *hwif = drive->hwif;
195 unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2;
196
197 count = ide_build_dmatable(drive, cmd);
198 if (count == 0)
199
200 return 1;
201
202 outl(hwif->dmatable_dma | rw, hwif->dma_base);
203
204 outw(count * 2 - 1, hwif->dma_base + 2);
205
206 return 0;
207}
208
209static void trm290_dma_start(ide_drive_t *drive)
210{
211 trm290_prepare_drive(drive, 1);
212}
213
214static int trm290_dma_end(ide_drive_t *drive)
215{
216 u16 status = inw(drive->hwif->dma_base + 2);
217
218 trm290_prepare_drive(drive, 0);
219
220 return status != 0x00ff;
221}
222
223static int trm290_dma_test_irq(ide_drive_t *drive)
224{
225 u16 status = inw(drive->hwif->dma_base + 2);
226
227 return status == 0x00ff;
228}
229
230static void trm290_dma_host_set(ide_drive_t *drive, int on)
231{
232}
233
234static void init_hwif_trm290(ide_hwif_t *hwif)
235{
236 struct pci_dev *dev = to_pci_dev(hwif->dev);
237 unsigned int cfg_base = pci_resource_start(dev, 4);
238 unsigned long flags;
239 u8 reg = 0;
240
241 if ((dev->class & 5) && cfg_base)
242 printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev));
243 else {
244 cfg_base = 0x3df0;
245 printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev));
246 }
247 printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
248 hwif->config_data = cfg_base;
249 hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
250
251 printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
252 hwif->name, hwif->dma_base, hwif->dma_base + 3);
253
254 if (ide_allocate_dma_engine(hwif))
255 return;
256
257 local_irq_save(flags);
258
259 outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
260
261 hwif->select_data = 0x21;
262 outb(hwif->select_data, hwif->config_data);
263
264 reg = inb(hwif->config_data + 3);
265
266 reg = (reg & 0x10) | 0x03;
267 outb(reg, hwif->config_data + 3);
268 local_irq_restore(flags);
269
270 if (reg & 0x10)
271
272 hwif->irq = hwif->channel ? 15 : 14;
273
274#if 1
275 {
276
277
278
279
280
281 u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
282 static u16 next_offset = 0;
283 u8 old_mask;
284
285 outb(0x54 | (hwif->channel << 3), hwif->config_data + 1);
286 old = inw(hwif->config_data);
287 old &= ~1;
288 old_mask = inb(old + 2);
289 if (old != compat && old_mask == 0xff) {
290
291 compat += (next_offset += 0x400);
292 hwif->io_ports.ctl_addr = compat + 2;
293 outw(compat | 1, hwif->config_data);
294 new = inw(hwif->config_data);
295 printk(KERN_INFO "%s: control basereg workaround: "
296 "old=0x%04x, new=0x%04x\n",
297 hwif->name, old, new & ~1);
298 }
299 }
300#endif
301}
302
303static const struct ide_tp_ops trm290_tp_ops = {
304 .exec_command = ide_exec_command,
305 .read_status = ide_read_status,
306 .read_altstatus = ide_read_altstatus,
307 .write_devctl = ide_write_devctl,
308
309 .dev_select = trm290_dev_select,
310 .tf_load = ide_tf_load,
311 .tf_read = ide_tf_read,
312
313 .input_data = ide_input_data,
314 .output_data = ide_output_data,
315};
316
317static struct ide_dma_ops trm290_dma_ops = {
318 .dma_host_set = trm290_dma_host_set,
319 .dma_setup = trm290_dma_setup,
320 .dma_start = trm290_dma_start,
321 .dma_end = trm290_dma_end,
322 .dma_test_irq = trm290_dma_test_irq,
323 .dma_lost_irq = ide_dma_lost_irq,
324 .dma_check = trm290_dma_check,
325};
326
327static const struct ide_port_info trm290_chipset = {
328 .name = DRV_NAME,
329 .init_hwif = init_hwif_trm290,
330 .tp_ops = &trm290_tp_ops,
331 .dma_ops = &trm290_dma_ops,
332 .host_flags = IDE_HFLAG_TRM290 |
333 IDE_HFLAG_NO_ATAPI_DMA |
334#if 0
335 IDE_HFLAG_TRUST_BIOS_FOR_DMA |
336#endif
337 IDE_HFLAG_NO_AUTODMA |
338 IDE_HFLAG_NO_LBA48,
339};
340
341static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
342{
343 return ide_pci_init_one(dev, &trm290_chipset, NULL);
344}
345
346static const struct pci_device_id trm290_pci_tbl[] = {
347 { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 },
348 { 0, },
349};
350MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
351
352static struct pci_driver trm290_pci_driver = {
353 .name = "TRM290_IDE",
354 .id_table = trm290_pci_tbl,
355 .probe = trm290_init_one,
356 .remove = ide_pci_remove,
357};
358
359static int __init trm290_ide_init(void)
360{
361 return ide_pci_register_driver(&trm290_pci_driver);
362}
363
364static void __exit trm290_ide_exit(void)
365{
366 pci_unregister_driver(&trm290_pci_driver);
367}
368
369module_init(trm290_ide_init);
370module_exit(trm290_ide_exit);
371
372MODULE_AUTHOR("Mark Lord");
373MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
374MODULE_LICENSE("GPL");
375