linux-old/drivers/block/ps2esdi.c
<<
>>
Prefs
   1/* ps2esdi driver based on assembler code by Arindam Banerji,
   2   written by Peter De Schrijver */
   3/* Reassuring note to IBM : This driver was NOT developed by vice-versa
   4   engineering the PS/2's BIOS */
   5/* Dedicated to Wannes, Tofke, Ykke, Godot, Killroy and all those 
   6   other lovely fish out there... */
   7/* This code was written during the long and boring WINA 
   8   elections 1994 */
   9/* Thanks to Arindam Banerij for giving me the source of his driver */
  10/* This code may be freely distributed and modified in any way, 
  11   as long as these notes remain intact */
  12
  13/*  Revised: 05/07/94 by Arindam Banerji (axb@cse.nd.edu) */
  14/*  Revised: 09/08/94 by Peter De Schrijver (stud11@cc4.kuleuven.ac.be)
  15   Thanks to Arindam Banerij for sending me the docs of the adapter */
  16
  17/* BA Modified for ThinkPad 720 by Boris Ashkinazi */
  18/*                    (bash@vnet.ibm.com) 08/08/95 */
  19
  20/* Modified further for ThinkPad-720C by Uri Blumenthal */
  21/*                    (uri@watson.ibm.com) Sep 11, 1995 */
  22
  23/* TODO : 
  24   + Timeouts
  25   + Get disk parameters
  26   + DMA above 16MB
  27   + reset after read/write error
  28 */
  29
  30#include <linux/config.h>
  31#include <linux/major.h>
  32
  33#ifdef  CONFIG_BLK_DEV_PS2
  34
  35#define MAJOR_NR PS2ESDI_MAJOR
  36
  37#include <linux/errno.h>
  38#include <linux/sched.h>
  39#include <linux/mm.h>
  40#include <linux/fs.h>
  41#include <linux/kernel.h>
  42#include <linux/genhd.h>
  43#include <linux/ps2esdi.h>
  44#include <linux/devfs_fs_kernel.h>
  45#include <linux/blk.h>
  46#include <linux/blkpg.h>
  47#include <linux/mca.h>
  48#include <linux/init.h>
  49#include <linux/ioport.h>
  50#include <linux/module.h>
  51
  52#include <asm/system.h>
  53#include <asm/io.h>
  54#include <asm/segment.h>
  55#include <asm/dma.h>
  56#include <asm/mca_dma.h>
  57#include <asm/uaccess.h>
  58
  59#define PS2ESDI_IRQ 14
  60#define MAX_HD 2
  61#define MAX_RETRIES 5
  62#define MAX_16BIT 65536
  63#define ESDI_TIMEOUT   0xf000
  64#define ESDI_STAT_TIMEOUT 4
  65
  66#define TYPE_0_CMD_BLK_LENGTH 2
  67#define TYPE_1_CMD_BLK_LENGTH 4
  68
  69
  70static void reset_ctrl(void);
  71
  72int ps2esdi_init(void);
  73
  74static void ps2esdi_geninit(void);
  75
  76static void do_ps2esdi_request(request_queue_t * q);
  77
  78static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count);
  79
  80static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
  81u_short cyl, u_short head, u_short sector, u_short length, u_char drive);
  82
  83static int ps2esdi_out_cmd_blk(u_short * cmd_blk);
  84
  85static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode);
  86
  87static void ps2esdi_interrupt_handler(int irq, void *dev_id,
  88                                      struct pt_regs *regs);
  89static void (*current_int_handler) (u_int) = NULL;
  90static void ps2esdi_normal_interrupt_handler(u_int);
  91static void ps2esdi_initial_reset_int_handler(u_int);
  92static void ps2esdi_geometry_int_handler(u_int);
  93
  94static int ps2esdi_open(struct inode *inode, struct file *file);
  95
  96static int ps2esdi_release(struct inode *inode, struct file *file);
  97
  98static int ps2esdi_ioctl(struct inode *inode, struct file *file,
  99                         u_int cmd, u_long arg);
 100
 101static int ps2esdi_reread_partitions(kdev_t dev);
 102
 103static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer);
 104
 105static void dump_cmd_complete_status(u_int int_ret_code);
 106
 107static void ps2esdi_get_device_cfg(void);
 108
 109static void ps2esdi_reset_timer(unsigned long unused);
 110
 111static u_int dma_arb_level;             /* DMA arbitration level */
 112
 113static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
 114static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open);
 115
 116static int no_int_yet;
 117static int access_count[MAX_HD];
 118static char ps2esdi_valid[MAX_HD];
 119static int ps2esdi_sizes[MAX_HD << 6];
 120static int ps2esdi_blocksizes[MAX_HD << 6];
 121static int ps2esdi_maxsect[MAX_HD << 6];
 122static int ps2esdi_drives;
 123static struct hd_struct ps2esdi[MAX_HD << 6];
 124static u_short io_base;
 125static struct timer_list esdi_timer = { function: ps2esdi_reset_timer };
 126static int reset_status;
 127static int ps2esdi_slot = -1;
 128static int tp720esdi = 0;       /* Is it Integrated ESDI of ThinkPad-720? */
 129static int intg_esdi = 0;       /* If integrated adapter */
 130struct ps2esdi_i_struct {
 131        unsigned int head, sect, cyl, wpcom, lzone, ctl;
 132};
 133
 134#if 0
 135#if 0                           /* try both - I don't know which one is better... UB */
 136static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 137{
 138        {4, 48, 1553, 0, 0, 0},
 139        {0, 0, 0, 0, 0, 0}};
 140#else
 141static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 142{
 143        {64, 32, 161, 0, 0, 0},
 144        {0, 0, 0, 0, 0, 0}};
 145#endif
 146#endif
 147static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 148{
 149        {0, 0, 0, 0, 0, 0},
 150        {0, 0, 0, 0, 0, 0}};
 151
 152static struct block_device_operations ps2esdi_fops =
 153{
 154        owner:          THIS_MODULE,
 155        open:           ps2esdi_open,
 156        release:        ps2esdi_release,
 157        ioctl:          ps2esdi_ioctl,
 158};
 159
 160static struct gendisk ps2esdi_gendisk =
 161{
 162        major:          MAJOR_NR,
 163        major_name:     "ed",
 164        minor_shift:    6,
 165        max_p:          1 << 6,
 166        part:           ps2esdi,
 167        sizes:          ps2esdi_sizes,
 168        real_devices:   (void *)ps2esdi_info,
 169        fops:           &ps2esdi_fops,
 170};
 171
 172/* initialization routine called by ll_rw_blk.c   */
 173int __init ps2esdi_init(void)
 174{
 175
 176        /* register the device - pass the name, major number and operations
 177           vector .                                                 */
 178        if (devfs_register_blkdev(MAJOR_NR, "ed", &ps2esdi_fops)) {
 179                printk("%s: Unable to get major number %d\n", DEVICE_NAME, MAJOR_NR);
 180                return -1;
 181        }
 182        /* set up some global information - indicating device specific info */
 183        blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 184        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
 185
 186        /* some minor housekeeping - setup the global gendisk structure */
 187        add_gendisk(&ps2esdi_gendisk);
 188        ps2esdi_geninit();
 189        return 0;
 190}                               /* ps2esdi_init */
 191
 192#ifdef MODULE
 193
 194static int cyl[MAX_HD] = {-1,-1};
 195static int head[MAX_HD] = {-1, -1};
 196static int sect[MAX_HD] = {-1, -1};
 197
 198MODULE_PARM(tp720esdi, "i");
 199MODULE_PARM(cyl, "i");
 200MODULE_PARM(head, "i");
 201MODULE_PARM(track, "i");
 202MODULE_LICENSE("GPL");
 203
 204int init_module(void) {
 205        int drive;
 206
 207        for(drive = 0; drive < MAX_HD; drive++) {
 208                struct ps2_esdi_i_struct *info = &ps2esdi_info[drive];
 209
 210                if (cyl[drive] != -1) {
 211                        info->cyl = info->lzone = cyl[drive];
 212                        info->wpcom = 0;
 213                }
 214                if (head[drive] != -1) {
 215                        info->head = head[drive];
 216                        info->ctl = (head[drive] > 8 ? 8 : 0);
 217                }
 218                if (sect[drive] != -1) info->sect = sect[drive];
 219        }
 220        return ps2esdi_init();
 221}
 222
 223void
 224cleanup_module(void)
 225{
 226        if(ps2esdi_slot) {
 227                mca_mark_as_unused(ps2esdi_slot);
 228                mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);
 229        }
 230        release_region(io_base, 4);
 231        free_dma(dma_arb_level);
 232        free_irq(PS2ESDI_IRQ, NULL);
 233        devfs_unregister_blkdev(MAJOR_NR, "ed");
 234        del_gendisk(&ps2esdi_gendisk);
 235        blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 236}
 237#endif /* MODULE */
 238
 239/* handles boot time command line parameters */
 240void __init tp720_setup(char *str, int *ints)
 241{
 242        /* no params, just sets the tp720esdi flag if it exists */
 243
 244        printk("%s: TP 720 ESDI flag set\n", DEVICE_NAME);
 245        tp720esdi = 1;
 246}
 247
 248void __init ed_setup(char *str, int *ints)
 249{
 250        int hdind = 0;
 251
 252        /* handles 3 parameters only - corresponding to
 253           1. Number of cylinders
 254           2. Number of heads
 255           3. Sectors/track
 256         */
 257
 258        if (ints[0] != 3)
 259                return;
 260
 261        /* print out the information - seen at boot time */
 262        printk("%s: ints[0]=%d ints[1]=%d ints[2]=%d ints[3]=%d\n",
 263               DEVICE_NAME, ints[0], ints[1], ints[2], ints[3]);
 264
 265        /* set the index into device specific information table */
 266        if (ps2esdi_info[0].head != 0)
 267                hdind = 1;
 268
 269        /* set up all the device information */
 270        ps2esdi_info[hdind].head = ints[2];
 271        ps2esdi_info[hdind].sect = ints[3];
 272        ps2esdi_info[hdind].cyl = ints[1];
 273        ps2esdi_info[hdind].wpcom = 0;
 274        ps2esdi_info[hdind].lzone = ints[1];
 275        ps2esdi_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
 276#if 0                           /* this may be needed for PS2/Mod.80, but it hurts ThinkPad! */
 277        ps2esdi_drives = hdind + 1;     /* increment index for the next time */
 278#endif
 279}                               /* ed_setup */
 280
 281static int ps2esdi_getinfo(char *buf, int slot, void *d)
 282{
 283        int len = 0;
 284
 285        len += sprintf(buf + len, "DMA Arbitration Level: %d\n",
 286                       dma_arb_level);
 287        len += sprintf(buf + len, "IO Port: %x\n", io_base);
 288        len += sprintf(buf + len, "IRQ: 14\n");
 289        len += sprintf(buf + len, "Drives: %d\n", ps2esdi_drives);
 290
 291        return len;
 292}
 293
 294/* ps2 esdi specific initialization - called thru the gendisk chain */
 295static void __init ps2esdi_geninit(void)
 296{
 297        /*
 298           The first part contains the initialization code
 299           for the ESDI disk subsystem.  All we really do
 300           is search for the POS registers of the controller
 301           to do some simple setup operations.  First, we
 302           must ensure that the controller is installed,
 303           enabled, and configured as PRIMARY.  Then we must
 304           determine the DMA arbitration level being used by
 305           the controller so we can handle data transfer
 306           operations properly.  If all of this works, then
 307           we will set the INIT_FLAG to a non-zero value.
 308         */
 309
 310        int slot = 0, i, reset_start, reset_end;
 311        u_char status;
 312        unsigned short adapterID;
 313
 314        if ((slot = mca_find_adapter(INTG_ESDI_ID, 0)) != MCA_NOTFOUND) {
 315                adapterID = INTG_ESDI_ID;
 316                printk("%s: integrated ESDI adapter found in slot %d\n",
 317                       DEVICE_NAME, slot+1);
 318#ifndef MODULE
 319                mca_set_adapter_name(slot, "PS/2 Integrated ESDI");
 320#endif
 321        } else if ((slot = mca_find_adapter(NRML_ESDI_ID, 0)) != -1) {
 322                adapterID = NRML_ESDI_ID;
 323                printk("%s: normal ESDI adapter found in slot %d\n",
 324                       DEVICE_NAME, slot+1);
 325                mca_set_adapter_name(slot, "PS/2 ESDI");
 326        } else {
 327                return;
 328        }
 329
 330        ps2esdi_slot = slot;
 331        mca_mark_as_used(slot);
 332        mca_set_adapter_procfn(slot, (MCA_ProcFn) ps2esdi_getinfo, NULL);
 333
 334        /* Found the slot - read the POS register 2 to get the necessary
 335           configuration and status information.  POS register 2 has the
 336           following information :
 337           Bit           Function
 338           7             reserved = 0
 339           6             arbitration method
 340           0 - fairness enabled
 341           1 - fairness disabled, linear priority assignment
 342           5-2           arbitration level
 343           1             alternate address
 344           1              alternate address
 345           0 - use addresses 0x3510 - 0x3517
 346           0             adapter enable
 347         */
 348
 349        status = mca_read_stored_pos(slot, 2);
 350        /* is it enabled ? */
 351        if (!(status & STATUS_ENABLED)) {
 352                printk("%s: ESDI adapter disabled\n", DEVICE_NAME);
 353                return;
 354        }
 355        /* try to grab IRQ, and try to grab a slow IRQ if it fails, so we can
 356           share with the SCSI driver */
 357        if (request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
 358                  SA_INTERRUPT | SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
 359            && request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
 360                           SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
 361            ) {
 362                printk("%s: Unable to get IRQ %d\n", DEVICE_NAME, PS2ESDI_IRQ);
 363                return;
 364        }
 365        if (status & STATUS_ALTERNATE)
 366                io_base = ALT_IO_BASE;
 367        else
 368                io_base = PRIMARY_IO_BASE;
 369
 370        /* get the dma arbitration level */
 371        dma_arb_level = (status >> 2) & 0xf;
 372
 373        /* BA */
 374        printk("%s: DMA arbitration level : %d\n",
 375               DEVICE_NAME, dma_arb_level);
 376
 377        LITE_ON;
 378        current_int_handler = ps2esdi_initial_reset_int_handler;
 379        reset_ctrl();
 380        reset_status = 0;
 381        reset_start = jiffies;
 382        while (!reset_status) {
 383                init_timer(&esdi_timer);
 384                esdi_timer.expires = jiffies + HZ;
 385                esdi_timer.data = 0;
 386                add_timer(&esdi_timer);
 387                sleep_on(&ps2esdi_int);
 388        }
 389        reset_end = jiffies;
 390        LITE_OFF;
 391        printk("%s: reset interrupt after %d jiffies,  %u.%02u secs\n",
 392               DEVICE_NAME, reset_end - reset_start, (reset_end - reset_start) / HZ,
 393               (reset_end - reset_start) % HZ);
 394
 395
 396        /* Integrated ESDI Disk and Controller has only one drive! */
 397        if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */
 398                ps2esdi_drives = 1;     /* then we have only one physical disk! */              intg_esdi = 1;
 399        }
 400
 401
 402
 403        /* finally this part sets up some global data structures etc. */
 404
 405        ps2esdi_get_device_cfg();
 406
 407        /* some annoyance in the above routine returns TWO drives?
 408         Is something else happining in the background?
 409         Regaurdless we fix the # of drives again. AJK */
 410        /* Integrated ESDI Disk and Controller has only one drive! */
 411        if (adapterID == INTG_ESDI_ID)  /* if not "normal" PS2 ESDI adapter */
 412                ps2esdi_drives = 1;     /* Not three or two, ONE DAMNIT! */
 413
 414        current_int_handler = ps2esdi_normal_interrupt_handler;
 415
 416        ps2esdi_gendisk.nr_real = ps2esdi_drives;
 417
 418        /* 128 was old default, maybe maxsect=255 is ok too? - Paul G. */
 419        for (i = 0; i < (MAX_HD << 6); i++) {
 420                ps2esdi_maxsect[i] = 128;
 421                ps2esdi_blocksizes[i] = 1024;
 422        }
 423
 424        request_dma(dma_arb_level, "ed");
 425        request_region(io_base, 4, "ed");
 426        blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
 427        max_sectors[MAJOR_NR] = ps2esdi_maxsect;
 428
 429        for (i = 0; i < ps2esdi_drives; i++) {
 430                register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
 431                                &ps2esdi_fops,
 432                                ps2esdi_info[i].head * ps2esdi_info[i].sect *
 433                                ps2esdi_info[i].cyl);
 434                ps2esdi_valid[i] = 1;
 435        }
 436}
 437
 438static void __init ps2esdi_get_device_cfg(void)
 439{
 440        u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
 441
 442        /*BA */ printk("%s: Drive 0\n", DEVICE_NAME);
 443        current_int_handler = ps2esdi_geometry_int_handler;
 444        cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600;
 445        cmd_blk[1] = 0;
 446        no_int_yet = TRUE;
 447        ps2esdi_out_cmd_blk(cmd_blk);
 448        if (no_int_yet)
 449                sleep_on(&ps2esdi_int);
 450
 451        if (ps2esdi_drives > 1) {
 452                printk("%s: Drive 1\n", DEVICE_NAME);   /*BA */
 453                cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600;
 454                cmd_blk[1] = 0;
 455                no_int_yet = TRUE;
 456                ps2esdi_out_cmd_blk(cmd_blk);
 457                if (no_int_yet)
 458                        sleep_on(&ps2esdi_int);
 459        }                       /* if second physical drive is present */
 460        return;
 461}
 462
 463/* strategy routine that handles most of the IO requests */
 464static void do_ps2esdi_request(request_queue_t * q)
 465{
 466        u_int block, count;
 467        /* since, this routine is called with interrupts cleared - they 
 468           must be before it finishes  */
 469
 470#if 0
 471        printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
 472               DEVICE_NAME,
 473               CURRENT_DEV, MINOR(CURRENT->rq_dev),
 474               CURRENT->cmd, CURRENT->sector,
 475               CURRENT->current_nr_sectors, CURRENT->buffer);
 476#endif
 477
 478        /* standard macro that ensures that requests are really on the
 479           list + sanity checks.                     */
 480        INIT_REQUEST;
 481
 482        if (virt_to_bus(CURRENT->buffer + CURRENT->current_nr_sectors * 512) > 16 * MB) {
 483                printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
 484                end_request(FAIL);
 485        }                       /* check for above 16Mb dmas */
 486        else if ((CURRENT_DEV < ps2esdi_drives) &&
 487            (CURRENT->sector + CURRENT->current_nr_sectors <=
 488             ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects)) {
 489#if 0
 490                printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld\n",
 491                       DEVICE_NAME,
 492                       CURRENT_DEV, MINOR(CURRENT->rq_dev),
 493                       CURRENT->cmd, CURRENT->sector,
 494                       CURRENT->current_nr_sectors);
 495#endif
 496
 497
 498                block = CURRENT->sector + ps2esdi[MINOR(CURRENT->rq_dev)].start_sect;
 499
 500#if 0
 501                printk("%s: blocknumber : %d\n", DEVICE_NAME, block);
 502#endif
 503                count = CURRENT->current_nr_sectors;
 504                switch (CURRENT->cmd) {
 505                case READ:
 506                        ps2esdi_readwrite(READ, CURRENT_DEV, block, count);
 507                        break;
 508                case WRITE:
 509                        ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count);
 510                        break;
 511                default:
 512                        printk("%s: Unknown command\n", DEVICE_NAME);
 513                        end_request(FAIL);
 514                        break;
 515                }               /* handle different commands */
 516        }
 517        /* is request is valid */ 
 518        else {
 519                printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
 520                       CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
 521                end_request(FAIL);
 522        }
 523
 524}                               /* main strategy routine */
 525
 526/* resets the ESDI adapter */
 527static void reset_ctrl(void)
 528{
 529
 530        u_long expire;
 531        u_short status;
 532
 533        /* enable interrupts on the controller */
 534        status = inb(ESDI_INTRPT);
 535        outb((status & 0xe0) | ATT_EOI, ESDI_ATTN);     /* to be sure we don't have
 536                                                           any interrupt pending... */
 537        outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL);
 538
 539        /* read the ESDI status port - if the controller is not busy,
 540           simply do a soft reset (fast) - otherwise we'll have to do a
 541           hard (slow) reset.  */
 542        if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) {
 543                /*BA */ printk("%s: soft reset...\n", DEVICE_NAME);
 544                outb_p(CTRL_SOFT_RESET, ESDI_ATTN);
 545        }
 546        /* soft reset */ 
 547        else {
 548                /*BA */
 549                printk("%s: hard reset...\n", DEVICE_NAME);
 550                outb_p(CTRL_HARD_RESET, ESDI_CONTROL);
 551                expire = jiffies + 2*HZ;
 552                while (time_before(jiffies, expire));
 553                outb_p(1, ESDI_CONTROL);
 554        }                       /* hard reset */
 555
 556
 557}                               /* reset the controller */
 558
 559/* called by the strategy routine to handle read and write requests */
 560static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count)
 561{
 562
 563        u_short track, head, cylinder, sector;
 564        u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
 565        int err;
 566
 567        /* do some relevant arithmatic */
 568        track = block / ps2esdi_info[drive].sect;
 569        head = track % ps2esdi_info[drive].head;
 570        cylinder = track / ps2esdi_info[drive].head;
 571        sector = block % ps2esdi_info[drive].sect;
 572
 573#if 0
 574        printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);
 575#endif
 576        /* call the routine that actually fills out a command block */
 577        ps2esdi_fill_cmd_block
 578            (cmd_blk,
 579             (cmd == READ) ? CMD_READ : CMD_WRITE,
 580             cylinder, head, sector,
 581             CURRENT->current_nr_sectors, drive);
 582
 583        spin_unlock_irq(&io_request_lock);
 584        /* send the command block to the controller */
 585        err = ps2esdi_out_cmd_blk(cmd_blk);
 586        spin_lock_irq(&io_request_lock);
 587        
 588        if (err) {
 589                printk(KERN_ERR "%s: Controller failed\n", DEVICE_NAME);
 590                if ((++CURRENT->errors) >= MAX_RETRIES)
 591                        end_request(FAIL);
 592        }
 593        /* check for failure to put out the command block */ 
 594        else {
 595#if 0
 596                printk("%s: waiting for xfer\n", DEVICE_NAME);
 597#endif
 598                /* turn disk lights on */
 599                LITE_ON;
 600        }
 601
 602}                               /* ps2esdi_readwrite */
 603
 604/* fill out the command block */
 605static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
 606 u_short cyl, u_short head, u_short sector, u_short length, u_char drive)
 607{
 608
 609        cmd_blk[0] = (drive << 5) | cmd;
 610        cmd_blk[1] = length;
 611        cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
 612        cmd_blk[3] = (cyl & 0x3E0) >> 5;
 613
 614}                               /* fill out the command block */
 615
 616/* write a command block to the controller */
 617static int ps2esdi_out_cmd_blk(u_short * cmd_blk)
 618{
 619
 620        int i, j;
 621        u_char status;
 622
 623        /* enable interrupts */
 624        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 625
 626        /* do not write to the controller, if it is busy */
 627        for (i = jiffies + ESDI_STAT_TIMEOUT; time_after(i, jiffies) && (inb(ESDI_STATUS) &
 628                                                          STATUS_BUSY););
 629
 630#if 0
 631        printk("%s: i(1)=%d\n", DEVICE_NAME, i);
 632#endif
 633
 634        /* if device is still busy - then just time out */
 635        if (inb(ESDI_STATUS) & STATUS_BUSY) {
 636                printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME);
 637                return ERROR;
 638        }                       /* timeout ??? */
 639        /* Set up the attention register in the controller */
 640        outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);
 641
 642#if 0
 643        printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);
 644#endif
 645
 646        /* one by one send each word out */
 647        for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) {
 648                status = inb(ESDI_STATUS);
 649                for (j = jiffies + ESDI_STAT_TIMEOUT;
 650                     time_after(j, jiffies) && (status & STATUS_BUSY) &&
 651                   (status & STATUS_CMD_INF); status = inb(ESDI_STATUS));
 652                if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {
 653#if 0
 654                        printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);
 655#endif
 656                        outw(*cmd_blk++, ESDI_CMD_INT);
 657                } else {
 658                        printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n",
 659                               DEVICE_NAME, status);
 660                        return ERROR;
 661                }
 662        }                       /* send all words out */
 663        return OK;
 664}                               /* send out the commands */
 665
 666
 667/* prepare for dma - do all the necessary setup */
 668static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode)
 669{
 670        unsigned long flags;
 671#if 0
 672        printk("ps2esdi: b_wait: %p\n", &CURRENT->bh->b_wait);
 673#endif
 674        flags = claim_dma_lock();
 675
 676        mca_disable_dma(dma_arb_level);
 677
 678        mca_set_dma_addr(dma_arb_level, virt_to_bus(buffer));
 679
 680        mca_set_dma_count(dma_arb_level, length * 512 / 2);
 681
 682        mca_set_dma_mode(dma_arb_level, dma_xmode);
 683
 684        mca_enable_dma(dma_arb_level);
 685
 686        release_dma_lock(flags);
 687
 688}                               /* prepare for dma */
 689
 690
 691
 692static void ps2esdi_interrupt_handler(int irq, void *dev_id,
 693                                      struct pt_regs *regs)
 694{
 695        u_int int_ret_code;
 696
 697        if (inb(ESDI_STATUS) & STATUS_INTR) {
 698                int_ret_code = inb(ESDI_INTRPT);
 699                if (current_int_handler) {
 700                        /* Disable adapter interrupts till processing is finished */
 701                        outb(CTRL_DISABLE_INTR, ESDI_CONTROL);
 702                        current_int_handler(int_ret_code);
 703                } else
 704                        printk("%s: help ! No interrupt handler.\n", DEVICE_NAME);
 705        } else {
 706                return;
 707        }
 708}
 709
 710static void ps2esdi_initial_reset_int_handler(u_int int_ret_code)
 711{
 712
 713        switch (int_ret_code & 0xf) {
 714        case INT_RESET:
 715                /*BA */
 716                printk("%s: initial reset completed.\n", DEVICE_NAME);
 717                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 718                wake_up(&ps2esdi_int);
 719                break;
 720        case INT_ATTN_ERROR:
 721                printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
 722                       int_ret_code);
 723                printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS));
 724                break;
 725        default:
 726                printk("%s: initial reset handler received interrupt: %02X\n",
 727                       DEVICE_NAME, int_ret_code);
 728                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 729                break;
 730        }
 731        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 732}
 733
 734
 735static void ps2esdi_geometry_int_handler(u_int int_ret_code)
 736{
 737        u_int status, drive_num;
 738        unsigned long rba;
 739        int i;
 740
 741        drive_num = int_ret_code >> 5;
 742        switch (int_ret_code & 0xf) {
 743        case INT_CMD_COMPLETE:
 744                for (i = ESDI_TIMEOUT; i & !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
 745                if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
 746                        printk("%s: timeout reading status word\n", DEVICE_NAME);
 747                        outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 748                        break;
 749                }
 750                status = inw(ESDI_STT_INT);
 751                if ((status & 0x1F) == CMD_GET_DEV_CONFIG) {
 752#define REPLY_WORDS 5           /* we already read word 0 */
 753                        u_short reply[REPLY_WORDS];
 754
 755                        if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) {
 756                                /*BA */
 757                                printk("%s: Device Configuration Status for drive %u\n",
 758                                       DEVICE_NAME, drive_num);
 759
 760                                printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8);
 761
 762                                printk
 763                                    ("Config bits: %s%s%s%s%s\n",
 764                                     (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "",
 765                                     ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS))
 766                                 ? "Zero Defect, " : "Defects Present, ",
 767                                     (reply[0] & CONFIG_SF) ? "Skewed Format, " : "",
 768                                     (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ",
 769                                     (reply[0] & CONFIG_RT) ? "No Retries" : "Retries");
 770
 771                                rba = reply[1] | ((unsigned long) reply[2] << 16);
 772                                printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba);
 773
 774                                printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n",
 775                                       DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff);
 776
 777                                if (!ps2esdi_info[drive_num].head) {
 778                                        ps2esdi_info[drive_num].head = 64;
 779                                        ps2esdi_info[drive_num].sect = 32;
 780                                        ps2esdi_info[drive_num].cyl = rba / (64 * 32);
 781                                        ps2esdi_info[drive_num].wpcom = 0;
 782                                        ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl;
 783                                        ps2esdi_info[drive_num].ctl = 8;
 784                                        if (tp720esdi) {        /* store the retrieved parameters */
 785                                                ps2esdi_info[0].head = reply[4] & 0Xff;
 786                                                ps2esdi_info[0].sect = reply[4] >> 8;
 787                                                ps2esdi_info[0].cyl = reply[3];
 788                                                ps2esdi_info[0].wpcom = 0;
 789                                                ps2esdi_info[0].lzone = reply[3];
 790                                        } else {
 791                                                if (!intg_esdi)
 792                                                        ps2esdi_drives++;
 793                                        }
 794                                }
 795#ifdef OBSOLETE
 796                                if (!ps2esdi_info[drive_num].head) {
 797                                        ps2esdi_info[drive_num].head = reply[4] & 0Xff;
 798                                        ps2esdi_info[drive_num].sect = reply[4] >> 8;
 799                                        ps2esdi_info[drive_num].cyl = reply[3];
 800                                        ps2esdi_info[drive_num].wpcom = 0;
 801                                        ps2esdi_info[drive_num].lzone = reply[3];
 802                                        if (tp720esdi) {        /* store the retrieved parameters */
 803                                                ps2esdi_info[0].head = reply[4] & 0Xff;
 804                                                ps2esdi_info[0].sect = reply[4] >> 8;
 805                                                ps2esdi_info[0].cyl = reply[3];
 806                                                ps2esdi_info[0].wpcom = 0;
 807                                                ps2esdi_info[0].lzone = reply[3];
 808                                        } else {
 809                                                ps2esdi_drives++;
 810                                        }
 811                                }
 812#endif
 813
 814                        } else
 815                                printk("%s: failed while getting device config\n", DEVICE_NAME);
 816#undef REPLY_WORDS
 817                } else
 818                        printk("%s: command %02X unknown by geometry handler\n",
 819                               DEVICE_NAME, status & 0x1f);
 820
 821                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 822                break;
 823
 824        case INT_ATTN_ERROR:
 825                printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
 826                       int_ret_code);
 827                printk("%s: Device not available\n", DEVICE_NAME);
 828                break;
 829        case INT_CMD_ECC:
 830        case INT_CMD_RETRY:
 831        case INT_CMD_ECC_RETRY:
 832        case INT_CMD_WARNING:
 833        case INT_CMD_ABORT:
 834        case INT_CMD_FAILED:
 835        case INT_DMA_ERR:
 836        case INT_CMD_BLK_ERR:
 837                /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME);
 838                dump_cmd_complete_status(int_ret_code);
 839                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 840                break;
 841        default:
 842                printk("%s: Unknown interrupt reason: %02X\n",
 843                       DEVICE_NAME, int_ret_code & 0xf);
 844                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 845                break;
 846        }
 847
 848        wake_up(&ps2esdi_int);
 849        no_int_yet = FALSE;
 850        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 851
 852}
 853
 854static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
 855{
 856        unsigned long flags;
 857        u_int status;
 858        u_int ending;
 859        int i;
 860
 861        switch (int_ret_code & 0x0f) {
 862        case INT_TRANSFER_REQ:
 863                ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors,
 864                    (CURRENT->cmd == READ)
 865                    ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
 866                    : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
 867                outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
 868                ending = -1;
 869                break;
 870
 871        case INT_ATTN_ERROR:
 872                printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
 873                       int_ret_code);
 874                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 875                ending = FAIL;
 876                break;
 877
 878        case INT_CMD_COMPLETE:
 879                for (i = ESDI_TIMEOUT; i & !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
 880                if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
 881                        printk("%s: timeout reading status word\n", DEVICE_NAME);
 882                        outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 883                        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 884                        if ((++CURRENT->errors) >= MAX_RETRIES)
 885                                ending = FAIL;
 886                        else
 887                                ending = -1;
 888                        break;
 889                }
 890                status = inw(ESDI_STT_INT);
 891                switch (status & 0x1F) {
 892                case (CMD_READ & 0xff):
 893                case (CMD_WRITE & 0xff):
 894                        LITE_OFF;
 895                        outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 896                        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 897#if 0
 898                        printk("ps2esdi: cmd_complete b_wait: %p\n", &CURRENT->bh->b_wait);
 899#endif
 900                        ending = SUCCES;
 901                        break;
 902                default:
 903                        printk("%s: interrupt for unknown command %02X\n",
 904                               DEVICE_NAME, status & 0x1f);
 905                        outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 906                        outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 907                        ending = -1;
 908                        break;
 909                }
 910                break;
 911        case INT_CMD_ECC:
 912        case INT_CMD_RETRY:
 913        case INT_CMD_ECC_RETRY:
 914                LITE_OFF;
 915                dump_cmd_complete_status(int_ret_code);
 916                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 917                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 918                ending = SUCCES;
 919                break;
 920        case INT_CMD_WARNING:
 921        case INT_CMD_ABORT:
 922        case INT_CMD_FAILED:
 923        case INT_DMA_ERR:
 924                LITE_OFF;
 925                dump_cmd_complete_status(int_ret_code);
 926                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 927                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 928                if ((++CURRENT->errors) >= MAX_RETRIES)
 929                        ending = FAIL;
 930                else
 931                        ending = -1;
 932                break;
 933
 934        case INT_CMD_BLK_ERR:
 935                dump_cmd_complete_status(int_ret_code);
 936                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 937                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 938                ending = FAIL;
 939                break;
 940
 941        case INT_CMD_FORMAT:
 942                printk("%s: huh ? Who issued this format command ?\n"
 943                       ,DEVICE_NAME);
 944                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 945                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 946                ending = -1;
 947                break;
 948
 949        case INT_RESET:
 950                /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ;
 951                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 952                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 953                ending = -1;
 954                break;
 955
 956        default:
 957                printk("%s: Unknown interrupt reason: %02X\n",
 958                       DEVICE_NAME, int_ret_code & 0xf);
 959                outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
 960                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
 961                ending = -1;
 962                break;
 963        }
 964        if(ending != -1) {
 965                spin_lock_irqsave(&io_request_lock, flags);
 966                end_request(ending);
 967                do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
 968                spin_unlock_irqrestore(&io_request_lock, flags);
 969        }
 970}                               /* handle interrupts */
 971
 972
 973
 974static int ps2esdi_read_status_words(int num_words,
 975                                     int max_words,
 976                                     u_short * buffer)
 977{
 978        int i;
 979
 980        for (; max_words && num_words; max_words--, num_words--, buffer++) {
 981                for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
 982                if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
 983                        printk("%s: timeout reading status word\n", DEVICE_NAME);
 984                        return FAIL;
 985                }
 986                *buffer = inw(ESDI_STT_INT);
 987        }
 988        return SUCCES;
 989}
 990
 991
 992
 993
 994static void dump_cmd_complete_status(u_int int_ret_code)
 995{
 996#define WAIT_FOR_STATUS \
 997  for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \
 998    if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \
 999    printk("%s: timeout reading status word\n",DEVICE_NAME); \
1000    return; \
1001    }
1002
1003        int i, word_count;
1004        u_short stat_word;
1005        u_long rba;
1006
1007        printk("%s: Device: %u, interrupt ID: %02X\n",
1008               DEVICE_NAME, int_ret_code >> 5,
1009               int_ret_code & 0xf);
1010
1011        WAIT_FOR_STATUS;
1012        stat_word = inw(ESDI_STT_INT);
1013        word_count = (stat_word >> 8) - 1;
1014        printk("%s: %u status words, command: %02X\n", DEVICE_NAME, word_count,
1015               stat_word & 0xff);
1016
1017        if (word_count--) {
1018                WAIT_FOR_STATUS;
1019                stat_word = inw(ESDI_STT_INT);
1020                printk("%s: command status code: %02X, command error code: %02X\n",
1021                       DEVICE_NAME, stat_word >> 8, stat_word & 0xff);
1022        }
1023        if (word_count--) {
1024                WAIT_FOR_STATUS;
1025                stat_word = inw(ESDI_STT_INT);
1026                printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME,
1027                       (stat_word & 0x1000) ? "Ready, " : "Not Ready, ",
1028                  (stat_word & 0x0800) ? "Selected, " : "Not Selected, ",
1029                       (stat_word & 0x0400) ? "Write Fault, " : "",
1030                       (stat_word & 0x0200) ? "Track 0, " : "",
1031                (stat_word & 0x0100) ? "Seek or command complete, " : "",
1032                       stat_word >> 8);
1033        }
1034        if (word_count--) {
1035                WAIT_FOR_STATUS;
1036                stat_word = inw(ESDI_STT_INT);
1037                printk("%s: Blocks to do: %u", DEVICE_NAME, stat_word);
1038        }
1039        if (word_count -= 2) {
1040                WAIT_FOR_STATUS;
1041                rba = inw(ESDI_STT_INT);
1042                WAIT_FOR_STATUS;
1043                rba |= inw(ESDI_STT_INT) << 16;
1044                printk(", Last Cyl: %u Head: %u Sector: %u\n",
1045                       (u_short) ((rba & 0x1ff80000) >> 11),
1046                 (u_short) ((rba & 0x7E0) >> 5), (u_short) (rba & 0x1f));
1047        } else
1048                printk("\n");
1049
1050        if (word_count--) {
1051                WAIT_FOR_STATUS;
1052                stat_word = inw(ESDI_STT_INT);
1053                printk("%s: Blocks required ECC: %u", DEVICE_NAME, stat_word);
1054        }
1055        printk("\n");
1056
1057#undef WAIT_FOR_STATUS
1058
1059}
1060
1061
1062static int ps2esdi_open(struct inode *inode, struct file *file)
1063{
1064        int dev = DEVICE_NR(inode->i_rdev);
1065
1066        if (dev < ps2esdi_drives) {
1067                while (!ps2esdi_valid[dev])
1068                        sleep_on(&ps2esdi_wait_open);
1069
1070                access_count[dev]++;
1071
1072                return (0);
1073        } else
1074                return (-ENODEV);
1075}
1076
1077
1078
1079static int ps2esdi_release(struct inode *inode, struct file *file)
1080{
1081        int dev = DEVICE_NR(inode->i_rdev);
1082
1083        if (dev < ps2esdi_drives) {
1084                access_count[dev]--;
1085        }
1086        return 0;
1087}
1088
1089
1090
1091static int ps2esdi_ioctl(struct inode *inode,
1092                         struct file *file, u_int cmd, u_long arg)
1093{
1094
1095        struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg;
1096        int dev = DEVICE_NR(inode->i_rdev), err;
1097
1098        if (inode && (dev < ps2esdi_drives))
1099                switch (cmd) {
1100                case HDIO_GETGEO:
1101                        if (arg) {
1102                                if ((err = verify_area(VERIFY_WRITE, geometry, sizeof(*geometry))))
1103                                        return (err);
1104                                put_user(ps2esdi_info[dev].head, (char *) &geometry->heads);
1105                                put_user(ps2esdi_info[dev].sect, (char *) &geometry->sectors);
1106                                put_user(ps2esdi_info[dev].cyl, (short *) &geometry->cylinders);
1107                                put_user(ps2esdi[MINOR(inode->i_rdev)].start_sect,
1108                                            (long *) &geometry->start);
1109
1110                                return (0);
1111                        }
1112                        break;
1113
1114                case BLKRRPART:
1115                        if (!capable(CAP_SYS_ADMIN)) 
1116                                return -EACCES;
1117                        return (ps2esdi_reread_partitions(inode->i_rdev));
1118
1119                case BLKGETSIZE:
1120                case BLKGETSIZE64:
1121                case BLKROSET:
1122                case BLKROGET:
1123                case BLKRASET:
1124                case BLKRAGET:
1125                case BLKFLSBUF:
1126                case BLKBSZGET:
1127                case BLKBSZSET:
1128                case BLKPG:
1129                        return blk_ioctl(inode->i_rdev, cmd, arg);
1130                }
1131        return (-EINVAL);
1132}
1133
1134
1135
1136static int ps2esdi_reread_partitions(kdev_t dev)
1137{
1138        int target = DEVICE_NR(dev);
1139        int start = target << ps2esdi_gendisk.minor_shift;
1140        int partition;
1141
1142        ps2esdi_valid[target] = (access_count[target] != 1);
1143        if (ps2esdi_valid[target])
1144                return (-EBUSY);
1145
1146        for (partition = ps2esdi_gendisk.max_p - 1;
1147             partition >= 0; partition--) {
1148                int minor = (start | partition);
1149                invalidate_device(MKDEV(MAJOR_NR, minor), 1);
1150                ps2esdi_gendisk.part[minor].start_sect = 0;
1151                ps2esdi_gendisk.part[minor].nr_sects = 0;
1152        }
1153
1154        grok_partitions(&ps2esdi_gendisk, target, 1<<6, 
1155                ps2esdi_info[target].head * ps2esdi_info[target].cyl * ps2esdi_info[target].sect);
1156
1157        ps2esdi_valid[target] = 1;
1158        wake_up(&ps2esdi_wait_open);
1159
1160        return (0);
1161}
1162
1163static void ps2esdi_reset_timer(unsigned long unused)
1164{
1165
1166        int status;
1167
1168        status = inb(ESDI_INTRPT);
1169        if ((status & 0xf) == INT_RESET) {
1170                outb((status & 0xe0) | ATT_EOI, ESDI_ATTN);
1171                outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
1172                reset_status = 1;
1173        }
1174        wake_up(&ps2esdi_int);
1175}
1176
1177#endif
1178
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.