File: /usr/src/linux/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