/* The following #define is to avoid a clash with hosts.c */ #define IMM_PROBE_SPP 0x0001 #define IMM_PROBE_PS2 0x0002 #define IMM_PROBE_ECR 0x0010 #define IMM_PROBE_EPP17 0x0100 #define IMM_PROBE_EPP19 0x0200
typedefstruct { struct pardevice *dev; /* Parport device entry */ int base; /* Actual port address */ int base_hi; /* Hi Base address for ECP-ISA chipset */ int mode; /* Transfer mode */ struct scsi_cmnd *cur_cmd; /* Current queued command */ struct delayed_work imm_tq; /* Polling interrupt stuff */ unsignedlong jstart; /* Jiffies at start */ unsigned failed:1; /* Failure flag */ unsigned dp:1; /* Data phase present */ unsigned rd:1; /* Read data in data phase */ unsigned wanted:1; /* Parport sharing busy flag */ unsignedint dev_no; /* Device number */
wait_queue_head_t *waiting; struct Scsi_Host *host; struct list_head list;
} imm_struct;
/* This is to give the imm driver a way to modify the timings (and other *parameters)bywritingtothe/proc/scsi/imm/0file. *Verysimplemethodreally...(Toosimple,noerrorchecking:() *Reason:KernelhackersHATEhavingtounloadandreloadmodulesfor *testing... *Alsogivesamethodtouseascripttoobtainoptimumtimings(TODO)
*/ staticint imm_write_info(struct Scsi_Host *host, char *buffer, int length)
{
imm_struct *dev = imm_dev(host);
#if IMM_DEBUG > 0 #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
y, __func__, __LINE__); imm_fail_func(x,y); staticinlinevoid
imm_fail_func(imm_struct *dev, int error_code) #else staticinlinevoid
imm_fail(imm_struct *dev, int error_code) #endif
{ /* If we fail a device then we trash status / message bytes */ if (dev->cur_cmd) {
dev->cur_cmd->result = error_code << 16;
dev->failed = 1;
}
}
if (a) {
printk
("IMM: IEEE1284 negotiate indicates no data available.\n");
imm_fail(tmp, DID_ERROR);
} return a;
}
/* *ClearEPPtimeoutbit.
*/ staticinlinevoid epp_reset(unsignedshort ppb)
{ int i;
i = r_str(ppb);
w_str(ppb, i);
w_str(ppb, i & 0xfe);
}
/* *WaitforemptyECPfifo(ifweareinECPfifomodeonly)
*/ staticinlinevoid ecp_sync(imm_struct *dev)
{ int i, ppb_hi = dev->base_hi;
if (ppb_hi == 0) return;
if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */ for (i = 0; i < 100; i++) { if (r_ecr(ppb_hi) & 0x01) return;
udelay(5);
}
printk("imm: ECP sync failed as data still present in FIFO.\n");
}
}
staticint imm_byte_out(unsignedshort base, constchar *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 */ return1; /* All went well - we hope! */
}
staticint imm_nibble_in(unsignedshort base, char *buffer, int len)
{ unsignedchar l; int i;
/* *Thefollowingisbasedondocumentedtimingsignals
*/
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);
} return1; /* All went well - we hope! */
}
staticint imm_byte_in(unsignedshort base, char *buffer, int len)
{ int i;
/* *Thefollowingisbasedondocumentedtimingsignals
*/
w_ctr(base, 0x4); for (i = len; i; i--) {
w_ctr(base, 0x26);
*buffer++ = r_dtr(base);
w_ctr(base, 0x25);
} return1; /* All went well - we hope! */
}
staticint imm_out(imm_struct *dev, char *buffer, int len)
{ unsignedshort ppb = dev->base; int r = imm_wait(dev);
/* *Makesurethat: *a)theSCSIbusisBUSY(devicestilllistening) *b)thedeviceislistening
*/ if ((r & 0x18) != 0x08) {
imm_fail(dev, DID_ERROR);
printk("IMM: returned SCSI status %2x\n", r); return0;
} switch (dev->mode) { case IMM_EPP_32: case IMM_EPP_16: case IMM_EPP_8:
epp_reset(ppb);
w_ctr(ppb, 0x4); if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03))
outsl(ppb + 4, buffer, len >> 2); elseif (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01))
outsw(ppb + 4, buffer, len >> 1); else
outsb(ppb + 4, buffer, len);
w_ctr(ppb, 0xc);
r = !(r_str(ppb) & 0x01);
w_ctr(ppb, 0xc);
ecp_sync(dev); 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;
}
staticint imm_in(imm_struct *dev, char *buffer, int len)
{ unsignedshort ppb = dev->base; int r = imm_wait(dev);
/* *Makesurethat: *a)theSCSIbusisBUSY(devicestilllistening) *b)thedeviceissendingdata
*/ if ((r & 0x18) != 0x18) {
imm_fail(dev, DID_ERROR); return0;
} switch (dev->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); if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03))
insw(ppb + 4, buffer, len >> 2); elseif (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01))
insl(ppb + 4, buffer, len >> 1); else
insb(ppb + 4, buffer, len);
w_ctr(ppb, 0x2c);
r = !(r_str(ppb) & 0x01);
w_ctr(ppb, 0x2c);
ecp_sync(dev); break;
default:
printk("IMM: bug in imm_ins()\n");
r = 0; break;
} return r;
}
staticint imm_cpp(unsignedshort ppb, unsignedchar b)
{ /* *Commentsonudelayvaluesrefertothe *CommandPacketProtocol(CPP)timingdiagram.
*/
if (autodetect) { int modes = dev->dev->port->modes;
/* Mode detection works up the chain of speed *Thisavoidsanastyif-then-else-if-...tree
*/
dev->mode = IMM_NIBBLE;
if (modes & PARPORT_MODE_TRISTATE)
dev->mode = IMM_PS2;
}
if (imm_connect(dev, 0) != 1) return -EIO;
imm_reset_pulse(dev->base);
mdelay(1); /* Delay to allow devices to settle */
imm_disconnect(dev);
mdelay(1); /* Another delay to allow devices to settle */
if (!status) {
imm_fail(dev, DID_BUS_BUSY); return -1; /* ERROR_RETURN */
} if (scsi_pointer->buffer && !scsi_pointer->this_residual) { /* if scatter/gather, advance to the next segment */ if (scsi_pointer->buffers_residual--) {
scsi_pointer->buffer =
sg_next(scsi_pointer->buffer);
scsi_pointer->this_residual =
scsi_pointer->buffer->length;
scsi_pointer->ptr = sg_virt(scsi_pointer->buffer);
/* *Makesurethatwetransferevennumberofbytes *otherwiseitmakesimm_byte_out()messy.
*/ if (scsi_pointer->this_residual & 0x01)
scsi_pointer->this_residual++;
}
} /* Now check to see if the drive is ready to comunicate */
w_ctr(ppb, 0x0c);
r = (r_str(ppb) & 0xb8);
/* If not, drop back down to the scheduler and wait a timer tick */ if (!(r & 0x80)) return0;
} return1; /* FINISH_RETURN */
}
if (imm_engine(dev, cmd)) {
schedule_delayed_work(&dev->imm_tq, 1); return;
} /* Command must of completed hence it is safe to let go... */ #if IMM_DEBUG > 0 switch ((cmd->result >> 16) & 0xff) { case DID_OK: break; case DID_NO_CONNECT:
printk("imm: no device at SCSI ID %i\n", cmd->device->id); break; case DID_BUS_BUSY:
printk("imm: BUS BUSY - EPP timeout detected\n"); break; case DID_TIME_OUT:
printk("imm: unknown timeout\n"); break; case DID_ABORT:
printk("imm: told to abort\n"); break; case DID_PARITY:
printk("imm: parity error (???)\n"); break; case DID_ERROR:
printk("imm: internal driver error\n"); break; case DID_RESET:
printk("imm: told to reset device\n"); break; case DID_BAD_INTR:
printk("imm: bad interrupt (???)\n"); break; default:
printk("imm: bad return code (%02x)\n",
(cmd->result >> 16) & 0xff);
} #endif
if (imm_scsi_pointer(cmd)->phase > 1)
imm_disconnect(dev);
case2: /* Phase 2 - We are now talking to the scsi bus */ if (!imm_select(dev, scmd_id(cmd))) {
imm_fail(dev, DID_NO_CONNECT); return0;
}
scsi_pointer->phase++;
fallthrough;
case3: /* Phase 3 - Ready to accept a command */
w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return1;
if (!imm_send_command(cmd)) return0;
scsi_pointer->phase++;
fallthrough;
switch (imm_scsi_pointer(cmd)->phase) { case0: /* Do not have access to parport */ case1: /* Have not connected to interface */
dev->cur_cmd = NULL; /* Forget the problem */ return SUCCESS; default: /* SCSI command sent, can not abort */ return FAILED;
}
}
staticint device_check(imm_struct *dev, bool autodetect)
{ /* 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. */
old_mode = dev->mode; for (loop = 0; loop < 8; loop++) { /* Attempt to use EPP for Test Unit Ready */ if (autodetect && (ppb & 0x0007) == 0x0000)
dev->mode = IMM_EPP_8;
second_pass:
imm_connect(dev, CONNECT_EPP_MAYBE); /* Select SCSI device */ if (!imm_select(dev, loop)) {
imm_disconnect(dev); continue;
}
printk("imm: Found device at ID %i, Attempting to use %s\n",
loop, IMM_MODE_STRING[dev->mode]);
/* Send SCSI command */
status = 1;
w_ctr(ppb, 0x0c); for (l = 0; (l < 3) && (status); l++)
status = imm_out(dev, &cmd[l << 1], 2);
dev->dev = parport_register_dev_model(pb, "imm", &imm_cb, dev->dev_no); if (!dev->dev) goto out;
/* Claim the bus so it remembers what we do to the control *registers.[CTRandECP]
*/
err = -EBUSY;
dev->waiting = &waiting;
prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); if (imm_pb_claim(dev))
schedule_timeout(3 * HZ); if (dev->wanted) {
printk(KERN_ERR "imm%d: failed to claim parport because " "a pardevice is owning the port for too long " "time!\n", pb->number);
imm_pb_dismiss(dev);
dev->waiting = NULL;
finish_wait(&waiting, &wait); goto out1;
}
dev->waiting = NULL;
finish_wait(&waiting, &wait);
dev->base = dev->dev->port->base;
dev->base_hi = dev->dev->port->base_hi;
w_ctr(dev->base, 0x0c);
/* Done configuration */
err = imm_init(dev);
imm_pb_release(dev);
if (err) goto out1;
/* now the glue ... */ if (dev->mode == IMM_NIBBLE || dev->mode == IMM_PS2)
ports = 3; else
ports = 8;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.