ide: call {in|out}put_data() methods from tf_{read|load}() methods (take 2)
[safe/jmp/linux-2.6] / drivers / ide / ide-h8300.c
1 /*
2  * H8/300 generic IDE interface
3  */
4
5 #include <linux/init.h>
6 #include <linux/ide.h>
7
8 #include <asm/io.h>
9 #include <asm/irq.h>
10
11 #define DRV_NAME "ide-h8300"
12
13 #define bswap(d) \
14 ({                                      \
15         u16 r;                          \
16         __asm__("mov.b %w1,r1h\n\t"     \
17                 "mov.b %x1,r1l\n\t"     \
18                 "mov.w r1,%0"           \
19                 :"=r"(r)                \
20                 :"r"(d)                 \
21                 :"er1");                \
22         (r);                            \
23 })
24
25 static void mm_outw(u16 d, unsigned long a)
26 {
27         __asm__("mov.b %w0,r2h\n\t"
28                 "mov.b %x0,r2l\n\t"
29                 "mov.w r2,@%1"
30                 :
31                 :"r"(d),"r"(a)
32                 :"er2");
33 }
34
35 static u16 mm_inw(unsigned long a)
36 {
37         register u16 r __asm__("er0");
38         __asm__("mov.w @%1,r2\n\t"
39                 "mov.b r2l,%x0\n\t"
40                 "mov.b r2h,%w0"
41                 :"=r"(r)
42                 :"r"(a)
43                 :"er2");
44         return r;
45 }
46
47 static void h8300_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
48 {
49         ide_hwif_t *hwif = drive->hwif;
50         struct ide_io_ports *io_ports = &hwif->io_ports;
51         struct ide_taskfile *tf = &cmd->tf;
52         u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
53
54         if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
55                 HIHI = 0xFF;
56
57         if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
58                 u8 data[2] = { tf->data, tf->hob_data };
59
60                 h8300_output_data(drive, cmd, data, 2);
61         }
62
63         if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
64                 outb(tf->hob_feature, io_ports->feature_addr);
65         if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
66                 outb(tf->hob_nsect, io_ports->nsect_addr);
67         if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
68                 outb(tf->hob_lbal, io_ports->lbal_addr);
69         if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
70                 outb(tf->hob_lbam, io_ports->lbam_addr);
71         if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
72                 outb(tf->hob_lbah, io_ports->lbah_addr);
73
74         if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
75                 outb(tf->feature, io_ports->feature_addr);
76         if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
77                 outb(tf->nsect, io_ports->nsect_addr);
78         if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
79                 outb(tf->lbal, io_ports->lbal_addr);
80         if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
81                 outb(tf->lbam, io_ports->lbam_addr);
82         if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
83                 outb(tf->lbah, io_ports->lbah_addr);
84
85         if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
86                 outb((tf->device & HIHI) | drive->select,
87                      io_ports->device_addr);
88 }
89
90 static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
91 {
92         ide_hwif_t *hwif = drive->hwif;
93         struct ide_io_ports *io_ports = &hwif->io_ports;
94         struct ide_taskfile *tf = &cmd->tf;
95
96         if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
97                 u8 data[2];
98
99                 h8300_input_data(drive, cmd, data, 2);
100
101                 tf->data = data[0];
102                 tf->hob_data = data[1];
103         }
104
105         /* be sure we're looking at the low order bits */
106         outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
107
108         if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
109                 tf->error  = inb(io_ports->feature_addr);
110         if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
111                 tf->nsect  = inb(io_ports->nsect_addr);
112         if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
113                 tf->lbal   = inb(io_ports->lbal_addr);
114         if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
115                 tf->lbam   = inb(io_ports->lbam_addr);
116         if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
117                 tf->lbah   = inb(io_ports->lbah_addr);
118         if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
119                 tf->device = inb(io_ports->device_addr);
120
121         if (cmd->tf_flags & IDE_TFLAG_LBA48) {
122                 outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
123
124                 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
125                         tf->hob_error = inb(io_ports->feature_addr);
126                 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
127                         tf->hob_nsect = inb(io_ports->nsect_addr);
128                 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
129                         tf->hob_lbal  = inb(io_ports->lbal_addr);
130                 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
131                         tf->hob_lbam  = inb(io_ports->lbam_addr);
132                 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
133                         tf->hob_lbah  = inb(io_ports->lbah_addr);
134         }
135 }
136
137 static void mm_outsw(unsigned long addr, void *buf, u32 len)
138 {
139         unsigned short *bp = (unsigned short *)buf;
140         for (; len > 0; len--, bp++)
141                 *(volatile u16 *)addr = bswap(*bp);
142 }
143
144 static void mm_insw(unsigned long addr, void *buf, u32 len)
145 {
146         unsigned short *bp = (unsigned short *)buf;
147         for (; len > 0; len--, bp++)
148                 *bp = bswap(*(volatile u16 *)addr);
149 }
150
151 static void h8300_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
152                              void *buf, unsigned int len)
153 {
154         mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
155 }
156
157 static void h8300_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
158                               void *buf, unsigned int len)
159 {
160         mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
161 }
162
163 static const struct ide_tp_ops h8300_tp_ops = {
164         .exec_command           = ide_exec_command,
165         .read_status            = ide_read_status,
166         .read_altstatus         = ide_read_altstatus,
167         .write_devctl           = ide_write_devctl,
168
169         .tf_load                = h8300_tf_load,
170         .tf_read                = h8300_tf_read,
171
172         .input_data             = h8300_input_data,
173         .output_data            = h8300_output_data,
174 };
175
176 #define H8300_IDE_GAP (2)
177
178 static inline void hw_setup(hw_regs_t *hw)
179 {
180         int i;
181
182         memset(hw, 0, sizeof(hw_regs_t));
183         for (i = 0; i <= 7; i++)
184                 hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
185         hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
186         hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
187         hw->chipset = ide_generic;
188 }
189
190 static const struct ide_port_info h8300_port_info = {
191         .tp_ops                 = &h8300_tp_ops,
192         .host_flags             = IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA,
193 };
194
195 static int __init h8300_ide_init(void)
196 {
197         hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
198
199         printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n");
200
201         if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
202                 goto out_busy;
203         if (!request_region(CONFIG_H8300_IDE_ALT, H8300_IDE_GAP, "ide-h8300")) {
204                 release_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8);
205                 goto out_busy;
206         }
207
208         hw_setup(&hw);
209
210         return ide_host_add(&h8300_port_info, hws, NULL);
211
212 out_busy:
213         printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
214
215         return -EBUSY;
216 }
217
218 module_init(h8300_ide_init);
219
220 MODULE_LICENSE("GPL");