📄 imm.c
字号:
static int imm_byte_out(unsigned short base, const char *buffer, int len){ int i; w_ctr(base, 0x4); /* apparently a sane mode */ for (i = len >> 1; i; i--) { w_dtr(base, *buffer++); w_ctr(base, 0x5); /* Drop STROBE low */ w_dtr(base, *buffer++); w_ctr(base, 0x0); /* STROBE high + INIT low */ } w_ctr(base, 0x4); /* apparently a sane mode */ return 1; /* All went well - we hope! */}static int imm_nibble_in(unsigned short base, char *buffer, int len){ unsigned char l; int i; /* * The following is based on documented timing signals */ w_ctr(base, 0x4); for (i = len; i; i--) { w_ctr(base, 0x6); l = (r_str(base) & 0xf0) >> 4; w_ctr(base, 0x5); *buffer++ = (r_str(base) & 0xf0) | l; w_ctr(base, 0x4); } return 1; /* All went well - we hope! */}static int imm_byte_in(unsigned short base, char *buffer, int len){ int i; /* * The following is based on documented timing signals */ w_ctr(base, 0x4); for (i = len; i; i--) { w_ctr(base, 0x26); *buffer++ = r_dtr(base); w_ctr(base, 0x25); } return 1; /* All went well - we hope! */}static int imm_out(int host_no, char *buffer, int len){ int r; unsigned short ppb = IMM_BASE(host_no); r = imm_wait(host_no); /* * Make sure that: * a) the SCSI bus is BUSY (device still listening) * b) the device is listening */ if ((r & 0x18) != 0x08) { imm_fail(host_no, DID_ERROR); printk("IMM: returned SCSI status %2x\n", r); return 0; } switch (imm_hosts[host_no].mode) { case IMM_EPP_32: case IMM_EPP_16: case IMM_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x4);#ifdef CONFIG_SCSI_IZIP_EPP16 if (!(((long) buffer | len) & 0x01)) outsw(ppb + 4, buffer, len >> 1);#else if (!(((long) buffer | len) & 0x03)) outsl(ppb + 4, buffer, len >> 2);#endif else outsb(ppb + 4, buffer, len); w_ctr(ppb, 0xc); r = !(r_str(ppb) & 0x01); w_ctr(ppb, 0xc); ecp_sync(host_no); break; case IMM_NIBBLE: case IMM_PS2: /* 8 bit output, with a loop */ r = imm_byte_out(ppb, buffer, len); break; default: printk("IMM: bug in imm_out()\n"); r = 0; } return r;}static int imm_in(int host_no, char *buffer, int len){ int r; unsigned short ppb = IMM_BASE(host_no); r = imm_wait(host_no); /* * Make sure that: * a) the SCSI bus is BUSY (device still listening) * b) the device is sending data */ if ((r & 0x18) != 0x18) { imm_fail(host_no, DID_ERROR); return 0; } switch (imm_hosts[host_no].mode) { case IMM_NIBBLE: /* 4 bit input, with a loop */ r = imm_nibble_in(ppb, buffer, len); w_ctr(ppb, 0xc); break; case IMM_PS2: /* 8 bit input, with a loop */ r = imm_byte_in(ppb, buffer, len); w_ctr(ppb, 0xc); break; case IMM_EPP_32: case IMM_EPP_16: case IMM_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x24);#ifdef CONFIG_SCSI_IZIP_EPP16 if (!(((long) buffer | len) & 0x01)) insw(ppb + 4, buffer, len >> 1);#else if (!(((long) buffer | len) & 0x03)) insl(ppb + 4, buffer, len >> 2);#endif else insb(ppb + 4, buffer, len); w_ctr(ppb, 0x2c); r = !(r_str(ppb) & 0x01); w_ctr(ppb, 0x2c); ecp_sync(host_no); break; default: printk("IMM: bug in imm_ins()\n"); r = 0; break; } return r;}static int imm_cpp(unsigned short ppb, unsigned char b){ /* * Comments on udelay values refer to the * Command Packet Protocol (CPP) timing diagram. */ unsigned char s1, s2, s3; w_ctr(ppb, 0x0c); udelay(2); /* 1 usec - infinite */ w_dtr(ppb, 0xaa); udelay(10); /* 7 usec - infinite */ w_dtr(ppb, 0x55); udelay(10); /* 7 usec - infinite */ w_dtr(ppb, 0x00); udelay(10); /* 7 usec - infinite */ w_dtr(ppb, 0xff); udelay(10); /* 7 usec - infinite */ s1 = r_str(ppb) & 0xb8; w_dtr(ppb, 0x87); udelay(10); /* 7 usec - infinite */ s2 = r_str(ppb) & 0xb8; w_dtr(ppb, 0x78); udelay(10); /* 7 usec - infinite */ s3 = r_str(ppb) & 0x38; /* * Values for b are: * 0000 00aa Assign address aa to current device * 0010 00aa Select device aa in EPP Winbond mode * 0010 10aa Select device aa in EPP mode * 0011 xxxx Deselect all devices * 0110 00aa Test device aa * 1101 00aa Select device aa in ECP mode * 1110 00aa Select device aa in Compatible mode */ w_dtr(ppb, b); udelay(2); /* 1 usec - infinite */ w_ctr(ppb, 0x0c); udelay(10); /* 7 usec - infinite */ w_ctr(ppb, 0x0d); udelay(2); /* 1 usec - infinite */ w_ctr(ppb, 0x0c); udelay(10); /* 7 usec - infinite */ w_dtr(ppb, 0xff); udelay(10); /* 7 usec - infinite */ /* * The following table is electrical pin values. * (BSY is inverted at the CTR register) * * BSY ACK POut SEL Fault * S1 0 X 1 1 1 * S2 1 X 0 1 1 * S3 L X 1 1 S * * L => Last device in chain * S => Selected * * Observered values for S1,S2,S3 are: * Disconnect => f8/58/78 * Connect => f8/58/70 */ if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30)) return 1; /* Connected */ if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38)) return 0; /* Disconnected */ return -1; /* No device present */}static inline int imm_connect(int host_no, int flag){ unsigned short ppb = IMM_BASE(host_no); imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */ imm_cpp(ppb, 0x30); /* Disconnect all devices */ if ((imm_hosts[host_no].mode == IMM_EPP_8) || (imm_hosts[host_no].mode == IMM_EPP_16) || (imm_hosts[host_no].mode == IMM_EPP_32)) return imm_cpp(ppb, 0x28); /* Select device 0 in EPP mode */ return imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */}static void imm_disconnect(int host_no){ unsigned short ppb = IMM_BASE(host_no); imm_cpp(ppb, 0x30); /* Disconnect all devices */}static int imm_select(int host_no, int target){ int k; unsigned short ppb = IMM_BASE(host_no); /* * Firstly we want to make sure there is nothing * holding onto the SCSI bus. */ w_ctr(ppb, 0xc); k = IMM_SELECT_TMO; do { k--; } while ((r_str(ppb) & 0x08) && (k)); if (!k) return 0; /* * Now assert the SCSI ID (HOST and TARGET) on the data bus */ w_ctr(ppb, 0x4); w_dtr(ppb, 0x80 | (1 << target)); udelay(1); /* * Deassert SELIN first followed by STROBE */ w_ctr(ppb, 0xc); w_ctr(ppb, 0xd); /* * ACK should drop low while SELIN is deasserted. * FAULT should drop low when the SCSI device latches the bus. */ k = IMM_SELECT_TMO; do { k--; } while (!(r_str(ppb) & 0x08) && (k)); /* * Place the interface back into a sane state (status mode) */ w_ctr(ppb, 0xc); return (k) ? 1 : 0;}static int imm_init(int host_no){ int retv;#if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE) if (imm_pb_claim(host_no)) while (imm_hosts[host_no].p_busy) schedule(); /* We can safe schedule here */#endif retv = imm_connect(host_no, 0); if (retv == 1) { imm_reset_pulse(IMM_BASE(host_no)); udelay(1000); /* Delay to allow devices to settle */ imm_disconnect(host_no); udelay(1000); /* Another delay to allow devices to settle */ retv = device_check(host_no); imm_pb_release(host_no); return retv; } imm_pb_release(host_no); return 1;}static inline int imm_send_command(Scsi_Cmnd * cmd){ int host_no = cmd->host->unique_id; int k; /* NOTE: IMM uses byte pairs */ for (k = 0; k < cmd->cmd_len; k += 2) if (!imm_out(host_no, &cmd->cmnd[k], 2)) return 0; return 1;}/* * The bulk flag enables some optimisations in the data transfer loops, * it should be true for any command that transfers data in integral * numbers of sectors. * * The driver appears to remain stable if we speed up the parallel port * i/o in this function, but not elsewhere. */static int imm_completion(Scsi_Cmnd * cmd){ /* Return codes: * -1 Error * 0 Told to schedule * 1 Finished data transfer */ int host_no = cmd->host->unique_id; unsigned short ppb = IMM_BASE(host_no); unsigned long start_jiffies = jiffies; unsigned char r, v; int fast, bulk, status; v = cmd->cmnd[0]; bulk = ((v == READ_6) || (v == READ_10) || (v == WRITE_6) || (v == WRITE_10)); /* * We only get here if the drive is ready to comunicate, * hence no need for a full imm_wait. */ w_ctr(ppb, 0x0c); r = (r_str(ppb) & 0xb8); /* * while (device is not ready to send status byte) * loop; */ while (r != (unsigned char) 0xb8) { /* * If we have been running for more than a full timer tick * then take a rest. */ if (time_after(jiffies, start_jiffies + 1)) return 0; /* * FAIL if: * a) Drive status is screwy (!ready && !present) * b) Drive is requesting/sending more data than expected */ if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) { imm_fail(host_no, DID_ERROR); return -1; /* ERROR_RETURN */ } /* determine if we should use burst I/O */ if (imm_hosts[host_no].rd == 0) { fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2; status = imm_out(host_no, cmd->SCp.ptr, fast); } else { fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1; status = imm_in(host_no, cmd->SCp.ptr, fast); } cmd->SCp.ptr += fast; cmd->SCp.this_residual -= fast; if (!status) { imm_fail(host_no, DID_BUS_BUSY); return -1; /* ERROR_RETURN */ } if (cmd->SCp.buffer && !cmd->SCp.this_residual) { /* if scatter/gather, advance to the next segment */ if (cmd->SCp.buffers_residual--) { cmd->SCp.buffer++; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; /* * Make sure that we transfer even number of bytes * otherwise it makes imm_byte_out() messy. */ if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; } } /* Now check to see if the drive is ready to comunicate */ w_ctr(ppb, 0x0c); r = (r_str(ppb) & 0xb8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -