📄 ppa.c
字号:
unsigned char l = 0, h = 0; int retv; /* First check for any errors that may have occurred * Here we check for internal errors */ if (tmp->failed) return 0; switch (cmd->SCp.phase) { case 0: /* Phase 0 - Waiting for parport */ if ((jiffies - tmp->jstart) > HZ) { /* * We waited more than a second * for parport to call us */ ppa_fail(host_no, DID_BUS_BUSY); return 0; } return 1; /* wait until ppa_wakeup claims parport */ case 1: /* Phase 1 - Connected */ { /* Perform a sanity check for cable unplugged */ int retv = 2; /* Failed */ ppa_connect(host_no, CONNECT_EPP_MAYBE); w_ctr(ppb, 0xe); if ((r_str(ppb) & 0x08) == 0x08) retv--; w_ctr(ppb, 0xc); if ((r_str(ppb) & 0x08) == 0x00) retv--; if (retv) if ((jiffies - tmp->jstart) > (1 * HZ)) { printk("ppa: Parallel port cable is unplugged!!\n"); ppa_fail(host_no, DID_BUS_BUSY); return 0; } else { ppa_disconnect(host_no); return 1; /* Try again in a jiffy */ } cmd->SCp.phase++; } case 2: /* Phase 2 - We are now talking to the scsi bus */ if (!ppa_select(host_no, cmd->target)) { ppa_fail(host_no, DID_NO_CONNECT); return 0; } cmd->SCp.phase++; case 3: /* Phase 3 - Ready to accept a command */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; if (!ppa_send_command(cmd)) return 0; cmd->SCp.phase++; case 4: /* Phase 4 - Setup scatter/gather buffers */ if (cmd->use_sg) { /* if many buffers are available, start filling the first */ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; } else { /* else fill the only available buffer */ cmd->SCp.buffer = NULL; cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } cmd->SCp.buffers_residual = cmd->use_sg; cmd->SCp.phase++; case 5: /* Phase 5 - Data transfer stage */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; retv = ppa_completion(cmd); if (retv == -1) return 0; if (retv == 0) return 1; cmd->SCp.phase++; case 6: /* Phase 6 - Read status/message */ cmd->result = DID_OK << 16; /* Check for data overrun */ if (ppa_wait(host_no) != (unsigned char) 0xf0) { ppa_fail(host_no, DID_ERROR); return 0; } if (ppa_in(host_no, &l, 1)) { /* read status byte */ /* Check for optional message byte */ if (ppa_wait(host_no) == (unsigned char) 0xf0) ppa_in(host_no, &h, 1); cmd->result = (DID_OK << 16) + (h << 8) + (l & STATUS_MASK); } return 0; /* Finished */ break; default: printk("ppa: Invalid scsi phase\n"); } return 0;}int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){ int host_no = cmd->host->unique_id; if (ppa_hosts[host_no].cur_cmd) { printk("PPA: bug in ppa_queuecommand\n"); return 0; } ppa_hosts[host_no].failed = 0; ppa_hosts[host_no].jstart = jiffies; ppa_hosts[host_no].cur_cmd = cmd; cmd->scsi_done = done; cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ ppa_pb_claim(host_no); ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no; ppa_hosts[host_no].ppa_tq.sync = 0; queue_task(&ppa_hosts[host_no].ppa_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); return 0;}/* * Apparently the disk->capacity attribute is off by 1 sector * for all disk drives. We add the one here, but it should really * be done in sd.c. Even if it gets fixed there, this will still * work. */int ppa_biosparam(Disk * disk, kdev_t dev, int ip[]){ ip[0] = 0x40; ip[1] = 0x20; ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); if (ip[2] > 1024) { ip[0] = 0xff; ip[1] = 0x3f; ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); if (ip[2] > 1023) ip[2] = 1023; } return 0;}int ppa_abort(Scsi_Cmnd * cmd){ /* * There is no method for aborting commands since Iomega * have tied the SCSI_MESSAGE line high in the interface */ switch (cmd->SCp.phase) { case 0: /* Do not have access to parport */ case 1: /* Have not connected to interface */ cmd->result = DID_ABORT; cmd->done(cmd); return SCSI_ABORT_SUCCESS; break; default: /* SCSI command sent, can not abort */ return SCSI_ABORT_BUSY; break; }}int ppa_reset(Scsi_Cmnd * cmd, unsigned int x){ int host_no = cmd->host->unique_id; int ppb = PPA_BASE(host_no); /* * PHASE1: * Bring the interface crashing down on whatever is running * hopefully this will kill the request. * Bring back up the interface, reset the drive (and anything * attached for that manner) */ if (cmd) if (cmd->SCp.phase) ppa_disconnect(cmd->host->unique_id); ppa_connect(host_no, CONNECT_NORMAL); w_dtr(ppb, 0x40); w_ctr(ppb, 0x8); udelay(30); w_ctr(ppb, 0xc); udelay(1000); /* delay for devices to settle down */ ppa_disconnect(host_no); udelay(1000); /* Additional delay to allow devices to settle down */ /* * PHASE2: * Sanity check for the sake of mid-level driver */ if (!cmd) { printk("ppa bus reset called for invalid command.\n"); return SCSI_RESET_NOT_RUNNING; } /* * PHASE3: * Flag the current command as having died due to reset */ ppa_connect(host_no, CONNECT_NORMAL); ppa_fail(host_no, DID_RESET); /* Since the command was already on the timer queue ppa_interrupt * will be called shortly. */ return SCSI_RESET_PENDING;}static int device_check(int host_no){ /* This routine looks for a device and then attempts to use EPP to send a command. If all goes as planned then EPP is available. */ static char cmd[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int loop, old_mode, status, k, ppb = PPA_BASE(host_no); unsigned char l; old_mode = ppa_hosts[host_no].mode; for (loop = 0; loop < 8; loop++) { /* Attempt to use EPP for Test Unit Ready */ if ((ppb & 0x0007) == 0x0000) ppa_hosts[host_no].mode = PPA_EPP_32; second_pass: ppa_connect(host_no, CONNECT_EPP_MAYBE); /* Select SCSI device */ if (!ppa_select(host_no, loop)) { ppa_disconnect(host_no); continue; } printk("ppa: Found device at ID %i, Attempting to use %s\n", loop, PPA_MODE_STRING[ppa_hosts[host_no].mode]); /* Send SCSI command */ status = 1; w_ctr(ppb, 0x0c); for (l = 0; (l < 6) && (status); l++) status = ppa_out(host_no, cmd, 1); if (!status) { ppa_disconnect(host_no); ppa_connect(host_no, CONNECT_EPP_MAYBE); w_dtr(ppb, 0x40); w_ctr(ppb, 0x08); udelay(30); w_ctr(ppb, 0x0c); udelay(1000); ppa_disconnect(host_no); udelay(1000); if (ppa_hosts[host_no].mode == PPA_EPP_32) { ppa_hosts[host_no].mode = old_mode; goto second_pass; } printk("ppa: Unable to establish communication, aborting driver load.\n"); return 1; } w_ctr(ppb, 0x0c); k = 1000000; /* 1 Second */ do { l = r_str(ppb); k--; udelay(1); } while (!(l & 0x80) && (k)); l &= 0xf0; if (l != 0xf0) { ppa_disconnect(host_no); ppa_connect(host_no, CONNECT_EPP_MAYBE); w_dtr(ppb, 0x40); w_ctr(ppb, 0x08); udelay(30); w_ctr(ppb, 0x0c); udelay(1000); ppa_disconnect(host_no); udelay(1000); if (ppa_hosts[host_no].mode == PPA_EPP_32) { ppa_hosts[host_no].mode = old_mode; goto second_pass; } printk("ppa: Unable to establish communication, aborting driver load.\n"); return 1; } ppa_disconnect(host_no); printk("ppa: Communication established with ID %i using %s\n", loop, PPA_MODE_STRING[ppa_hosts[host_no].mode]); return 0; } printk("ppa: No devices found, aborting driver load.\n"); return 1;}#define PPA_ID "ppa: "int port_probe(unsigned short port){ int retv = 0; unsigned char a, b, c; unsigned int i, j; printk(PPA_ID "Probing port %04x\n", port);/* ##### ###### ###### * # # # # # # * # # # # # * ##### ###### ###### * # # # * # # # # * ##### # # */ outb(0x0c, port + 0x402); outb(0x0c, port + 0x002); outb(0x55, port); a = inb(port); if (a != 0x55) return retv; printk(PPA_ID " SPP port present\n"); retv += PPA_PROBE_SPP;/* ####### ##### ###### * # # # # # * # # # # * ##### # ###### * # # # * # # # # * ####### ##### # */ for (i = 1024; i > 0; i--) { /* clear at most 1k of data from FIFO */ a = inb(port + 0x402); if ((a & 0x03) == 0x03) goto no_ecp; if (a & 0x01) break; inb(port + 0x400); /* Remove byte from FIFO */ } if (i <= 0) goto no_ecp; b = a ^ 3; outb(b, port + 0x402); c = inb(port + 0x402); if (a == c) { outb(0xc0, port + 0x402); /* FIFO test */ j = 0; while (!(inb(port + 0x402) & 0x01) && (j < 1024)) { inb(port + 0x400); j++; } if (j >= 1024) goto no_ecp; i = 0; j = 0; while (!(inb(port + 0x402) & 0x02) && (j < 1024)) { outb(0x00, port + 0x400); i++; j++; } if (j >= 1024) goto no_ecp; j = 0; while (!(inb(port + 0x402) & 0x01) && (j < 1024)) { inb(port + 0x400); j++; } if (j >= 1024) goto no_ecp; printk(PPA_ID " ECP with a %i byte FIFO present\n", i); retv += PPA_PROBE_ECR; }/* ###### ##### ##### * # # # # # # * # # # # * ###### ##### ##### * # # # * # # # # * # ##### ####### */ no_ecp: if (retv & PPA_PROBE_ECR) outb(0x20, port + 0x402); outb(0x55, port); outb(0x0c, port + 2); a = inb(port); outb(0x55, port); outb(0x2c, port + 2); b = inb(port); if (a != b) { printk(PPA_ID " PS/2 bidirectional port present\n"); retv += PPA_PROBE_PS2; }/* ####### ###### ###### * # # # # # * # # # # # * ##### ###### ###### * # # # * # # # * ####### # # */ if (port & 0x007) { printk(PPA_ID " EPP not supported at this address\n"); return retv; } if (retv & PPA_PROBE_ECR) { for (i = 0x00; i < 0x80; i += 0x20) { outb(i, port + 0x402); a = inb(port + 1); outb(a, port + 1); outb(a & 0xfe, port + 1); a = inb(port + 1); if (!(a & 0x01)) { printk(PPA_ID " Failed Intel bug check. (Phony EPP in ECP)\n"); return retv; } } printk(PPA_ID " Passed Intel bug check.\n"); outb(0x80, port + 0x402); } a = inb(port + 1); outb(a, port + 1); outb(a & 0xfe, port + 1); a = inb(port + 1); if (a & 0x01) { outb(0x0c, port + 0x402); outb(0x0c, port + 0x002); return retv; } outb(0x04, port + 2); inb(port + 4); a = inb(port + 1); outb(a, port + 1); outb(a & 0xfe, port + 1); if (a & 0x01) { printk(PPA_ID " EPP 1.9 with hardware direction protocol\n"); retv += PPA_PROBE_EPP19; } else { /* The EPP timeout bit was not set, this could either be: * EPP 1.7 * EPP 1.9 with software direction */ outb(0x24, port + 2); inb(port + 4); a = inb(port + 1); outb(a, port + 1); outb(a & 0xfe, port + 1); if (a & 0x01) { printk(PPA_ID " EPP 1.9 with software direction protocol\n"); retv += PPA_PROBE_EPP19; } else { printk(PPA_ID " EPP 1.7\n"); retv += PPA_PROBE_EPP17; } } outb(0x0c, port + 0x402); outb(0x0c, port + 0x002); return retv;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -