Back to home page

OSCL-LXR

 
 

    


0001 /* 
0002     frpw.c  (c) 1996-8  Grant R. Guenther <grant@torque.net>
0003                     Under the terms of the GNU General Public License
0004 
0005     frpw.c is a low-level protocol driver for the Freecom "Power"
0006     parallel port IDE adapter.
0007     
0008     Some applications of this adapter may require a "printer" reset
0009     prior to loading the driver.  This can be done by loading and
0010     unloading the "lp" driver, or it can be done by this driver
0011     if you define FRPW_HARD_RESET.  The latter is not recommended
0012     as it may upset devices on other ports.
0013 
0014 */
0015 
0016 /* Changes:
0017 
0018         1.01    GRG 1998.05.06 init_proto, release_proto
0019                    fix chip detect
0020                    added EPP-16 and EPP-32
0021     1.02    GRG 1998.09.23 added hard reset to initialisation process
0022     1.03    GRG 1998.12.14 made hard reset conditional
0023 
0024 */
0025 
0026 #define FRPW_VERSION    "1.03" 
0027 
0028 #include <linux/module.h>
0029 #include <linux/init.h>
0030 #include <linux/delay.h>
0031 #include <linux/kernel.h>
0032 #include <linux/types.h>
0033 #include <linux/wait.h>
0034 #include <asm/io.h>
0035 
0036 #include "paride.h"
0037 
0038 #define cec4        w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
0039 #define j44(l,h)    (((l>>4)&0x0f)|(h&0xf0))
0040 
0041 /* cont = 0 - access the IDE register file 
0042    cont = 1 - access the IDE command set 
0043 */
0044 
0045 static int  cont_map[2] = { 0x08, 0x10 };
0046 
0047 static int frpw_read_regr( PIA *pi, int cont, int regr )
0048 
0049 {   int h,l,r;
0050 
0051     r = regr + cont_map[cont];
0052 
0053     w2(4);
0054     w0(r); cec4;
0055     w2(6); l = r1();
0056     w2(4); h = r1();
0057     w2(4); 
0058 
0059     return j44(l,h);
0060 
0061 }
0062 
0063 static void frpw_write_regr( PIA *pi, int cont, int regr, int val)
0064 
0065 {   int r;
0066 
0067         r = regr + cont_map[cont];
0068 
0069     w2(4); w0(r); cec4; 
0070     w0(val);
0071     w2(5);w2(7);w2(5);w2(4);
0072 }
0073 
0074 static void frpw_read_block_int( PIA *pi, char * buf, int count, int regr )
0075 
0076 {       int     h, l, k, ph;
0077 
0078         switch(pi->mode) {
0079 
0080         case 0: w2(4); w0(regr); cec4;
0081                 for (k=0;k<count;k++) {
0082                         w2(6); l = r1();
0083                         w2(4); h = r1();
0084                         buf[k] = j44(l,h);
0085                 }
0086                 w2(4);
0087                 break;
0088 
0089         case 1: ph = 2;
0090                 w2(4); w0(regr + 0xc0); cec4;
0091                 w0(0xff);
0092                 for (k=0;k<count;k++) {
0093                         w2(0xa4 + ph); 
0094                         buf[k] = r0();
0095                         ph = 2 - ph;
0096                 } 
0097                 w2(0xac); w2(0xa4); w2(4);
0098                 break;
0099 
0100         case 2: w2(4); w0(regr + 0x80); cec4;
0101                 for (k=0;k<count;k++) buf[k] = r4();
0102                 w2(0xac); w2(0xa4);
0103                 w2(4);
0104                 break;
0105 
0106     case 3: w2(4); w0(regr + 0x80); cec4;
0107         for (k=0;k<count-2;k++) buf[k] = r4();
0108         w2(0xac); w2(0xa4);
0109         buf[count-2] = r4();
0110         buf[count-1] = r4();
0111         w2(4);
0112         break;
0113 
0114     case 4: w2(4); w0(regr + 0x80); cec4;
0115                 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
0116                 w2(0xac); w2(0xa4);
0117                 buf[count-2] = r4();
0118                 buf[count-1] = r4();
0119                 w2(4);
0120                 break;
0121 
0122     case 5: w2(4); w0(regr + 0x80); cec4;
0123                 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
0124                 buf[count-4] = r4();
0125                 buf[count-3] = r4();
0126                 w2(0xac); w2(0xa4);
0127                 buf[count-2] = r4();
0128                 buf[count-1] = r4();
0129                 w2(4);
0130                 break;
0131 
0132         }
0133 }
0134 
0135 static void frpw_read_block( PIA *pi, char * buf, int count)
0136 
0137 {   frpw_read_block_int(pi,buf,count,0x08);
0138 }
0139 
0140 static void frpw_write_block( PIA *pi, char * buf, int count )
0141  
0142 {   int k;
0143 
0144     switch(pi->mode) {
0145 
0146     case 0:
0147     case 1:
0148     case 2: w2(4); w0(8); cec4; w2(5);
0149             for (k=0;k<count;k++) {
0150             w0(buf[k]);
0151             w2(7);w2(5);
0152         }
0153         w2(4);
0154         break;
0155 
0156     case 3: w2(4); w0(0xc8); cec4; w2(5);
0157         for (k=0;k<count;k++) w4(buf[k]);
0158         w2(4);
0159         break;
0160 
0161         case 4: w2(4); w0(0xc8); cec4; w2(5);
0162                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
0163                 w2(4);
0164                 break;
0165 
0166         case 5: w2(4); w0(0xc8); cec4; w2(5);
0167                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
0168                 w2(4);
0169                 break;
0170     }
0171 }
0172 
0173 static void frpw_connect ( PIA *pi  )
0174 
0175 {       pi->saved_r0 = r0();
0176         pi->saved_r2 = r2();
0177     w2(4);
0178 }
0179 
0180 static void frpw_disconnect ( PIA *pi )
0181 
0182 {       w2(4); w0(0x20); cec4;
0183     w0(pi->saved_r0);
0184         w2(pi->saved_r2);
0185 } 
0186 
0187 /* Stub logic to see if PNP string is available - used to distinguish
0188    between the Xilinx and ASIC implementations of the Freecom adapter.
0189 */
0190 
0191 static int frpw_test_pnp ( PIA *pi )
0192 
0193 /*  returns chip_type:   0 = Xilinx, 1 = ASIC   */
0194 
0195 {   int olddelay, a, b;
0196 
0197 #ifdef FRPW_HARD_RESET
0198         w0(0); w2(8); udelay(50); w2(0xc);   /* parallel bus reset */
0199         mdelay(1500);
0200 #endif
0201 
0202     olddelay = pi->delay;
0203     pi->delay = 10;
0204 
0205     pi->saved_r0 = r0();
0206         pi->saved_r2 = r2();
0207     
0208     w2(4); w0(4); w2(6); w2(7);
0209     a = r1() & 0xff; w2(4); b = r1() & 0xff;
0210     w2(0xc); w2(0xe); w2(4);
0211 
0212     pi->delay = olddelay;
0213         w0(pi->saved_r0);
0214         w2(pi->saved_r2);
0215 
0216     return ((~a&0x40) && (b&0x40));
0217 } 
0218 
0219 /* We use the pi->private to remember the result of the PNP test.
0220    To make this work, private = port*2 + chip.  Yes, I know it's
0221    a hack :-(
0222 */
0223 
0224 static int frpw_test_proto( PIA *pi, char * scratch, int verbose )
0225 
0226 {       int     j, k, r;
0227     int e[2] = {0,0};
0228 
0229     if ((pi->private>>1) != pi->port)
0230        pi->private = frpw_test_pnp(pi) + 2*pi->port;
0231 
0232     if (((pi->private%2) == 0) && (pi->mode > 2)) {
0233        if (verbose) 
0234         printk("%s: frpw: Xilinx does not support mode %d\n",
0235             pi->device, pi->mode);
0236        return 1;
0237     }
0238 
0239     if (((pi->private%2) == 1) && (pi->mode == 2)) {
0240        if (verbose)
0241         printk("%s: frpw: ASIC does not support mode 2\n",
0242             pi->device);
0243        return 1;
0244     }
0245 
0246     frpw_connect(pi);
0247     for (j=0;j<2;j++) {
0248                 frpw_write_regr(pi,0,6,0xa0+j*0x10);
0249                 for (k=0;k<256;k++) {
0250                         frpw_write_regr(pi,0,2,k^0xaa);
0251                         frpw_write_regr(pi,0,3,k^0x55);
0252                         if (frpw_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
0253                         }
0254                 }
0255     frpw_disconnect(pi);
0256 
0257     frpw_connect(pi);
0258         frpw_read_block_int(pi,scratch,512,0x10);
0259         r = 0;
0260         for (k=0;k<128;k++) if (scratch[k] != k) r++;
0261     frpw_disconnect(pi);
0262 
0263         if (verbose)  {
0264             printk("%s: frpw: port 0x%x, chip %ld, mode %d, test=(%d,%d,%d)\n",
0265                    pi->device,pi->port,(pi->private%2),pi->mode,e[0],e[1],r);
0266         }
0267 
0268         return (r || (e[0] && e[1]));
0269 }
0270 
0271 
0272 static void frpw_log_adapter( PIA *pi, char * scratch, int verbose )
0273 
0274 {       char    *mode_string[6] = {"4-bit","8-bit","EPP",
0275                    "EPP-8","EPP-16","EPP-32"};
0276 
0277         printk("%s: frpw %s, Freecom (%s) adapter at 0x%x, ", pi->device,
0278         FRPW_VERSION,((pi->private%2) == 0)?"Xilinx":"ASIC",pi->port);
0279         printk("mode %d (%s), delay %d\n",pi->mode,
0280         mode_string[pi->mode],pi->delay);
0281 
0282 }
0283 
0284 static struct pi_protocol frpw = {
0285     .owner      = THIS_MODULE,
0286     .name       = "frpw",
0287     .max_mode   = 6,
0288     .epp_first  = 2,
0289     .default_delay  = 2,
0290     .max_units  = 1,
0291     .write_regr = frpw_write_regr,
0292     .read_regr  = frpw_read_regr,
0293     .write_block    = frpw_write_block,
0294     .read_block = frpw_read_block,
0295     .connect    = frpw_connect,
0296     .disconnect = frpw_disconnect,
0297     .test_proto = frpw_test_proto,
0298     .log_adapter    = frpw_log_adapter,
0299 };
0300 
0301 static int __init frpw_init(void)
0302 {
0303     return paride_register(&frpw);
0304 }
0305 
0306 static void __exit frpw_exit(void)
0307 {
0308     paride_unregister(&frpw);
0309 }
0310 
0311 MODULE_LICENSE("GPL");
0312 module_init(frpw_init)
0313 module_exit(frpw_exit)