Back to home page

OSCL-LXR

 
 

    


0001 /* 
0002     friq.c  (c) 1998    Grant R. Guenther <grant@torque.net>
0003                     Under the terms of the GNU General Public License
0004 
0005     friq.c is a low-level protocol driver for the Freecom "IQ"
0006     parallel port IDE adapter.   Early versions of this adapter
0007     use the 'frpw' protocol.
0008     
0009     Freecom uses this adapter in a battery powered external 
0010     CD-ROM drive.  It is also used in LS-120 drives by
0011     Maxell and Panasonic, and other devices.
0012 
0013     The battery powered drive requires software support to
0014     control the power to the drive.  This module enables the
0015     drive power when the high level driver (pcd) is loaded
0016     and disables it when the module is unloaded.  Note, if
0017     the friq module is built in to the kernel, the power
0018     will never be switched off, so other means should be
0019     used to conserve battery power.
0020 
0021 */
0022 
0023 /* Changes:
0024 
0025     1.01    GRG 1998.12.20   Added support for soft power switch
0026 */
0027 
0028 #define FRIQ_VERSION    "1.01" 
0029 
0030 #include <linux/module.h>
0031 #include <linux/init.h>
0032 #include <linux/delay.h>
0033 #include <linux/kernel.h>
0034 #include <linux/types.h>
0035 #include <linux/wait.h>
0036 #include <asm/io.h>
0037 
0038 #include "paride.h"
0039 
0040 #define CMD(x)      w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
0041             w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
0042 
0043 #define j44(l,h)    (((l>>4)&0x0f)|(h&0xf0))
0044 
0045 /* cont = 0 - access the IDE register file 
0046    cont = 1 - access the IDE command set 
0047 */
0048 
0049 static int  cont_map[2] = { 0x08, 0x10 };
0050 
0051 static int friq_read_regr( PIA *pi, int cont, int regr )
0052 
0053 {   int h,l,r;
0054 
0055     r = regr + cont_map[cont];
0056 
0057     CMD(r);
0058     w2(6); l = r1();
0059     w2(4); h = r1();
0060     w2(4); 
0061 
0062     return j44(l,h);
0063 
0064 }
0065 
0066 static void friq_write_regr( PIA *pi, int cont, int regr, int val)
0067 
0068 {   int r;
0069 
0070         r = regr + cont_map[cont];
0071 
0072     CMD(r);
0073     w0(val);
0074     w2(5);w2(7);w2(5);w2(4);
0075 }
0076 
0077 static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
0078 
0079 {       int     h, l, k, ph;
0080 
0081         switch(pi->mode) {
0082 
0083         case 0: CMD(regr); 
0084                 for (k=0;k<count;k++) {
0085                         w2(6); l = r1();
0086                         w2(4); h = r1();
0087                         buf[k] = j44(l,h);
0088                 }
0089                 w2(4);
0090                 break;
0091 
0092         case 1: ph = 2;
0093                 CMD(regr+0xc0); 
0094                 w0(0xff);
0095                 for (k=0;k<count;k++) {
0096                         w2(0xa4 + ph); 
0097                         buf[k] = r0();
0098                         ph = 2 - ph;
0099                 } 
0100                 w2(0xac); w2(0xa4); w2(4);
0101                 break;
0102 
0103     case 2: CMD(regr+0x80);
0104         for (k=0;k<count-2;k++) buf[k] = r4();
0105         w2(0xac); w2(0xa4);
0106         buf[count-2] = r4();
0107         buf[count-1] = r4();
0108         w2(4);
0109         break;
0110 
0111     case 3: CMD(regr+0x80);
0112                 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
0113                 w2(0xac); w2(0xa4);
0114                 buf[count-2] = r4();
0115                 buf[count-1] = r4();
0116                 w2(4);
0117                 break;
0118 
0119     case 4: CMD(regr+0x80);
0120                 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
0121                 buf[count-4] = r4();
0122                 buf[count-3] = r4();
0123                 w2(0xac); w2(0xa4);
0124                 buf[count-2] = r4();
0125                 buf[count-1] = r4();
0126                 w2(4);
0127                 break;
0128 
0129         }
0130 }
0131 
0132 static void friq_read_block( PIA *pi, char * buf, int count)
0133 
0134 {   friq_read_block_int(pi,buf,count,0x08);
0135 }
0136 
0137 static void friq_write_block( PIA *pi, char * buf, int count )
0138  
0139 {   int k;
0140 
0141     switch(pi->mode) {
0142 
0143     case 0:
0144     case 1: CMD(8); w2(5);
0145             for (k=0;k<count;k++) {
0146             w0(buf[k]);
0147             w2(7);w2(5);
0148         }
0149         w2(4);
0150         break;
0151 
0152     case 2: CMD(0xc8); w2(5);
0153         for (k=0;k<count;k++) w4(buf[k]);
0154         w2(4);
0155         break;
0156 
0157         case 3: CMD(0xc8); w2(5);
0158                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
0159                 w2(4);
0160                 break;
0161 
0162         case 4: CMD(0xc8); w2(5);
0163                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
0164                 w2(4);
0165                 break;
0166     }
0167 }
0168 
0169 static void friq_connect ( PIA *pi  )
0170 
0171 {       pi->saved_r0 = r0();
0172         pi->saved_r2 = r2();
0173     w2(4);
0174 }
0175 
0176 static void friq_disconnect ( PIA *pi )
0177 
0178 {       CMD(0x20);
0179     w0(pi->saved_r0);
0180         w2(pi->saved_r2);
0181 } 
0182 
0183 static int friq_test_proto( PIA *pi, char * scratch, int verbose )
0184 
0185 {       int     j, k, r;
0186     int e[2] = {0,0};
0187 
0188     pi->saved_r0 = r0();    
0189     w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
0190     udelay(500);
0191     w0(pi->saved_r0);
0192 
0193     friq_connect(pi);
0194     for (j=0;j<2;j++) {
0195                 friq_write_regr(pi,0,6,0xa0+j*0x10);
0196                 for (k=0;k<256;k++) {
0197                         friq_write_regr(pi,0,2,k^0xaa);
0198                         friq_write_regr(pi,0,3,k^0x55);
0199                         if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
0200                         }
0201                 }
0202     friq_disconnect(pi);
0203 
0204     friq_connect(pi);
0205         friq_read_block_int(pi,scratch,512,0x10);
0206         r = 0;
0207         for (k=0;k<128;k++) if (scratch[k] != k) r++;
0208     friq_disconnect(pi);
0209 
0210         if (verbose)  {
0211             printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",
0212                    pi->device,pi->port,pi->mode,e[0],e[1],r);
0213         }
0214 
0215         return (r || (e[0] && e[1]));
0216 }
0217 
0218 
0219 static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
0220 
0221 {       char    *mode_string[6] = {"4-bit","8-bit",
0222                    "EPP-8","EPP-16","EPP-32"};
0223 
0224         printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device,
0225         FRIQ_VERSION,pi->port);
0226         printk("mode %d (%s), delay %d\n",pi->mode,
0227         mode_string[pi->mode],pi->delay);
0228 
0229     pi->private = 1;
0230     friq_connect(pi);
0231     CMD(0x9e);          /* disable sleep timer */
0232     friq_disconnect(pi);
0233 
0234 }
0235 
0236 static void friq_release_proto( PIA *pi)
0237 {
0238     if (pi->private) {      /* turn off the power */
0239         friq_connect(pi);
0240         CMD(0x1d); CMD(0x1e);
0241         friq_disconnect(pi);
0242         pi->private = 0;
0243     }
0244 }
0245 
0246 static struct pi_protocol friq = {
0247     .owner      = THIS_MODULE,
0248     .name       = "friq",
0249     .max_mode   = 5,
0250     .epp_first  = 2,
0251     .default_delay  = 1,
0252     .max_units  = 1,
0253     .write_regr = friq_write_regr,
0254     .read_regr  = friq_read_regr,
0255     .write_block    = friq_write_block,
0256     .read_block = friq_read_block,
0257     .connect    = friq_connect,
0258     .disconnect = friq_disconnect,
0259     .test_proto = friq_test_proto,
0260     .log_adapter    = friq_log_adapter,
0261     .release_proto  = friq_release_proto,
0262 };
0263 
0264 static int __init friq_init(void)
0265 {
0266     return paride_register(&friq);
0267 }
0268 
0269 static void __exit friq_exit(void)
0270 {
0271     paride_unregister(&friq);
0272 }
0273 
0274 MODULE_LICENSE("GPL");
0275 module_init(friq_init)
0276 module_exit(friq_exit)