Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
friq.c
Go to the documentation of this file.
1 /*
2  friq.c (c) 1998 Grant R. Guenther <[email protected]>
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 paride_register(&friq);
267 }
268 
269 static void __exit friq_exit(void)
270 {
271  paride_unregister(&friq);
272 }
273 
274 MODULE_LICENSE("GPL");
275 module_init(friq_init)
276 module_exit(friq_exit)