📄 ps2esdi.c
字号:
/* BA */ printk("%s: DMA arbitration level : %d\n", DEVICE_NAME, dma_arb_level); LITE_ON; current_int_handler = ps2esdi_initial_reset_int_handler; reset_ctrl(); reset_status = 0; reset_start = jiffies; while (!reset_status) { init_timer(&esdi_timer); esdi_timer.expires = jiffies + HZ; esdi_timer.data = 0; add_timer(&esdi_timer); sleep_on(&ps2esdi_int); } reset_end = jiffies; LITE_OFF; printk("%s: reset interrupt after %d jiffies, %u.%02u secs\n", DEVICE_NAME, reset_end - reset_start, (reset_end - reset_start) / HZ, (reset_end - reset_start) % HZ); /* Integrated ESDI Disk and Controller has only one drive! */ if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */ ps2esdi_drives = 1; /* then we have only one physical disk! */ intg_esdi = 1; } /* finally this part sets up some global data structures etc. */ ps2esdi_get_device_cfg(); /* some annoyance in the above routine returns TWO drives? Is something else happining in the background? Regaurdless we fix the # of drives again. AJK */ /* Integrated ESDI Disk and Controller has only one drive! */ if (adapterID == INTG_ESDI_ID) /* if not "normal" PS2 ESDI adapter */ ps2esdi_drives = 1; /* Not three or two, ONE DAMNIT! */ current_int_handler = ps2esdi_normal_interrupt_handler; if (request_dma(dma_arb_level, "ed") !=0) { printk(KERN_WARNING "PS2ESDI: Can't request dma-channel %d\n" ,(int) dma_arb_level); error = -EBUSY; goto err_out3; } blk_queue_max_sectors(ps2esdi_queue, 128); error = -ENOMEM; for (i = 0; i < ps2esdi_drives; i++) { struct gendisk *disk = alloc_disk(64); if (!disk) goto err_out4; disk->major = PS2ESDI_MAJOR; disk->first_minor = i<<6; sprintf(disk->disk_name, "ed%c", 'a'+i); sprintf(disk->devfs_name, "ed/target%d", i); disk->fops = &ps2esdi_fops; ps2esdi_gendisk[i] = disk; } for (i = 0; i < ps2esdi_drives; i++) { struct gendisk *disk = ps2esdi_gendisk[i]; set_capacity(disk, ps2esdi_info[i].head * ps2esdi_info[i].sect * ps2esdi_info[i].cyl); disk->queue = ps2esdi_queue; disk->private_data = &ps2esdi_info[i]; add_disk(disk); } return 0;err_out4: while (i--) put_disk(ps2esdi_gendisk[i]);err_out3: release_region(io_base, 4);err_out2: free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);err_out1: if(ps2esdi_slot) { mca_mark_as_unused(ps2esdi_slot); mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL); } return error;}static void __init ps2esdi_get_device_cfg(void){ u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH]; /*BA */ printk("%s: Drive 0\n", DEVICE_NAME); current_int_handler = ps2esdi_geometry_int_handler; cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600; cmd_blk[1] = 0; no_int_yet = TRUE; ps2esdi_out_cmd_blk(cmd_blk); if (no_int_yet) sleep_on(&ps2esdi_int); if (ps2esdi_drives > 1) { printk("%s: Drive 1\n", DEVICE_NAME); /*BA */ cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600; cmd_blk[1] = 0; no_int_yet = TRUE; ps2esdi_out_cmd_blk(cmd_blk); if (no_int_yet) sleep_on(&ps2esdi_int); } /* if second physical drive is present */ return;}/* strategy routine that handles most of the IO requests */static void do_ps2esdi_request(request_queue_t * q){ struct request *req; /* since, this routine is called with interrupts cleared - they must be before it finishes */ req = elv_next_request(q); if (!req) return;#if 0 printk("%s:got request. device : %s command : %d sector : %ld count : %ld, buffer: %p\n", DEVICE_NAME, req->rq_disk->disk_name, req->cmd, req->sector, req->current_nr_sectors, req->buffer);#endif /* check for above 16Mb dmas */ if (isa_virt_to_bus(req->buffer + req->current_nr_sectors * 512) > 16 * MB) { printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); end_request(req, FAIL); return; } if (req->sector+req->current_nr_sectors > get_capacity(req->rq_disk)) { printk("Grrr. error. ps2esdi_drives: %d, %llu %llu\n", ps2esdi_drives, req->sector, (unsigned long long)get_capacity(req->rq_disk)); end_request(req, FAIL); return; } switch (rq_data_dir(req)) { case READ: ps2esdi_readwrite(READ, req); break; case WRITE: ps2esdi_readwrite(WRITE, req); break; default: printk("%s: Unknown command\n", req->rq_disk->disk_name); end_request(req, FAIL); break; } /* handle different commands */} /* main strategy routine *//* resets the ESDI adapter */static void reset_ctrl(void){ u_long expire; u_short status; /* enable interrupts on the controller */ status = inb(ESDI_INTRPT); outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); /* to be sure we don't have any interrupt pending... */ outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL); /* read the ESDI status port - if the controller is not busy, simply do a soft reset (fast) - otherwise we'll have to do a hard (slow) reset. */ if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) { /*BA */ printk("%s: soft reset...\n", DEVICE_NAME); outb_p(CTRL_SOFT_RESET, ESDI_ATTN); } /* soft reset */ else { /*BA */ printk("%s: hard reset...\n", DEVICE_NAME); outb_p(CTRL_HARD_RESET, ESDI_CONTROL); expire = jiffies + 2*HZ; while (time_before(jiffies, expire)); outb_p(1, ESDI_CONTROL); } /* hard reset */} /* reset the controller *//* called by the strategy routine to handle read and write requests */static void ps2esdi_readwrite(int cmd, struct request *req){ struct ps2esdi_i_struct *p = req->rq_disk->private_data; unsigned block = req->sector; unsigned count = req->current_nr_sectors; int drive = p - ps2esdi_info; u_short track, head, cylinder, sector; u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; /* do some relevant arithmatic */ track = block / p->sect; head = track % p->head; cylinder = track / p->head; sector = block % p->sect;#if 0 printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);#endif /* call the routine that actually fills out a command block */ ps2esdi_fill_cmd_block (cmd_blk, (cmd == READ) ? CMD_READ : CMD_WRITE, cylinder, head, sector, count, drive); /* send the command block to the controller */ current_req = req; spin_unlock_irq(&ps2esdi_lock); if (ps2esdi_out_cmd_blk(cmd_blk)) { spin_lock_irq(&ps2esdi_lock); printk("%s: Controller failed\n", DEVICE_NAME); if ((++req->errors) >= MAX_RETRIES) end_request(req, FAIL); } /* check for failure to put out the command block */ else { spin_lock_irq(&ps2esdi_lock);#if 0 printk("%s: waiting for xfer\n", DEVICE_NAME);#endif /* turn disk lights on */ LITE_ON; }} /* ps2esdi_readwrite *//* fill out the command block */static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, u_short cyl, u_short head, u_short sector, u_short length, u_char drive){ cmd_blk[0] = (drive << 5) | cmd; cmd_blk[1] = length; cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector; cmd_blk[3] = (cyl & 0x3E0) >> 5;} /* fill out the command block *//* write a command block to the controller */static int ps2esdi_out_cmd_blk(u_short * cmd_blk){ int i; unsigned long jif; u_char status; /* enable interrupts */ outb(CTRL_ENABLE_INTR, ESDI_CONTROL); /* do not write to the controller, if it is busy */ for (jif = jiffies + ESDI_STAT_TIMEOUT; time_after(jif, jiffies) && (inb(ESDI_STATUS) & STATUS_BUSY); ) ;#if 0 printk("%s: i(1)=%ld\n", DEVICE_NAME, jif);#endif /* if device is still busy - then just time out */ if (inb(ESDI_STATUS) & STATUS_BUSY) { printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME); return ERROR; } /* timeout ??? */ /* Set up the attention register in the controller */ outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);#if 0 printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);#endif /* one by one send each word out */ for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) { status = inb(ESDI_STATUS); for (jif = jiffies + ESDI_STAT_TIMEOUT; time_after(jif, jiffies) && (status & STATUS_BUSY) && (status & STATUS_CMD_INF); status = inb(ESDI_STATUS)); if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {#if 0 printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);#endif outw(*cmd_blk++, ESDI_CMD_INT); } else { printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n", DEVICE_NAME, status); return ERROR; } } /* send all words out */ return OK;} /* send out the commands *//* prepare for dma - do all the necessary setup */static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode){ unsigned long flags = claim_dma_lock(); mca_disable_dma(dma_arb_level); mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer)); mca_set_dma_count(dma_arb_level, length * 512 / 2); mca_set_dma_mode(dma_arb_level, dma_xmode); mca_enable_dma(dma_arb_level); release_dma_lock(flags);} /* prepare for dma */static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs){ u_int int_ret_code; if (inb(ESDI_STATUS) & STATUS_INTR) { int_ret_code = inb(ESDI_INTRPT); if (current_int_handler) { /* Disable adapter interrupts till processing is finished */ outb(CTRL_DISABLE_INTR, ESDI_CONTROL); current_int_handler(int_ret_code); } else printk("%s: help ! No interrupt handler.\n", DEVICE_NAME); } else { return IRQ_NONE; } return IRQ_HANDLED;}static void ps2esdi_initial_reset_int_handler(u_int int_ret_code){ switch (int_ret_code & 0xf) { case INT_RESET: /*BA */ printk("%s: initial reset completed.\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); wake_up(&ps2esdi_int); break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS)); break; default: printk("%s: initial reset handler received interrupt: %02X\n", DEVICE_NAME, int_ret_code);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -