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/delay.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/wait.h>
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);
42 #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))
44 /* cont = 0 - access the IDE register file
45 cont = 1 - access the IDE command set
48 static int cont_map[2] = { 0x08, 0x10 };
50 static int friq_read_regr( PIA *pi, int cont, int regr )
54 r = regr + cont_map[cont];
65 static void friq_write_regr( PIA *pi, int cont, int regr, int val)
69 r = regr + cont_map[cont];
73 w2(5);w2(7);w2(5);w2(4);
76 static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
83 for (k=0;k<count;k++) {
94 for (k=0;k<count;k++) {
99 w2(0xac); w2(0xa4); w2(4);
102 case 2: CMD(regr+0x80);
103 for (k=0;k<count-2;k++) buf[k] = r4();
110 case 3: CMD(regr+0x80);
111 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
118 case 4: CMD(regr+0x80);
119 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
131 static void friq_read_block( PIA *pi, char * buf, int count)
133 { friq_read_block_int(pi,buf,count,0x08);
136 static void friq_write_block( PIA *pi, char * buf, int count )
143 case 1: CMD(8); w2(5);
144 for (k=0;k<count;k++) {
151 case 2: CMD(0xc8); w2(5);
152 for (k=0;k<count;k++) w4(buf[k]);
156 case 3: CMD(0xc8); w2(5);
157 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
161 case 4: CMD(0xc8); w2(5);
162 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
168 static void friq_connect ( PIA *pi )
170 { pi->saved_r0 = r0();
175 static void friq_disconnect ( PIA *pi )
182 static int friq_test_proto( PIA *pi, char * scratch, int verbose )
188 w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
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]++;
204 friq_read_block_int(pi,scratch,512,0x10);
206 for (k=0;k<128;k++) if (scratch[k] != k) r++;
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);
214 return (r || (e[0] && e[1]));
218 static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
220 { char *mode_string[6] = {"4-bit","8-bit",
221 "EPP-8","EPP-16","EPP-32"};
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);
230 CMD(0x9e); /* disable sleep timer */
235 static void friq_init_proto( PIA *pi)
241 static void friq_release_proto( PIA *pi)
243 { if (pi->private) { /* turn off the power */
245 CMD(0x1d); CMD(0x1e);
253 struct pi_protocol friq = {"friq",0,5,2,1,1,
271 int init_module(void)
273 { return pi_register( &friq ) - 1;
276 void cleanup_module(void)
278 { pi_unregister( &friq );
284 MODULE_LICENSE("GPL");