1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun backpack.c (c) 2001 Micro Solutions Inc.
3*4882a593Smuzhiyun Released under the terms of the GNU General Public license
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun backpack.c is a low-level protocol driver for the Micro Solutions
6*4882a593Smuzhiyun "BACKPACK" parallel port IDE adapter
7*4882a593Smuzhiyun (Works on Series 6 drives)
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun Written by: Ken Hahn (linux-dev@micro-solutions.com)
10*4882a593Smuzhiyun Clive Turvey (linux-dev@micro-solutions.com)
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun This is Ken's linux wrapper for the PPC library
16*4882a593Smuzhiyun Version 1.0.0 is the backpack driver for which source is not available
17*4882a593Smuzhiyun Version 2.0.0 is the first to have source released
18*4882a593Smuzhiyun Version 2.0.1 is the "Cox-ified" source code
19*4882a593Smuzhiyun Version 2.0.2 - fixed version string usage, and made ppc functions static
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define BACKPACK_VERSION "2.0.2"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <linux/module.h>
26*4882a593Smuzhiyun #include <linux/init.h>
27*4882a593Smuzhiyun #include <linux/kernel.h>
28*4882a593Smuzhiyun #include <linux/slab.h>
29*4882a593Smuzhiyun #include <linux/types.h>
30*4882a593Smuzhiyun #include <asm/io.h>
31*4882a593Smuzhiyun #include <linux/parport.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include "ppc6lnx.c"
34*4882a593Smuzhiyun #include "paride.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* PARAMETERS */
37*4882a593Smuzhiyun static bool verbose; /* set this to 1 to see debugging messages and whatnot */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define PPCSTRUCT(pi) ((Interface *)(pi->private))
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /****************************************************************/
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun ATAPI CDROM DRIVE REGISTERS
45*4882a593Smuzhiyun */
46*4882a593Smuzhiyun #define ATAPI_DATA 0 /* data port */
47*4882a593Smuzhiyun #define ATAPI_ERROR 1 /* error register (read) */
48*4882a593Smuzhiyun #define ATAPI_FEATURES 1 /* feature register (write) */
49*4882a593Smuzhiyun #define ATAPI_INT_REASON 2 /* interrupt reason register */
50*4882a593Smuzhiyun #define ATAPI_COUNT_LOW 4 /* byte count register (low) */
51*4882a593Smuzhiyun #define ATAPI_COUNT_HIGH 5 /* byte count register (high) */
52*4882a593Smuzhiyun #define ATAPI_DRIVE_SEL 6 /* drive select register */
53*4882a593Smuzhiyun #define ATAPI_STATUS 7 /* status port (read) */
54*4882a593Smuzhiyun #define ATAPI_COMMAND 7 /* command port (write) */
55*4882a593Smuzhiyun #define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */
56*4882a593Smuzhiyun #define ATAPI_DEVICE_CONTROL 0x0e /* device control (write) */
57*4882a593Smuzhiyun /****************************************************************/
58*4882a593Smuzhiyun
bpck6_read_regr(PIA * pi,int cont,int reg)59*4882a593Smuzhiyun static int bpck6_read_regr(PIA *pi, int cont, int reg)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun unsigned int out;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* check for bad settings */
64*4882a593Smuzhiyun if (reg<0 || reg>7 || cont<0 || cont>2)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun return(-1);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg);
69*4882a593Smuzhiyun return(out);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
bpck6_write_regr(PIA * pi,int cont,int reg,int val)72*4882a593Smuzhiyun static void bpck6_write_regr(PIA *pi, int cont, int reg, int val)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun /* check for bad settings */
75*4882a593Smuzhiyun if (reg>=0 && reg<=7 && cont>=0 && cont<=1)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
bpck6_write_block(PIA * pi,char * buf,int len)81*4882a593Smuzhiyun static void bpck6_write_block( PIA *pi, char * buf, int len )
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
bpck6_read_block(PIA * pi,char * buf,int len)86*4882a593Smuzhiyun static void bpck6_read_block( PIA *pi, char * buf, int len )
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
bpck6_connect(PIA * pi)91*4882a593Smuzhiyun static void bpck6_connect ( PIA *pi )
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun if(verbose)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun printk(KERN_DEBUG "connect\n");
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if(pi->mode >=2)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun PPCSTRUCT(pi)->mode=4+pi->mode-2;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun else if(pi->mode==1)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun PPCSTRUCT(pi)->mode=3;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun else
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun PPCSTRUCT(pi)->mode=1;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun ppc6_open(PPCSTRUCT(pi));
112*4882a593Smuzhiyun ppc6_wr_extout(PPCSTRUCT(pi),0x3);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
bpck6_disconnect(PIA * pi)115*4882a593Smuzhiyun static void bpck6_disconnect ( PIA *pi )
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun if(verbose)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun printk("disconnect\n");
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun ppc6_wr_extout(PPCSTRUCT(pi),0x0);
122*4882a593Smuzhiyun ppc6_close(PPCSTRUCT(pi));
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
bpck6_test_port(PIA * pi)125*4882a593Smuzhiyun static int bpck6_test_port ( PIA *pi ) /* check for 8-bit port */
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun if(verbose)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n",
130*4882a593Smuzhiyun ((struct pardevice*)(pi->pardev))->port->modes,
131*4882a593Smuzhiyun ((struct pardevice *)(pi->pardev))->port->base);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /*copy over duplicate stuff.. initialize state info*/
135*4882a593Smuzhiyun PPCSTRUCT(pi)->ppc_id=pi->unit;
136*4882a593Smuzhiyun PPCSTRUCT(pi)->lpt_addr=pi->port;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* look at the parport device to see if what modes we can use */
139*4882a593Smuzhiyun if(((struct pardevice *)(pi->pardev))->port->modes &
140*4882a593Smuzhiyun (PARPORT_MODE_EPP)
141*4882a593Smuzhiyun )
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun return 5; /* Can do EPP*/
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun else if(((struct pardevice *)(pi->pardev))->port->modes &
146*4882a593Smuzhiyun (PARPORT_MODE_TRISTATE)
147*4882a593Smuzhiyun )
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun return 2;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun else /*Just flat SPP*/
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun return 1;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
bpck6_probe_unit(PIA * pi)157*4882a593Smuzhiyun static int bpck6_probe_unit ( PIA *pi )
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun int out;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if(verbose)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*SET PPC UNIT NUMBER*/
167*4882a593Smuzhiyun PPCSTRUCT(pi)->ppc_id=pi->unit;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*LOWER DOWN TO UNIDIRECTIONAL*/
170*4882a593Smuzhiyun PPCSTRUCT(pi)->mode=1;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun out=ppc6_open(PPCSTRUCT(pi));
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if(verbose)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun printk(KERN_DEBUG "ppc_open returned %2x\n",out);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if(out)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun ppc6_close(PPCSTRUCT(pi));
182*4882a593Smuzhiyun if(verbose)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun printk(KERN_DEBUG "leaving probe\n");
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun return(1);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun else
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun if(verbose)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun printk(KERN_DEBUG "Failed open\n");
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun return(0);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
bpck6_log_adapter(PIA * pi,char * scratch,int verbose)198*4882a593Smuzhiyun static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose )
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun char *mode_string[5]=
201*4882a593Smuzhiyun {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device);
204*4882a593Smuzhiyun printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device);
205*4882a593Smuzhiyun printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n",
206*4882a593Smuzhiyun pi->device,BACKPACK_VERSION,pi->port);
207*4882a593Smuzhiyun printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device,
208*4882a593Smuzhiyun pi->unit,pi->mode,mode_string[pi->mode],pi->delay);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
bpck6_init_proto(PIA * pi)211*4882a593Smuzhiyun static int bpck6_init_proto(PIA *pi)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun Interface *p = kzalloc(sizeof(Interface), GFP_KERNEL);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (p) {
216*4882a593Smuzhiyun pi->private = (unsigned long)p;
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n", pi->device);
221*4882a593Smuzhiyun return -1;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
bpck6_release_proto(PIA * pi)224*4882a593Smuzhiyun static void bpck6_release_proto(PIA *pi)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun kfree((void *)(pi->private));
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun static struct pi_protocol bpck6 = {
230*4882a593Smuzhiyun .owner = THIS_MODULE,
231*4882a593Smuzhiyun .name = "bpck6",
232*4882a593Smuzhiyun .max_mode = 5,
233*4882a593Smuzhiyun .epp_first = 2, /* 2-5 use epp (need 8 ports) */
234*4882a593Smuzhiyun .max_units = 255,
235*4882a593Smuzhiyun .write_regr = bpck6_write_regr,
236*4882a593Smuzhiyun .read_regr = bpck6_read_regr,
237*4882a593Smuzhiyun .write_block = bpck6_write_block,
238*4882a593Smuzhiyun .read_block = bpck6_read_block,
239*4882a593Smuzhiyun .connect = bpck6_connect,
240*4882a593Smuzhiyun .disconnect = bpck6_disconnect,
241*4882a593Smuzhiyun .test_port = bpck6_test_port,
242*4882a593Smuzhiyun .probe_unit = bpck6_probe_unit,
243*4882a593Smuzhiyun .log_adapter = bpck6_log_adapter,
244*4882a593Smuzhiyun .init_proto = bpck6_init_proto,
245*4882a593Smuzhiyun .release_proto = bpck6_release_proto,
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun
bpck6_init(void)248*4882a593Smuzhiyun static int __init bpck6_init(void)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n");
251*4882a593Smuzhiyun printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n");
252*4882a593Smuzhiyun if(verbose)
253*4882a593Smuzhiyun printk(KERN_DEBUG "bpck6: verbose debug enabled.\n");
254*4882a593Smuzhiyun return paride_register(&bpck6);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
bpck6_exit(void)257*4882a593Smuzhiyun static void __exit bpck6_exit(void)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun paride_unregister(&bpck6);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun MODULE_LICENSE("GPL");
263*4882a593Smuzhiyun MODULE_AUTHOR("Micro Solutions Inc.");
264*4882a593Smuzhiyun MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
265*4882a593Smuzhiyun module_param(verbose, bool, 0644);
266*4882a593Smuzhiyun module_init(bpck6_init)
267*4882a593Smuzhiyun module_exit(bpck6_exit)
268