diff options
Diffstat (limited to 'drivers/block/paride/friq.c')
-rw-r--r-- | drivers/block/paride/friq.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/drivers/block/paride/friq.c b/drivers/block/paride/friq.c new file mode 100644 index 000000000000..5ea2904d2815 --- /dev/null +++ b/drivers/block/paride/friq.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | friq.c (c) 1998 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License | ||
4 | |||
5 | friq.c is a low-level protocol driver for the Freecom "IQ" | ||
6 | parallel port IDE adapter. Early versions of this adapter | ||
7 | use the 'frpw' protocol. | ||
8 | |||
9 | Freecom uses this adapter in a battery powered external | ||
10 | CD-ROM drive. It is also used in LS-120 drives by | ||
11 | Maxell and Panasonic, and other devices. | ||
12 | |||
13 | The battery powered drive requires software support to | ||
14 | control the power to the drive. This module enables the | ||
15 | drive power when the high level driver (pcd) is loaded | ||
16 | and disables it when the module is unloaded. Note, if | ||
17 | the friq module is built in to the kernel, the power | ||
18 | will never be switched off, so other means should be | ||
19 | used to conserve battery power. | ||
20 | |||
21 | */ | ||
22 | |||
23 | /* Changes: | ||
24 | |||
25 | 1.01 GRG 1998.12.20 Added support for soft power switch | ||
26 | */ | ||
27 | |||
28 | #define FRIQ_VERSION "1.01" | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <asm/io.h> | ||
37 | |||
38 | #include "paride.h" | ||
39 | |||
40 | #define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\ | ||
41 | w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x); | ||
42 | |||
43 | #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0)) | ||
44 | |||
45 | /* cont = 0 - access the IDE register file | ||
46 | cont = 1 - access the IDE command set | ||
47 | */ | ||
48 | |||
49 | static int cont_map[2] = { 0x08, 0x10 }; | ||
50 | |||
51 | static int friq_read_regr( PIA *pi, int cont, int regr ) | ||
52 | |||
53 | { int h,l,r; | ||
54 | |||
55 | r = regr + cont_map[cont]; | ||
56 | |||
57 | CMD(r); | ||
58 | w2(6); l = r1(); | ||
59 | w2(4); h = r1(); | ||
60 | w2(4); | ||
61 | |||
62 | return j44(l,h); | ||
63 | |||
64 | } | ||
65 | |||
66 | static void friq_write_regr( PIA *pi, int cont, int regr, int val) | ||
67 | |||
68 | { int r; | ||
69 | |||
70 | r = regr + cont_map[cont]; | ||
71 | |||
72 | CMD(r); | ||
73 | w0(val); | ||
74 | w2(5);w2(7);w2(5);w2(4); | ||
75 | } | ||
76 | |||
77 | static void friq_read_block_int( PIA *pi, char * buf, int count, int regr ) | ||
78 | |||
79 | { int h, l, k, ph; | ||
80 | |||
81 | switch(pi->mode) { | ||
82 | |||
83 | case 0: CMD(regr); | ||
84 | for (k=0;k<count;k++) { | ||
85 | w2(6); l = r1(); | ||
86 | w2(4); h = r1(); | ||
87 | buf[k] = j44(l,h); | ||
88 | } | ||
89 | w2(4); | ||
90 | break; | ||
91 | |||
92 | case 1: ph = 2; | ||
93 | CMD(regr+0xc0); | ||
94 | w0(0xff); | ||
95 | for (k=0;k<count;k++) { | ||
96 | w2(0xa4 + ph); | ||
97 | buf[k] = r0(); | ||
98 | ph = 2 - ph; | ||
99 | } | ||
100 | w2(0xac); w2(0xa4); w2(4); | ||
101 | break; | ||
102 | |||
103 | case 2: CMD(regr+0x80); | ||
104 | for (k=0;k<count-2;k++) buf[k] = r4(); | ||
105 | w2(0xac); w2(0xa4); | ||
106 | buf[count-2] = r4(); | ||
107 | buf[count-1] = r4(); | ||
108 | w2(4); | ||
109 | break; | ||
110 | |||
111 | case 3: CMD(regr+0x80); | ||
112 | for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w(); | ||
113 | w2(0xac); w2(0xa4); | ||
114 | buf[count-2] = r4(); | ||
115 | buf[count-1] = r4(); | ||
116 | w2(4); | ||
117 | break; | ||
118 | |||
119 | case 4: CMD(regr+0x80); | ||
120 | for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l(); | ||
121 | buf[count-4] = r4(); | ||
122 | buf[count-3] = r4(); | ||
123 | w2(0xac); w2(0xa4); | ||
124 | buf[count-2] = r4(); | ||
125 | buf[count-1] = r4(); | ||
126 | w2(4); | ||
127 | break; | ||
128 | |||
129 | } | ||
130 | } | ||
131 | |||
132 | static void friq_read_block( PIA *pi, char * buf, int count) | ||
133 | |||
134 | { friq_read_block_int(pi,buf,count,0x08); | ||
135 | } | ||
136 | |||
137 | static void friq_write_block( PIA *pi, char * buf, int count ) | ||
138 | |||
139 | { int k; | ||
140 | |||
141 | switch(pi->mode) { | ||
142 | |||
143 | case 0: | ||
144 | case 1: CMD(8); w2(5); | ||
145 | for (k=0;k<count;k++) { | ||
146 | w0(buf[k]); | ||
147 | w2(7);w2(5); | ||
148 | } | ||
149 | w2(4); | ||
150 | break; | ||
151 | |||
152 | case 2: CMD(0xc8); w2(5); | ||
153 | for (k=0;k<count;k++) w4(buf[k]); | ||
154 | w2(4); | ||
155 | break; | ||
156 | |||
157 | case 3: CMD(0xc8); w2(5); | ||
158 | for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); | ||
159 | w2(4); | ||
160 | break; | ||
161 | |||
162 | case 4: CMD(0xc8); w2(5); | ||
163 | for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); | ||
164 | w2(4); | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static void friq_connect ( PIA *pi ) | ||
170 | |||
171 | { pi->saved_r0 = r0(); | ||
172 | pi->saved_r2 = r2(); | ||
173 | w2(4); | ||
174 | } | ||
175 | |||
176 | static void friq_disconnect ( PIA *pi ) | ||
177 | |||
178 | { CMD(0x20); | ||
179 | w0(pi->saved_r0); | ||
180 | w2(pi->saved_r2); | ||
181 | } | ||
182 | |||
183 | static int friq_test_proto( PIA *pi, char * scratch, int verbose ) | ||
184 | |||
185 | { int j, k, r; | ||
186 | int e[2] = {0,0}; | ||
187 | |||
188 | pi->saved_r0 = r0(); | ||
189 | w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */ | ||
190 | udelay(500); | ||
191 | w0(pi->saved_r0); | ||
192 | |||
193 | friq_connect(pi); | ||
194 | for (j=0;j<2;j++) { | ||
195 | friq_write_regr(pi,0,6,0xa0+j*0x10); | ||
196 | for (k=0;k<256;k++) { | ||
197 | friq_write_regr(pi,0,2,k^0xaa); | ||
198 | friq_write_regr(pi,0,3,k^0x55); | ||
199 | if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++; | ||
200 | } | ||
201 | } | ||
202 | friq_disconnect(pi); | ||
203 | |||
204 | friq_connect(pi); | ||
205 | friq_read_block_int(pi,scratch,512,0x10); | ||
206 | r = 0; | ||
207 | for (k=0;k<128;k++) if (scratch[k] != k) r++; | ||
208 | friq_disconnect(pi); | ||
209 | |||
210 | if (verbose) { | ||
211 | printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n", | ||
212 | pi->device,pi->port,pi->mode,e[0],e[1],r); | ||
213 | } | ||
214 | |||
215 | return (r || (e[0] && e[1])); | ||
216 | } | ||
217 | |||
218 | |||
219 | static void friq_log_adapter( PIA *pi, char * scratch, int verbose ) | ||
220 | |||
221 | { char *mode_string[6] = {"4-bit","8-bit", | ||
222 | "EPP-8","EPP-16","EPP-32"}; | ||
223 | |||
224 | printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device, | ||
225 | FRIQ_VERSION,pi->port); | ||
226 | printk("mode %d (%s), delay %d\n",pi->mode, | ||
227 | mode_string[pi->mode],pi->delay); | ||
228 | |||
229 | pi->private = 1; | ||
230 | friq_connect(pi); | ||
231 | CMD(0x9e); /* disable sleep timer */ | ||
232 | friq_disconnect(pi); | ||
233 | |||
234 | } | ||
235 | |||
236 | static void friq_release_proto( PIA *pi) | ||
237 | { | ||
238 | if (pi->private) { /* turn off the power */ | ||
239 | friq_connect(pi); | ||
240 | CMD(0x1d); CMD(0x1e); | ||
241 | friq_disconnect(pi); | ||
242 | pi->private = 0; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static struct pi_protocol friq = { | ||
247 | .owner = THIS_MODULE, | ||
248 | .name = "friq", | ||
249 | .max_mode = 5, | ||
250 | .epp_first = 2, | ||
251 | .default_delay = 1, | ||
252 | .max_units = 1, | ||
253 | .write_regr = friq_write_regr, | ||
254 | .read_regr = friq_read_regr, | ||
255 | .write_block = friq_write_block, | ||
256 | .read_block = friq_read_block, | ||
257 | .connect = friq_connect, | ||
258 | .disconnect = friq_disconnect, | ||
259 | .test_proto = friq_test_proto, | ||
260 | .log_adapter = friq_log_adapter, | ||
261 | .release_proto = friq_release_proto, | ||
262 | }; | ||
263 | |||
264 | static int __init friq_init(void) | ||
265 | { | ||
266 | return pi_register(&friq)-1; | ||
267 | } | ||
268 | |||
269 | static void __exit friq_exit(void) | ||
270 | { | ||
271 | pi_unregister(&friq); | ||
272 | } | ||
273 | |||
274 | MODULE_LICENSE("GPL"); | ||
275 | module_init(friq_init) | ||
276 | module_exit(friq_exit) | ||