linux/drivers/block/paride/friq.c
<<
>>
Prefs
   1/* 
   2        friq.c  (c) 1998    Grant R. Guenther <grant@torque.net>
   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
  49static int  cont_map[2] = { 0x08, 0x10 };
  50
  51static 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
  66static 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
  77static 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
 132static void friq_read_block( PIA *pi, char * buf, int count)
 133
 134{       friq_read_block_int(pi,buf,count,0x08);
 135}
 136
 137static 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
 169static void friq_connect ( PIA *pi  )
 170
 171{       pi->saved_r0 = r0();
 172        pi->saved_r2 = r2();
 173        w2(4);
 174}
 175
 176static void friq_disconnect ( PIA *pi )
 177
 178{       CMD(0x20);
 179        w0(pi->saved_r0);
 180        w2(pi->saved_r2);
 181} 
 182
 183static 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
 219static 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
 236static 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
 246static 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
 264static int __init friq_init(void)
 265{
 266        return paride_register(&friq);
 267}
 268
 269static void __exit friq_exit(void)
 270{
 271        paride_unregister(&friq);
 272}
 273
 274MODULE_LICENSE("GPL");
 275module_init(friq_init)
 276module_exit(friq_exit)
 277