• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/block/paride/
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/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
49static int  cont_map[2] = { 0x08, 0x10 };
50
51static 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
66static 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
77static 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
132static void friq_read_block( PIA *pi, char * buf, int count)
133
134{	friq_read_block_int(pi,buf,count,0x08);
135}
136
137static 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
169static void friq_connect ( PIA *pi  )
170
171{       pi->saved_r0 = r0();
172        pi->saved_r2 = r2();
173	w2(4);
174}
175
176static void friq_disconnect ( PIA *pi )
177
178{       CMD(0x20);
179	w0(pi->saved_r0);
180        w2(pi->saved_r2);
181}
182
183static 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
219static 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
236static 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
246static 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
264static int __init friq_init(void)
265{
266	return paride_register(&friq);
267}
268
269static void __exit friq_exit(void)
270{
271	paride_unregister(&friq);
272}
273
274MODULE_LICENSE("GPL");
275module_init(friq_init)
276module_exit(friq_exit)
277