Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/block/paride/friq.c
15112 views
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)
277
278