brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / drivers / block / paride / friq.c
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/delay.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/wait.h>
35 #include <asm/io.h>
36
37 #include "paride.h"
38
39 #define CMD(x)          w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
40                         w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
41
42 #define j44(l,h)        (((l>>4)&0x0f)|(h&0xf0))
43
44 /* cont = 0 - access the IDE register file 
45    cont = 1 - access the IDE command set 
46 */
47
48 static int  cont_map[2] = { 0x08, 0x10 };
49
50 static int friq_read_regr( PIA *pi, int cont, int regr )
51
52 {       int     h,l,r;
53
54         r = regr + cont_map[cont];
55
56         CMD(r);
57         w2(6); l = r1();
58         w2(4); h = r1();
59         w2(4); 
60
61         return j44(l,h);
62
63 }
64
65 static void friq_write_regr( PIA *pi, int cont, int regr, int val)
66
67 {       int r;
68
69         r = regr + cont_map[cont];
70
71         CMD(r);
72         w0(val);
73         w2(5);w2(7);w2(5);w2(4);
74 }
75
76 static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
77
78 {       int     h, l, k, ph;
79
80         switch(pi->mode) {
81
82         case 0: CMD(regr); 
83                 for (k=0;k<count;k++) {
84                         w2(6); l = r1();
85                         w2(4); h = r1();
86                         buf[k] = j44(l,h);
87                 }
88                 w2(4);
89                 break;
90
91         case 1: ph = 2;
92                 CMD(regr+0xc0); 
93                 w0(0xff);
94                 for (k=0;k<count;k++) {
95                         w2(0xa4 + ph); 
96                         buf[k] = r0();
97                         ph = 2 - ph;
98                 } 
99                 w2(0xac); w2(0xa4); w2(4);
100                 break;
101
102         case 2: CMD(regr+0x80);
103                 for (k=0;k<count-2;k++) buf[k] = r4();
104                 w2(0xac); w2(0xa4);
105                 buf[count-2] = r4();
106                 buf[count-1] = r4();
107                 w2(4);
108                 break;
109
110         case 3: CMD(regr+0x80);
111                 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
112                 w2(0xac); w2(0xa4);
113                 buf[count-2] = r4();
114                 buf[count-1] = r4();
115                 w2(4);
116                 break;
117
118         case 4: CMD(regr+0x80);
119                 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
120                 buf[count-4] = r4();
121                 buf[count-3] = r4();
122                 w2(0xac); w2(0xa4);
123                 buf[count-2] = r4();
124                 buf[count-1] = r4();
125                 w2(4);
126                 break;
127
128         }
129 }
130
131 static void friq_read_block( PIA *pi, char * buf, int count)
132
133 {       friq_read_block_int(pi,buf,count,0x08);
134 }
135
136 static void friq_write_block( PIA *pi, char * buf, int count )
137  
138 {       int     k;
139
140         switch(pi->mode) {
141
142         case 0:
143         case 1: CMD(8); w2(5);
144                 for (k=0;k<count;k++) {
145                         w0(buf[k]);
146                         w2(7);w2(5);
147                 }
148                 w2(4);
149                 break;
150
151         case 2: CMD(0xc8); w2(5);
152                 for (k=0;k<count;k++) w4(buf[k]);
153                 w2(4);
154                 break;
155
156         case 3: CMD(0xc8); w2(5);
157                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
158                 w2(4);
159                 break;
160
161         case 4: CMD(0xc8); w2(5);
162                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
163                 w2(4);
164                 break;
165         }
166 }
167
168 static void friq_connect ( PIA *pi  )
169
170 {       pi->saved_r0 = r0();
171         pi->saved_r2 = r2();
172         w2(4);
173 }
174
175 static void friq_disconnect ( PIA *pi )
176
177 {       CMD(0x20);
178         w0(pi->saved_r0);
179         w2(pi->saved_r2);
180
181
182 static int friq_test_proto( PIA *pi, char * scratch, int verbose )
183
184 {       int     j, k, r;
185         int     e[2] = {0,0};
186
187         pi->saved_r0 = r0();    
188         w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
189         udelay(500);
190         w0(pi->saved_r0);
191
192         friq_connect(pi);
193         for (j=0;j<2;j++) {
194                 friq_write_regr(pi,0,6,0xa0+j*0x10);
195                 for (k=0;k<256;k++) {
196                         friq_write_regr(pi,0,2,k^0xaa);
197                         friq_write_regr(pi,0,3,k^0x55);
198                         if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
199                         }
200                 }
201         friq_disconnect(pi);
202
203         friq_connect(pi);
204         friq_read_block_int(pi,scratch,512,0x10);
205         r = 0;
206         for (k=0;k<128;k++) if (scratch[k] != k) r++;
207         friq_disconnect(pi);
208
209         if (verbose)  {
210             printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",
211                    pi->device,pi->port,pi->mode,e[0],e[1],r);
212         }
213
214         return (r || (e[0] && e[1]));
215 }
216
217
218 static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
219
220 {       char    *mode_string[6] = {"4-bit","8-bit",
221                                    "EPP-8","EPP-16","EPP-32"};
222
223         printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device,
224                 FRIQ_VERSION,pi->port);
225         printk("mode %d (%s), delay %d\n",pi->mode,
226                 mode_string[pi->mode],pi->delay);
227
228         pi->private = 1;
229         friq_connect(pi);
230         CMD(0x9e);              /* disable sleep timer */
231         friq_disconnect(pi);
232
233 }
234
235 static void friq_init_proto( PIA *pi)
236
237 {       MOD_INC_USE_COUNT;
238         pi->private = 0;
239 }
240
241 static void friq_release_proto( PIA *pi)
242
243 {       if (pi->private) {              /* turn off the power */
244                 friq_connect(pi);
245                 CMD(0x1d); CMD(0x1e);
246                 friq_disconnect(pi);
247                 pi->private = 0;
248         }
249
250         MOD_DEC_USE_COUNT;
251 }
252
253 struct pi_protocol friq = {"friq",0,5,2,1,1,
254                            friq_write_regr,
255                            friq_read_regr,
256                            friq_write_block,
257                            friq_read_block,
258                            friq_connect,
259                            friq_disconnect,
260                            0,
261                            0,
262                            friq_test_proto,
263                            friq_log_adapter,
264                            friq_init_proto,
265                            friq_release_proto
266                           };
267
268
269 #ifdef MODULE
270
271 int     init_module(void)
272
273 {       return pi_register( &friq ) - 1;
274 }
275
276 void    cleanup_module(void)
277
278 {       pi_unregister( &friq );
279 }
280
281 #endif
282
283 /* end of friq.c */
284 MODULE_LICENSE("GPL");