2 friq.c (c) 1998 Grant R. Guenther <grant@torque.net>
3 Under the terms of the GNU General Public License
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.
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.
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.
25 1.01 GRG 1998.12.20 Added support for soft power switch
28 #define FRIQ_VERSION "1.01"
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>
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);
43 #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))
45 /* cont = 0 - access the IDE register file
46 cont = 1 - access the IDE command set
49 static int cont_map[2] = { 0x08, 0x10 };
51 static int friq_read_regr( PIA *pi, int cont, int regr )
55 r = regr + cont_map[cont];
66 static void friq_write_regr( PIA *pi, int cont, int regr, int val)
70 r = regr + cont_map[cont];
74 w2(5);w2(7);w2(5);w2(4);
77 static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
84 for (k=0;k<count;k++) {
95 for (k=0;k<count;k++) {
100 w2(0xac); w2(0xa4); w2(4);
103 case 2: CMD(regr+0x80);
104 for (k=0;k<count-2;k++) buf[k] = r4();
111 case 3: CMD(regr+0x80);
112 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
119 case 4: CMD(regr+0x80);
120 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
132 static void friq_read_block( PIA *pi, char * buf, int count)
134 { friq_read_block_int(pi,buf,count,0x08);
137 static void friq_write_block( PIA *pi, char * buf, int count )
144 case 1: CMD(8); w2(5);
145 for (k=0;k<count;k++) {
152 case 2: CMD(0xc8); w2(5);
153 for (k=0;k<count;k++) w4(buf[k]);
157 case 3: CMD(0xc8); w2(5);
158 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
162 case 4: CMD(0xc8); w2(5);
163 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
169 static void friq_connect ( PIA *pi )
171 { pi->saved_r0 = r0();
176 static void friq_disconnect ( PIA *pi )
183 static int friq_test_proto( PIA *pi, char * scratch, int verbose )
189 w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
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]++;
205 friq_read_block_int(pi,scratch,512,0x10);
207 for (k=0;k<128;k++) if (scratch[k] != k) r++;
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);
215 return (r || (e[0] && e[1]));
219 static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
221 { char *mode_string[6] = {"4-bit","8-bit",
222 "EPP-8","EPP-16","EPP-32"};
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);
231 CMD(0x9e); /* disable sleep timer */
236 static void friq_release_proto( PIA *pi)
238 if (pi->private) { /* turn off the power */
240 CMD(0x1d); CMD(0x1e);
246 static struct pi_protocol friq = {
247 .owner = THIS_MODULE,
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,
264 static int __init friq_init(void)
266 return paride_register(&friq);
269 static void __exit friq_exit(void)
271 paride_unregister(&friq);
274 MODULE_LICENSE("GPL");
275 module_init(friq_init)
276 module_exit(friq_exit)