• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 	bpck.c	(c) 1996-8  Grant R. Guenther <grant@torque.net>
3 		            Under the terms of the GNU General Public License.
4 
5 	bpck.c is a low-level protocol driver for the MicroSolutions
6 	"backpack" parallel port IDE adapter.
7 
8 */
9 
10 /* Changes:
11 
12 	1.01	GRG 1998.05.05 init_proto, release_proto, pi->delay
13 	1.02    GRG 1998.08.15 default pi->delay returned to 4
14 
15 */
16 
17 #define	BPCK_VERSION	"1.02"
18 
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/delay.h>
22 #include <linux/kernel.h>
23 #include <linux/types.h>
24 #include <linux/wait.h>
25 #include <asm/io.h>
26 
27 #include "paride.h"
28 
29 #undef r2
30 #undef w2
31 #undef PC
32 
33 #define PC			pi->private
34 #define r2()			(PC=(in_p(2) & 0xff))
35 #define w2(byte)  		{out_p(2,byte); PC = byte;}
36 #define t2(pat)   		{PC ^= pat; out_p(2,PC);}
37 #define e2()			{PC &= 0xfe; out_p(2,PC);}
38 #define o2()			{PC |= 1; out_p(2,PC);}
39 
40 #define j44(l,h)     (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80))
41 
42 /* cont = 0 - access the IDE register file
43    cont = 1 - access the IDE command set
44    cont = 2 - use internal bpck register addressing
45 */
46 
47 static int  cont_map[3] = { 0x40, 0x48, 0 };
48 
bpck_read_regr(PIA * pi,int cont,int regr)49 static int bpck_read_regr( PIA *pi, int cont, int regr )
50 
51 {       int r, l, h;
52 
53 	r = regr + cont_map[cont];
54 
55 	switch (pi->mode) {
56 
57 	case 0: w0(r & 0xf); w0(r); t2(2); t2(4);
58 	        l = r1();
59         	t2(4);
60         	h = r1();
61         	return j44(l,h);
62 
63 	case 1: w0(r & 0xf); w0(r); t2(2);
64 	        e2(); t2(0x20);
65 		t2(4); h = r0();
66 	        t2(1); t2(0x20);
67 	        return h;
68 
69 	case 2:
70 	case 3:
71 	case 4: w0(r); w2(9); w2(0); w2(0x20);
72 		h = r4();
73 		w2(0);
74 		return h;
75 
76 	}
77 	return -1;
78 }
79 
bpck_write_regr(PIA * pi,int cont,int regr,int val)80 static void bpck_write_regr( PIA *pi, int cont, int regr, int val )
81 
82 {	int	r;
83 
84         r = regr + cont_map[cont];
85 
86 	switch (pi->mode) {
87 
88 	case 0:
89 	case 1: w0(r);
90 		t2(2);
91 		w0(val);
92 		o2(); t2(4); t2(1);
93 		break;
94 
95 	case 2:
96 	case 3:
97 	case 4: w0(r); w2(9); w2(0);
98 		w0(val); w2(1); w2(3); w2(0);
99 		break;
100 
101 	}
102 }
103 
104 /* These macros access the bpck registers in native addressing */
105 
106 #define WR(r,v)		bpck_write_regr(pi,2,r,v)
107 #define RR(r)		(bpck_read_regr(pi,2,r))
108 
bpck_write_block(PIA * pi,char * buf,int count)109 static void bpck_write_block( PIA *pi, char * buf, int count )
110 
111 {	int i;
112 
113 	switch (pi->mode) {
114 
115 	case 0: WR(4,0x40);
116 		w0(0x40); t2(2); t2(1);
117 		for (i=0;i<count;i++) { w0(buf[i]); t2(4); }
118 		WR(4,0);
119 		break;
120 
121 	case 1: WR(4,0x50);
122                 w0(0x40); t2(2); t2(1);
123                 for (i=0;i<count;i++) { w0(buf[i]); t2(4); }
124                 WR(4,0x10);
125 		break;
126 
127 	case 2: WR(4,0x48);
128 		w0(0x40); w2(9); w2(0); w2(1);
129 		for (i=0;i<count;i++) w4(buf[i]);
130 		w2(0);
131 		WR(4,8);
132 		break;
133 
134         case 3: WR(4,0x48);
135                 w0(0x40); w2(9); w2(0); w2(1);
136                 for (i=0;i<count/2;i++) w4w(((u16 *)buf)[i]);
137                 w2(0);
138                 WR(4,8);
139                 break;
140 
141         case 4: WR(4,0x48);
142                 w0(0x40); w2(9); w2(0); w2(1);
143                 for (i=0;i<count/4;i++) w4l(((u32 *)buf)[i]);
144                 w2(0);
145                 WR(4,8);
146                 break;
147  	}
148 }
149 
bpck_read_block(PIA * pi,char * buf,int count)150 static void bpck_read_block( PIA *pi, char * buf, int count )
151 
152 {	int i, l, h;
153 
154 	switch (pi->mode) {
155 
156       	case 0: WR(4,0x40);
157 		w0(0x40); t2(2);
158 		for (i=0;i<count;i++) {
159 		    t2(4); l = r1();
160 		    t2(4); h = r1();
161 		    buf[i] = j44(l,h);
162 		}
163 		WR(4,0);
164 		break;
165 
166 	case 1: WR(4,0x50);
167 		w0(0x40); t2(2); t2(0x20);
168       	        for(i=0;i<count;i++) { t2(4); buf[i] = r0(); }
169 	        t2(1); t2(0x20);
170 	        WR(4,0x10);
171 		break;
172 
173 	case 2: WR(4,0x48);
174 		w0(0x40); w2(9); w2(0); w2(0x20);
175 		for (i=0;i<count;i++) buf[i] = r4();
176 		w2(0);
177 		WR(4,8);
178 		break;
179 
180         case 3: WR(4,0x48);
181                 w0(0x40); w2(9); w2(0); w2(0x20);
182                 for (i=0;i<count/2;i++) ((u16 *)buf)[i] = r4w();
183                 w2(0);
184                 WR(4,8);
185                 break;
186 
187         case 4: WR(4,0x48);
188                 w0(0x40); w2(9); w2(0); w2(0x20);
189                 for (i=0;i<count/4;i++) ((u32 *)buf)[i] = r4l();
190                 w2(0);
191                 WR(4,8);
192                 break;
193 
194 	}
195 }
196 
bpck_probe_unit(PIA * pi)197 static int bpck_probe_unit ( PIA *pi )
198 
199 {	int o1, o0, f7, id;
200 	int t, s;
201 
202 	id = pi->unit;
203 	s = 0;
204 	w2(4); w2(0xe); r2(); t2(2);
205 	o1 = r1()&0xf8;
206 	o0 = r0();
207 	w0(255-id); w2(4); w0(id);
208 	t2(8); t2(8); t2(8);
209 	t2(2); t = r1()&0xf8;
210 	f7 = ((id % 8) == 7);
211 	if ((f7) || (t != o1)) { t2(2); s = r1()&0xf8; }
212 	if ((t == o1) && ((!f7) || (s == o1)))  {
213 		w2(0x4c); w0(o0);
214 		return 0;
215 	}
216 	t2(8); w0(0); t2(2); w2(0x4c); w0(o0);
217 	return 1;
218 }
219 
bpck_connect(PIA * pi)220 static void bpck_connect ( PIA *pi  )
221 
222 {       pi->saved_r0 = r0();
223 	w0(0xff-pi->unit); w2(4); w0(pi->unit);
224 	t2(8); t2(8); t2(8);
225 	t2(2); t2(2);
226 
227 	switch (pi->mode) {
228 
229 	case 0: t2(8); WR(4,0);
230 		break;
231 
232 	case 1: t2(8); WR(4,0x10);
233 		break;
234 
235 	case 2:
236         case 3:
237 	case 4: w2(0); WR(4,8);
238 		break;
239 
240 	}
241 
242 	WR(5,8);
243 
244 	if (pi->devtype == PI_PCD) {
245 		WR(0x46,0x10);		/* fiddle with ESS logic ??? */
246 		WR(0x4c,0x38);
247 		WR(0x4d,0x88);
248 		WR(0x46,0xa0);
249 		WR(0x41,0);
250 		WR(0x4e,8);
251 		}
252 }
253 
bpck_disconnect(PIA * pi)254 static void bpck_disconnect ( PIA *pi )
255 
256 {	w0(0);
257 	if (pi->mode >= 2) { w2(9); w2(0); } else t2(2);
258 	w2(0x4c); w0(pi->saved_r0);
259 }
260 
bpck_force_spp(PIA * pi)261 static void bpck_force_spp ( PIA *pi )
262 
263 /* This fakes the EPP protocol to turn off EPP ... */
264 
265 {       pi->saved_r0 = r0();
266         w0(0xff-pi->unit); w2(4); w0(pi->unit);
267         t2(8); t2(8); t2(8);
268         t2(2); t2(2);
269 
270         w2(0);
271         w0(4); w2(9); w2(0);
272         w0(0); w2(1); w2(3); w2(0);
273         w0(0); w2(9); w2(0);
274         w2(0x4c); w0(pi->saved_r0);
275 }
276 
277 #define TEST_LEN  16
278 
bpck_test_proto(PIA * pi,char * scratch,int verbose)279 static int bpck_test_proto( PIA *pi, char * scratch, int verbose )
280 
281 {	int i, e, l, h, om;
282 	char buf[TEST_LEN];
283 
284 	bpck_force_spp(pi);
285 
286 	switch (pi->mode) {
287 
288 	case 0: bpck_connect(pi);
289 		WR(0x13,0x7f);
290 		w0(0x13); t2(2);
291 		for(i=0;i<TEST_LEN;i++) {
292                     t2(4); l = r1();
293                     t2(4); h = r1();
294                     buf[i] = j44(l,h);
295 		}
296 		bpck_disconnect(pi);
297 		break;
298 
299         case 1: bpck_connect(pi);
300 		WR(0x13,0x7f);
301                 w0(0x13); t2(2); t2(0x20);
302                 for(i=0;i<TEST_LEN;i++) { t2(4); buf[i] = r0(); }
303                 t2(1); t2(0x20);
304 		bpck_disconnect(pi);
305 		break;
306 
307 	case 2:
308 	case 3:
309 	case 4: om = pi->mode;
310 		pi->mode = 0;
311 		bpck_connect(pi);
312 		WR(7,3);
313 		WR(4,8);
314 		bpck_disconnect(pi);
315 
316 		pi->mode = om;
317 		bpck_connect(pi);
318 		w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0);
319 
320 		switch (pi->mode) {
321 		  case 2: for (i=0;i<TEST_LEN;i++) buf[i] = r4();
322 			  break;
323 		  case 3: for (i=0;i<TEST_LEN/2;i++) ((u16 *)buf)[i] = r4w();
324                           break;
325 		  case 4: for (i=0;i<TEST_LEN/4;i++) ((u32 *)buf)[i] = r4l();
326                           break;
327 		}
328 
329 		w2(0);
330 		WR(7,0);
331 		bpck_disconnect(pi);
332 
333 		break;
334 
335 	}
336 
337 	if (verbose) {
338 	    printk("%s: bpck: 0x%x unit %d mode %d: ",
339 		   pi->device,pi->port,pi->unit,pi->mode);
340 	    for (i=0;i<TEST_LEN;i++) printk("%3d",buf[i]);
341 	    printk("\n");
342 	}
343 
344 	e = 0;
345 	for (i=0;i<TEST_LEN;i++) if (buf[i] != (i+1)) e++;
346 	return e;
347 }
348 
bpck_read_eeprom(PIA * pi,char * buf)349 static void bpck_read_eeprom ( PIA *pi, char * buf )
350 
351 {       int i, j, k, p, v, f, om, od;
352 
353 	bpck_force_spp(pi);
354 
355 	om = pi->mode;  od = pi->delay;
356 	pi->mode = 0; pi->delay = 6;
357 
358 	bpck_connect(pi);
359 
360 	WR(4,0);
361 	for (i=0;i<64;i++) {
362 	    WR(6,8);
363 	    WR(6,0xc);
364 	    p = 0x100;
365 	    for (k=0;k<9;k++) {
366 		f = (((i + 0x180) & p) != 0) * 2;
367 		WR(6,f+0xc);
368 		WR(6,f+0xd);
369 		WR(6,f+0xc);
370 		p = (p >> 1);
371 	    }
372 	    for (j=0;j<2;j++) {
373 		v = 0;
374 		for (k=0;k<8;k++) {
375 		    WR(6,0xc);
376 		    WR(6,0xd);
377 		    WR(6,0xc);
378 		    f = RR(0);
379 		    v = 2*v + (f == 0x84);
380 		}
381 		buf[2*i+1-j] = v;
382 	    }
383 	}
384 	WR(6,8);
385 	WR(6,0);
386 	WR(5,8);
387 
388 	bpck_disconnect(pi);
389 
390         if (om >= 2) {
391                 bpck_connect(pi);
392                 WR(7,3);
393                 WR(4,8);
394                 bpck_disconnect(pi);
395         }
396 
397 	pi->mode = om; pi->delay = od;
398 }
399 
bpck_test_port(PIA * pi)400 static int bpck_test_port ( PIA *pi ) 	/* check for 8-bit port */
401 
402 {	int	i, r, m;
403 
404 	w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i);
405 	m = -1;
406 	if (r == i) m = 2;
407 	if (r == (255-i)) m = 0;
408 
409 	w2(0xc); i = r0(); w0(255-i); r = r0(); w0(i);
410 	if (r != (255-i)) m = -1;
411 
412 	if (m == 0) { w2(6); w2(0xc); r = r0(); w0(0xaa); w0(r); w0(0xaa); }
413 	if (m == 2) { w2(0x26); w2(0xc); }
414 
415 	if (m == -1) return 0;
416 	return 5;
417 }
418 
bpck_log_adapter(PIA * pi,char * scratch,int verbose)419 static void bpck_log_adapter( PIA *pi, char * scratch, int verbose )
420 
421 {	char	*mode_string[5] = { "4-bit","8-bit","EPP-8",
422 				    "EPP-16","EPP-32" };
423 
424 #ifdef DUMP_EEPROM
425 	int i;
426 #endif
427 
428 	bpck_read_eeprom(pi,scratch);
429 
430 #ifdef DUMP_EEPROM
431 	if (verbose) {
432 	   for(i=0;i<128;i++)
433 		if ((scratch[i] < ' ') || (scratch[i] > '~'))
434 		    scratch[i] = '.';
435 	   printk("%s: bpck EEPROM: %64.64s\n",pi->device,scratch);
436 	   printk("%s:              %64.64s\n",pi->device,&scratch[64]);
437 	}
438 #endif
439 
440 	printk("%s: bpck %s, backpack %8.8s unit %d",
441 		pi->device,BPCK_VERSION,&scratch[110],pi->unit);
442 	printk(" at 0x%x, mode %d (%s), delay %d\n",pi->port,
443 		pi->mode,mode_string[pi->mode],pi->delay);
444 }
445 
446 static struct pi_protocol bpck = {
447 	.owner		= THIS_MODULE,
448 	.name		= "bpck",
449 	.max_mode	= 5,
450 	.epp_first	= 2,
451 	.default_delay	= 4,
452 	.max_units	= 255,
453 	.write_regr	= bpck_write_regr,
454 	.read_regr	= bpck_read_regr,
455 	.write_block	= bpck_write_block,
456 	.read_block	= bpck_read_block,
457 	.connect	= bpck_connect,
458 	.disconnect	= bpck_disconnect,
459 	.test_port	= bpck_test_port,
460 	.probe_unit	= bpck_probe_unit,
461 	.test_proto	= bpck_test_proto,
462 	.log_adapter	= bpck_log_adapter,
463 };
464 
bpck_init(void)465 static int __init bpck_init(void)
466 {
467 	return paride_register(&bpck);
468 }
469 
bpck_exit(void)470 static void __exit bpck_exit(void)
471 {
472 	paride_unregister(&bpck);
473 }
474 
475 MODULE_LICENSE("GPL");
476 module_init(bpck_init)
477 module_exit(bpck_exit)
478