patch-2.1.77 linux/drivers/block/ez.c
Next file: linux/drivers/block/genhd.c
Previous file: linux/drivers/block/Makefile
Back to the patch index
Back to the overall index
- Lines: 1023
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.1.76/linux/drivers/block/ez.c
- Orig date:
Thu May 29 21:53:05 1997
diff -u --recursive --new-file v2.1.76/linux/drivers/block/ez.c linux/drivers/block/ez.c
@@ -1,1022 +0,0 @@
-/*
- ez.c (c) 1996 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU public license.
-
- This is a driver for the parallel port versions of SyQuest's
- EZ135 and EZ230 removable media disk drives.
-
- Special thanks go to Pedro Soria-Rodriguez for his help testing
- the EZFlyer 230 support.
-
- The drive is actually SyQuest's IDE product with a
- ShuttleTech IDE <-> parallel converter chip built in.
-
- To compile the driver, ensure that /usr/include/linux and
- /usr/include/asm are links to the correct include files for
- the target system. Then compile the driver with
-
- cc -D__KERNEL__ -DMODULE -O2 -c ez.c
-
- If you are using MODVERSIONS, add the following to the cc command:
-
- -DMODVERSIONS -I /usr/include/linux/modversions.h
-
- You must then load it with insmod.
-
- Before attempting to access the new driver, you will need to
- create some device special files. The following commands will
- do that for you:
-
- mknod /dev/eza b 40 0
- mknod /dev/eza1 b 40 1
- mknod /dev/eza2 b 40 2
- mknod /dev/eza3 b 40 3
- mknod /dev/eza4 b 40 4
- chown root:disk /dev/ez*
- chmod 660 /dev/ez*
-
- You can make devices for more partitions (up to 15) if you need to.
-
- You can alter the port used by the driver in two ways: either
- change the definition of EZ_BASE or modify the ez_base variable
- on the insmod command line, for example:
-
- insmod ez ez_base=0x3bc
-
- The driver can detect if the parallel port supports 8-bit
- transfers. If so, it will use them. You can force it to use
- 4-bit (nybble) mode by setting the variable ez_nybble to 1.
-
- The driver can be used with or without interrupts. If an IRQ
- is specified in the variable ez_irq, the driver will use it.
- If ez_irq is set to 0, an alternative, polling-based, strategy
- will be used.
-
- If you experience timeout errors while using this driver - and
- you have enabled interrupts - try disabling the interrupt. I
- have heard reports of some parallel ports having exceptionally
- unreliable interrupts. This could happen on misconfigured
- systems in which an inactive sound card shares the same IRQ with
- the parallel port. (Remember that most people do not use the
- parallel port interrupt for printing.)
-
- It would be advantageous to use multiple mode transfers,
- but ShuttleTech's driver does not appear to use them, so I'm not
- sure that the converter can handle it.
-
- It is not currently possible to connect a printer to the chained
- port on the EZ135p and expect Linux to use both devices at once.
-
- When the EZ230 powers on, the "standby timer" is set to about 6
- minutes: if the drive is idle for that length of time, it will
- put itself into a low power standby mode. It takes a couple of
- seconds for the drive to come out of standby mode. So, if you
- load this driver while it is in standby mode, you will notice
- a "freeze" of a second or two as the driver waits for the EZ230
- to come back to life. Once loaded, this driver disables the
- standby timer (until you next power up the EZ230 ...)
-
- Keep an eye on http://www.torque.net/ez135.html for news and
- other information about the driver. If you have any problems
- with this driver, please send me, grant@torque.net, some mail
- directly before posting into the newsgroups or mailing lists.
-
-*/
-
-#define EZ_VERSION "0.11"
-
-#define EZ_BASE 0x378
-#define EZ_IRQ 7
-#define EZ_REP 4
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/tqueue.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define EZ_BITS 4 /* compatible with SCSI version */
-#define EZ_MAJOR 40 /* as assigned by hpa */
-
-#define MAJOR_NR EZ_MAJOR
-
-/* set up defines for blk.h, why don't all drivers do it this way ? */
-
-#define DEVICE_NAME "ez"
-#define DEVICE_REQUEST do_ez_request
-#define DEVICE_NR(device) (MINOR(device)>>EZ_BITS)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-
-#include <linux/blk.h>
-
-#define EZ_PARTNS (1<<EZ_BITS)
-
-#define EZ_LOG_HEADS 64
-#define EZ_LOG_SECTS 32 /* SCSI compatible logical geometry */
-
-#define EZ_SIGOFF 54
-#define EZ_SIG "ySuQse tZE"
-#define EZ_SIGLEN 10
-#define EZ_ID_LEN 14
-
-#define EZ_TMO 250 /* interrupt timeout in jiffies */
-
-#define EZ_SPIN_DEL 50 /* spin delay in micro-seconds */
-
-#define EZ_SPIN (10000/EZ_SPIN_DEL)*EZ_TMO
-#define EZ_ISPIN (10000/EZ_SPIN_DEL)*20
-#define EZ_DELAY udelay(EZ_SPIN_DEL)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-
-#define ERR_AMNF 0x00100
-#define ERR_TK0NF 0x00200
-#define ERR_ABRT 0x00400
-#define ERR_MCR 0x00800
-#define ERR_IDNF 0x01000
-#define ERR_MC 0x02000
-#define ERR_UNC 0x04000
-#define ERR_TMO 0x10000
-
-#define IDE_READ 0x20
-#define IDE_WRITE 0x30
-#define IDE_STANDBY 0x96
-#define IDE_DOORLOCK 0xde
-#define IDE_DOORUNLOCK 0xdf
-#define IDE_ACKCHANGE 0xdb
-#define IDE_IDENTIFY 0xec
-
-int ez_init(void);
-void ez_setup(char * str, int * ints);
-#ifdef MODULE
-void cleanup_module( void );
-#endif
-static void ez_geninit(struct gendisk *ignored);
-static int ez_open(struct inode *inode, struct file *file);
-static void do_ez_request(void);
-static int ez_ioctl(struct inode *inode,struct file *file,
- unsigned int cmd, unsigned long arg);
-static int ez_release (struct inode *inode, struct file *file);
-static int ez_revalidate(kdev_t dev);
-static int ez_check_media(kdev_t dev);
-static void ez_get_capacity( void );
-static int ez_detect(void);
-static void do_ez_read(void);
-static void do_ez_write(void);
-static void ez_media_check(void);
-static void ez_doorlock(int func);
-static void ez_interrupt( int irq, void * dev_id, struct pt_regs * regs);
-static void ez_pseudo( void *data);
-static void ez_timer_int( unsigned long data);
-static void do_ez_read_drq( void );
-static void do_ez_write_done( void );
-
-static struct hd_struct ez[EZ_PARTNS];
-static int ez_sizes[EZ_PARTNS];
-static int ez_blocksizes[EZ_PARTNS];
-
-static int ez_base = EZ_BASE;
-static int ez_irq = EZ_IRQ;
-static int ez_rep = EZ_REP;
-static int ez_nybble = 0; /* force 4-bit mode ? */
-
-static int ez_valid = 0; /* OK to open */
-static int ez_access = 0; /* count of active opens ... */
-static int ez_changed = 0; /* Did we see new media on open ? */
-static int ez_capacity = 512*16*32; /* Size of this volume in sectors */
-static int ez_heads = 16; /* physical geometry */
-static int ez_sectors = 32;
-static int ez_mode = 1; /* 4- or 8-bit mode */
-static int ez_loops = 0; /* counter for pseudo-interrupts */
-static int ez_timeout = 0; /* did the interrupt time out ? */
-static int ez_int_seen = 0; /* have we ever seen an interrupt ? */
-static int ez_busy = 0; /* request being processed ? */
-static int ez_block; /* address of next requested block */
-static int ez_count; /* number of blocks still to do */
-static char * ez_buf; /* buffer for request in progress */
-static char ez_scratch[512]; /* scratch block buffer */
-static void (*ez_continuation)(void); /* i/o completion handler */
-
-char *ez_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
- "READY","BUSY","AMNF","TK0NF","ABRT","MCR",
- "IDNF","MC","UNC","???","TMO"};
-
-static struct tq_struct ez_tq = {0,0,ez_pseudo,NULL};
-static struct timer_list ez_timer = {0,0,0,0,ez_timer_int};
-static struct wait_queue *ez_wait_open = NULL;
-
-/* kernel glue structures */
-
-static struct gendisk ez_gendisk = {
- MAJOR_NR, /* Major number */
- "ez", /* Major name */
- EZ_BITS, /* Bits to shift to get real from partition */
- EZ_PARTNS, /* Number of partitions per real */
- 1, /* maximum number of real */
- ez_geninit, /* init function */
- ez, /* hd struct */
- ez_sizes, /* block sizes */
- 0, /* number */
- NULL, /* internal */
- NULL /* next */
-};
-
-static struct file_operations ez_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- ez_ioctl, /* ioctl */
- NULL, /* mmap */
- ez_open, /* open */
- ez_release, /* release */
- block_fsync, /* fsync */
- NULL, /* fasync */
- ez_check_media, /* media change ? */
- ez_revalidate /* revalidate new media */
-};
-
-__initfunc(int ez_init (void)) /* preliminary initialisation */
-
-{
- if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) {
- printk("ez_init: unable to get major number %d\n",MAJOR_NR);
- return -1;
- }
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
- ez_gendisk.next = gendisk_head;
- gendisk_head = &ez_gendisk;
-
- return 0;
-}
-
-__initfunc(static void ez_geninit (struct gendisk *ignored)) /* real init */
-
-{ int i;
-
- ez_gendisk.nr_real = 0;
-
- if (ez_detect()) {
- ez_busy = 0;
- ez_valid = 1;
- ez_gendisk.nr_real = 1;
- ez[0].nr_sects = ez_capacity;
- for(i=0;i<EZ_PARTNS;i++) ez_blocksizes[i] = 1024;
- blksize_size[MAJOR_NR] = ez_blocksizes;
- }
-#ifdef MODULE
- else cleanup_module();
-#endif
-}
-
-static int ez_open (struct inode *inode, struct file *file)
-
-{ int dev = DEVICE_NR(inode->i_rdev);
-
- if (dev >= ez_gendisk.nr_real) return -ENODEV;
-
- MOD_INC_USE_COUNT;
-
- while (!ez_valid) sleep_on(&ez_wait_open);
- ez_access++;
- ez_media_check();
- ez_doorlock(IDE_DOORLOCK);
- return 0;
-}
-
-static void do_ez_request (void)
-
-{ int dev;
-
- if (ez_busy) return;
-repeat:
- if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
- INIT_REQUEST;
-
- dev = MINOR(CURRENT->rq_dev);
- ez_block = CURRENT->sector;
- ez_count = CURRENT->nr_sectors;
-
- if ((dev >= EZ_PARTNS) || ((ez_block+ez_count) > ez[dev].nr_sects)) {
- end_request(0);
- goto repeat;
- }
-
- ez_block += ez[dev].start_sect;
- ez_buf = CURRENT->buffer;
-
- if (CURRENT->cmd == READ) do_ez_read();
- else if (CURRENT->cmd == WRITE) do_ez_write();
- else { end_request(0);
- goto repeat;
- }
-}
-
-static int ez_ioctl(struct inode *inode,struct file *file,
- unsigned int cmd, unsigned long arg)
-
-{ struct hd_geometry *geo = (struct hd_geometry *) arg;
- int dev, err;
-
- if ((!inode) || (!inode->i_rdev)) return -EINVAL;
- dev = MINOR(inode->i_rdev);
- if (dev >= EZ_PARTNS) return -EINVAL;
-
- switch (cmd) {
- case HDIO_GETGEO:
- if (!geo) return -EINVAL;
- err = verify_area(VERIFY_WRITE,geo,sizeof(*geo));
- if (err) return err;
- put_user(ez_capacity/(EZ_LOG_HEADS*EZ_LOG_SECTS),
- (short *) &geo->cylinders);
- put_user(EZ_LOG_HEADS, (char *) &geo->heads);
- put_user(EZ_LOG_SECTS, (char *) &geo->sectors);
- put_user(ez[dev].start_sect,(long *)&geo->start);
- return 0;
- case BLKRASET:
- if(!suser()) return -EACCES;
- if(!(inode->i_rdev)) return -EINVAL;
- if(arg > 0xff) return -EINVAL;
- read_ahead[MAJOR(inode->i_rdev)] = arg;
- return 0;
- case BLKRAGET:
- if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
- if (err) return (err);
- put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
- return (0);
- case BLKGETSIZE:
- if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
- if (err) return (err);
- put_user(ez[dev].nr_sects,(long *) arg);
- return (0);
- case BLKFLSBUF:
- if(!suser()) return -EACCES;
- if(!(inode->i_rdev)) return -EINVAL;
- fsync_dev(inode->i_rdev);
- invalidate_buffers(inode->i_rdev);
- return 0;
- case BLKRRPART:
- return ez_revalidate(inode->i_rdev);
- RO_IOCTLS(inode->i_rdev,arg);
- default:
- return -EINVAL;
- }
-}
-
-static int ez_release (struct inode *inode, struct file *file)
-
-{ kdev_t devp;
-
- devp = inode->i_rdev;
- if (DEVICE_NR(devp) == 0) {
- fsync_dev(devp);
- invalidate_inodes(devp);
- invalidate_buffers(devp);
- ez_access--;
- if (!ez_access) ez_doorlock(IDE_DOORUNLOCK);
- MOD_DEC_USE_COUNT;
- }
- return 0;
-}
-
-static int ez_check_media( kdev_t dev)
-
-{ int t;
-
- t = ez_changed;
- ez_changed = 0;
- return t;
-}
-
-static int ez_revalidate(kdev_t dev)
-
-{ int p;
- long flags;
- kdev_t devp;
-
- save_flags(flags);
- cli();
- if (ez_access > 1) {
- restore_flags(flags);
- return -EBUSY;
- }
- ez_valid = 0;
- restore_flags(flags);
-
- for (p=(EZ_PARTNS-1);p>=0;p--) {
- devp = MKDEV(MAJOR_NR, p);
- fsync_dev(devp);
- invalidate_inodes(devp);
- invalidate_buffers(devp);
- ez[p].start_sect = 0;
- ez[p].nr_sects = 0;
- }
-
- ez_get_capacity();
- ez[0].nr_sects = ez_capacity;
- resetup_one_dev(&ez_gendisk,0);
-
- ez_valid = 1;
- wake_up(&ez_wait_open);
-
- return 0;
-}
-
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void cleanup_module(void);
-
-int init_module(void)
-
-{ int err;
- long flags;
-
- save_flags(flags);
- cli();
-
- err = ez_init();
- if (err) {
- restore_flags(flags);
- return err;
- }
- ez_geninit(&ez_gendisk);
-
- if (!ez_gendisk.nr_real) {
- restore_flags(flags);
- return -1;
- }
-
- ez_valid = 0;
- resetup_one_dev(&ez_gendisk,0);
- ez_valid = 1;
-
- restore_flags(flags);
- return 0;
-}
-
-void cleanup_module(void)
-
-{ struct gendisk **gdp;
- long flags;
-
- save_flags(flags);
- cli();
-
- unregister_blkdev(MAJOR_NR,"ez");
-
- for(gdp=&gendisk_head;*gdp;gdp=&((*gdp)->next))
- if (*gdp == &ez_gendisk) break;
- if (*gdp) *gdp = (*gdp)->next;
-
- if (ez_gendisk.nr_real) {
- release_region(ez_base,3);
- if (ez_irq) free_irq(ez_irq,NULL);
- }
-
- restore_flags(flags);
-}
-
-#else
-
-/* ez_setup: process lilo command parameters ...
-
- syntax: ez=base[,irq[,rep[,nybble]]]
-*/
-
-__initfunc(void ez_setup(char *str, int *ints))
-
-{ if (ints[0] > 0) ez_base = ints[1];
- if (ints[0] > 1) ez_irq = ints[2];
- if (ints[0] > 2) ez_rep = ints[3];
- if (ints[0] > 3) ez_nybble = ints[4];
-}
-
-#endif
-
-/* Now the actual hardware interface to the EZ135p */
-
-static void out_p( short port, char byte)
-
-{ int i;
-
- for(i=0;i<ez_rep;i++) outb(byte,ez_base+port);
-}
-
-static int in_p( short port)
-
-{ int i;
- char c;
-
- c=inb(ez_base+port);
- for(i=1;i<ez_rep;i++) c=inb(ez_base+port);
- return c & 0xff;
-}
-
-#define w0(byte) out_p(0,byte)
-#define w2(byte) out_p(2,byte)
-#define r0() (in_p(0) & 0xff)
-#define r1() (in_p(1) & 0xff)
-
-/* register access functions */
-
-static int read_regr( char regr )
-
-{ int h, l;
-
- if (ez_mode == 1) { /* nybble mode */
- w0(regr);
- w2(1); w2(3);
- l = r1() >> 4;
- w2(4);
- h = r1() & 0xf0;
- return h + l;
- } else { /* byte mode */
- w0(regr+0x20);
- w2(1); w2(0x25);
- h = r0();
- w2(4);
- return h;
- }
-}
-
-static void write_regr( char regr, char val )
-
-{ w0(regr);
- w2(1);
- w0(val);
- w2(4);
-}
-
-/* connect / disconnect code */
-
-static void prefix( char byte )
-
-{ w2(4); w0(0x22); w0(0xaa); w0(0x55); w0(0);
- w0(0xff); w0(0x87); w0(0x78); w0(byte);
- w2(5); w2(4); w0(0xff);
-}
-
-static void connect ( void )
-
-{ prefix(0x40); prefix(0x50); prefix(0xe0);
- w0(0); w2(1); w2(4);
- read_regr(0xd);
- write_regr(0x6d,0xe8);
- write_regr(0x6c,0x1c);
- write_regr(0x72,0x10);
- write_regr(0x6a,0x38);
- write_regr(0x68,0x10);
- read_regr(0x12);
- write_regr(0x72,0x10);
- read_regr(0xd);
- write_regr(0x6d,0xaa);
- write_regr(0x6d,0xaa);
-}
-
-static void disconnect ( void )
-
-{ read_regr(0xd);
- write_regr(0x6d,0xa8);
- prefix(0x30);
-}
-
-/* basic i/o */
-
-static void read_block( char * buf )
-
-/* the nybble mode read has a curious optimisation in it: there are actually
- five bits available on each read. The extra bit is used to signal that
- the next nybble is identical ... I wonder how much research went into
- designing this use of the extra bit ?
-*/
-
-{ int j, k, n0, n1, n2, n3;
-
- read_regr(0xd); write_regr(0x6d,0xe9);
-
- j = 0;
- if (ez_mode == 1) { /* nybble mode */
-
- w0(7); w2(1); w2(3); w0(0xff);
- for(k=0;k<256;k++) {
- w2(6); n0 = r1();
- if (n0 & 8) n1 = n0; else { w2(4); n1 = r1(); }
- w2(7); n2 = r1();
- if (n2 & 8) n3 = n2; else { w2(5); n3 = r1(); }
- buf[j++] = (n0 >> 4) + (n1 & 0xf0);
- buf[j++] = (n2 >> 4) + (n3 & 0xf0);
- }
-
- } else { /* byte mode */
-
- w0(0x27); w2(1); w2(0x25); w0(0);
- for(k=0;k<256;k++) {
- w2(0x24); buf[j++] = r0();
- w2(0x25); buf[j++] = r0();
- }
- w2(0x26); w2(0x27); w0(0); w2(0x25); w2(4);
-
- }
-}
-
-static void write_block( char * buf )
-
-{ int j;
-
- read_regr(0xd); write_regr(0x6d,0xe9);
-
- w0(0x67); w2(1); w2(5);
- for(j=0;j<256;j++) {
- w0(buf[2*j]); w2(4);
- w0(buf[2*j+1]); w2(5);
- }
- w2(7); w2(4);
-}
-
-/* ide command interface */
-
-void ez_print_error( char * msg, int status )
-
-{ char *e, *p;
- int i;
-
- e = ez_scratch;
- for(i=0;i<18;i++) if (status & (1<<i)) {
- p = ez_errs[i];
- while ((*e++=*p++));
- *(e-1) = ' ';
- }
- if (status) e--;
- *e = 0;
- printk("ez: %s: status = 0x%x (%s)\n",msg,status,ez_scratch);
-}
-
-static int wait_for( int w, char * msg ) /* polled wait */
-
-{ int k, r, e;
-
- k=0;
- while(k < EZ_SPIN) {
- r = read_regr(0x1f);
- k++;
- if (ez_timeout) break;
- if (((r & w) == w) && !(r & STAT_BUSY)) break;
- EZ_DELAY;
- }
- e = (read_regr(0x19)<<8) + r;
- if ((k >= EZ_SPIN) || ez_timeout) e |= (ERR_TMO|STAT_ERR);
- if ((e & STAT_ERR) & (msg != NULL)) ez_print_error(msg,e);
- return e;
-}
-
-static void send_command( int n, int s, int h, int c0, int c1, int func )
-
-{
- read_regr(0xd); write_regr(0x6d,0xa9);
-
- write_regr(0x76,0);
- write_regr(0x79,0); /* the IDE task file */
- write_regr(0x7a,n);
- write_regr(0x7b,s);
- write_regr(0x7c,c0);
- write_regr(0x7d,c1);
- write_regr(0x7e,0xa0+h);
- write_regr(0x7f,func);
-
- udelay(1);
-}
-
-static void ez_ide_command( int func, int block )
-
-{ int c1, c0, h, s;
-
- s = ( block % ez_sectors) + 1;
- h = ( block / ez_sectors) % ez_heads;
- c0 = ( block / (ez_sectors*ez_heads)) % 256;
- c1 = ( block / (ez_sectors*ez_heads*256));
-
- send_command(1,s,h,c0,c1,func);
-}
-
-static void ez_gate_intr( int flag )
-
-{ if (flag) write_regr(0x6d,0x39); /* gate interrupt line to bus */
- if (flag && ez_irq) w2(0x14); /* enable IRQ */
- if (!flag) w2(4); /* disable IRQ */
-}
-
-static int check_int( void ) /* is the interrupt bit set ? */
-
-{ return (r1() & 0x40);
-}
-
-static void ez_doorlock( int func )
-
-{ connect();
- if (wait_for(STAT_READY,"Lock") & STAT_ERR) {
- disconnect();
- return;
- }
- ez_ide_command(func,0);
- wait_for(STAT_READY,"Lock done");
- disconnect();
-}
-
-/* ez_media_check: check for and acknowledge the MC flag */
-
-__initfunc(static void ez_media_check( void ))
-
-{ int r;
-
- ez_changed = 0;
- connect();
- r = wait_for(STAT_READY,"Media check ready");
- if (!(r & STAT_ERR)) {
- ez_ide_command(IDE_READ,0); /* try to read block 0 */
- r = wait_for(STAT_DRQ,"Media check");
- if (!(r & STAT_ERR)) read_block(ez_scratch);
- } else ez_changed = 1; /* say changed if other error */
- if (r & ERR_MC) {
- ez_changed = 1;
- ez_ide_command(IDE_ACKCHANGE,0);
- wait_for(STAT_READY,"Ack. media change");
- }
- disconnect();
-}
-
-__initfunc(static int ez_identify( void ))
-
-
-{ int k, r;
-
- connect();
- wait_for(0,NULL); /* wait until not busy, quietly */
- ez_ide_command(IDE_IDENTIFY,0);
-
- if (ez_irq) { /* check that the interrupt works */
- ez_gate_intr(1);
- k = 0;
- while ((k++ < EZ_ISPIN) && !ez_int_seen) EZ_DELAY;
- ez_gate_intr(0);
- r = read_regr(0x1f);
- if ((!ez_int_seen) || !(r & STAT_DRQ)) {
- free_irq(ez_irq,NULL);
- ez_irq = 0;
- }
- }
-
- if (wait_for(STAT_DRQ,NULL) & STAT_ERR) {
- disconnect();
- return 0;
- }
- read_block(ez_scratch);
- disconnect();
- return 1;
-}
-
-#define word_val(n) (ez_scratch[2*n]+256*ez_scratch[2*n+1])
-
-__initfunc(static void ez_get_capacity( void ))
-
-{ int ez_cylinders;
-
- connect();
- wait_for(0,NULL);
- ez_ide_command(IDE_IDENTIFY,0);
- if (wait_for(STAT_DRQ,"Get capacity") & STAT_ERR) {
- disconnect();
- return;
- }
- read_block(ez_scratch);
- disconnect();
- ez_sectors = word_val(6);
- ez_heads = word_val(3);
- ez_cylinders = word_val(1);
- ez_capacity = ez_sectors*ez_heads*ez_cylinders;
- printk("ez: Capacity = %d, (%d/%d/%d)\n",ez_capacity,ez_cylinders,
- ez_heads,ez_sectors);
-}
-
-__initfunc(static void ez_standby_off( void ))
-
-{ connect();
- wait_for(0,NULL);
- send_command(0,0,0,0,0,IDE_STANDBY);
- wait_for(0,NULL);
- disconnect();
-}
-
-__initfunc(static int ez_port_check( void )) /* check for 8-bit port */
-
-{ int r;
-
- w2(0);
- w0(0x55); if (r0() != 0x55) return 0;
- w0(0xaa); if (r0() != 0xaa) return 0;
- w2(0x20); w0(0x55); r = r0(); w0(0xaa);
- if (r0() == r) return 2;
- if (r0() == 0xaa) return 1;
- return 0;
-}
-
-__initfunc(static int ez_detect( void ))
-
-{ int j, k;
- char sig[EZ_SIGLEN] = EZ_SIG;
- char id[EZ_ID_LEN+1];
- long flags;
-
- if (check_region(ez_base,3)) {
- printk("ez: Ports at 0x%x are not available\n",ez_base);
- return 0;
- }
-
- ez_mode = ez_port_check();
- if (!ez_mode) {
- printk("ez: No parallel port at 0x%x\n",ez_base);
- return 0;
- }
-
- if (ez_irq && request_irq(ez_irq,ez_interrupt,0,"ez",NULL)) ez_irq = 0;
-
- if (ez_nybble) ez_mode = 1;
-
- request_region(ez_base,3,"ez");
-
- save_flags(flags);
- sti();
-
- k = 0;
- if (ez_identify()) {
- k = 1;
- for(j=0;j<EZ_SIGLEN;j++)
- k &= (ez_scratch[j+EZ_SIGOFF] == sig[j]);
- }
- if (k) {
- for(j=0;j<EZ_ID_LEN;j++) id[j^1] = ez_scratch[j+EZ_SIGOFF];
- id[EZ_ID_LEN] = 0;
- if (!ez_irq) printk("ez %s: %s at 0x%x, %d-bit mode.\n",
- EZ_VERSION,id,ez_base,4*ez_mode);
- else printk("ez %s: %s at 0x%x, IRQ %d, %d-bit mode.\n",
- EZ_VERSION,id,ez_base,ez_irq,4*ez_mode);
- ez_standby_off();
- ez_media_check();
- ez_get_capacity();
- restore_flags(flags);
- return 1;
- }
- restore_flags(flags);
- release_region(ez_base,3);
- if (ez_irq) free_irq(ez_irq,NULL);
- printk("ez: Drive not detected\n");
- return 0;
-}
-
-/* interrupt management */
-
-static void ez_set_intr( void (*continuation)(void) )
-
-{ ez_continuation = continuation;
- ez_loops = 1; ez_timeout = 0;
- ez_gate_intr(1);
- if (ez_irq) {
- ez_timer.expires = jiffies + EZ_TMO;
- add_timer(&ez_timer);
- } else queue_task(&ez_tq,&tq_scheduler);
-}
-
-static void ez_pseudo( void *data )
-
-{ void (*con)(void);
-
- ez_timeout = (ez_loops >= EZ_TMO);
- if (check_int() || ez_timeout) {
- con = ez_continuation;
- ez_continuation = NULL;
- if (con) con();
- } else {
- ez_loops++;
- queue_task(&ez_tq,&tq_scheduler);
- }
-}
-
-static void ez_timer_int( unsigned long data)
-
-{ void (*con)(void);
-
- con = ez_continuation;
- if (!con) return;
- ez_continuation = NULL;
- ez_gate_intr(0);
- ez_timeout = 1;
- con();
-}
-
-static void ez_interrupt( int irq, void * dev_id, struct pt_regs * regs)
-
-{ void (*con)(void);
-
- ez_int_seen = 1;
- con = ez_continuation;
- if (!con) return;
- ez_gate_intr(0);
- del_timer(&ez_timer);
- ez_continuation = NULL;
- con();
-}
-
-/* The i/o request engine */
-
-#define EZ_DONE(s) { disconnect(); end_request(s); ez_busy = 0;\
- cli(); do_ez_request(); return; }
-
-static void do_ez_read( void )
-
-{ ez_busy = 1;
- if (!ez_count) {
- ez_busy = 0;
- return;
- }
- sti();
- connect();
- if (wait_for(STAT_READY,"do_ez_read") & STAT_ERR) EZ_DONE(0);
- ez_ide_command(IDE_READ,ez_block);
- ez_set_intr(do_ez_read_drq);
-}
-
-static void do_ez_read_drq( void )
-
-{ sti();
- if (wait_for(STAT_DRQ,"do_ez_read_drq") & STAT_ERR) EZ_DONE(0);
- read_block(ez_buf);
- ez_count--;
- if (ez_count) {
- ez_buf += 512;
- ez_block++;
- disconnect();
- do_ez_read();
- return;
- }
- EZ_DONE(1);
-}
-
-static void do_ez_write( void )
-
-{ ez_busy = 1;
- if (!ez_count) {
- ez_busy = 0;
- return;
- }
- sti();
- connect();
- if (wait_for(STAT_READY,"do_ez_write") & STAT_ERR)
- EZ_DONE(0);
- ez_ide_command(IDE_WRITE,ez_block);
- if (wait_for(STAT_DRQ,"do_ez_write_drq") & STAT_ERR)
- EZ_DONE(0);
- write_block(ez_buf);
- ez_set_intr(do_ez_write_done);
-}
-
-static void do_ez_write_done( void )
-
-{ sti();
- if (wait_for(STAT_READY,"do_ez_write_done") & STAT_ERR) EZ_DONE(0);
- ez_count--;
- if (ez_count) {
- ez_buf += 512;
- ez_block++;
- disconnect();
- do_ez_write();
- return;
- }
- EZ_DONE(1);
-}
-
-/* end of ez.c */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov