/* This is to give the ppa driver a way to modify the timings (and other *parameters)bywritingtothe/proc/scsi/ppa/0file. *Verysimplemethodreally...(Tosimple,noerrorchecking:() *Reason:KernelhackersHATEhavingtounloadandreloadmodulesfor *testing... *Alsogivesamethodtouseascripttoobtainoptimumtimings(TODO)
*/
#if PPA_DEBUG > 0 #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
y, __func__, __LINE__); ppa_fail_func(x,y); staticinlinevoid ppa_fail_func(ppa_struct *dev, int error_code) #else staticinlinevoid ppa_fail(ppa_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;
}
}
/* Counter expired - Time out occurred */
ppa_fail(dev, DID_TIME_OUT);
printk(KERN_WARNING "ppa timeout in ppa_wait\n"); return0; /* command timed out */
}
/* *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(ppa_struct *dev)
{ int i, ppb_hi = dev->dev->port->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(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n");
}
}
staticint ppa_byte_out(unsignedshort base, constchar *buffer, int len)
{ int i;
for (i = len; i; i--) {
w_dtr(base, *buffer++);
w_ctr(base, 0xe);
w_ctr(base, 0xc);
} return1; /* All went well - we hope! */
}
staticint ppa_byte_in(unsignedshort base, char *buffer, int len)
{ int i;
for (i = len; i; i--) {
*buffer++ = r_dtr(base);
w_ctr(base, 0x27);
w_ctr(base, 0x25);
} return1; /* All went well - we hope! */
}
staticint ppa_nibble_in(unsignedshort base, char *buffer, int len)
{ for (; len; len--) { unsignedchar h;
w_ctr(base, 0x4);
h = r_str(base) & 0xf0;
w_ctr(base, 0x6);
*buffer++ = h | ((r_str(base) & 0xf0) >> 4);
} return1; /* All went well - we hope! */
}
staticint ppa_out(ppa_struct *dev, char *buffer, int len)
{ int r; unsignedshort ppb = dev->base;
r = ppa_wait(dev);
if ((r & 0x50) != 0x40) {
ppa_fail(dev, DID_ERROR); return0;
} switch (dev->mode) { case PPA_NIBBLE: case PPA_PS2: /* 8 bit output, with a loop */
r = ppa_byte_out(ppb, buffer, len); break;
case PPA_EPP_32: case PPA_EPP_16: case PPA_EPP_8:
epp_reset(ppb);
w_ctr(ppb, 0x4); if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x03))
outsl(ppb + 4, buffer, len >> 2); elseif (dev->mode == PPA_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;
default:
printk(KERN_ERR "PPA: bug in ppa_out()\n");
r = 0;
} return r;
}
staticint ppa_in(ppa_struct *dev, char *buffer, int len)
{ int r; unsignedshort ppb = dev->base;
r = ppa_wait(dev);
if ((r & 0x50) != 0x50) {
ppa_fail(dev, DID_ERROR); return0;
} switch (dev->mode) { case PPA_NIBBLE: /* 4 bit input, with a loop */
r = ppa_nibble_in(ppb, buffer, len);
w_ctr(ppb, 0xc); break;
case PPA_PS2: /* 8 bit input, with a loop */
w_ctr(ppb, 0x25);
r = ppa_byte_in(ppb, buffer, len);
w_ctr(ppb, 0x4);
w_ctr(ppb, 0xc); break;
case PPA_EPP_32: case PPA_EPP_16: case PPA_EPP_8:
epp_reset(ppb);
w_ctr(ppb, 0x24); if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x03))
insl(ppb + 4, buffer, len >> 2); elseif (dev->mode == PPA_EPP_16 && !(((long) buffer | len) & 0x01))
insw(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(KERN_ERR "PPA: bug in ppa_ins()\n");
r = 0; break;
} return r;
}
/* end of ppa_io.h */ staticinlinevoid ppa_d_pulse(unsignedshort ppb, unsignedchar b)
{
w_dtr(ppb, b);
w_ctr(ppb, 0xc);
w_ctr(ppb, 0xe);
w_ctr(ppb, 0xc);
w_ctr(ppb, 0x4);
w_ctr(ppb, 0xc);
}
w_ctr(ppb, 0xe); if ((r_str(ppb) & 0x08) == 0x08)
retv--;
w_ctr(ppb, 0xc); if ((r_str(ppb) & 0x08) == 0x00)
retv--;
if (!retv)
ppa_reset_pulse(ppb);
udelay(1000); /* Allow devices to settle down */
ppa_disconnect(dev);
udelay(1000); /* Another delay to allow devices to settle */
/* On some hardware we have SCSI disconnected (6th bit low) *forabout100usecs.Itistooexpensivetowaita *tickoneveryloopsowebusywaitfornomorethan *500usecstogivethedriveachancefirst.Wedonot *changethingsfor"normal"hardwaresincegenerally *the6thbitisalwayshigh. *ThismakestheCPUloadhigheronsomehardware *butotherwisewecannotgetmorethan50K/secs *onthisproblemhardware.
*/ if ((r & 0xc0) != 0xc0) { /* Wait for reconnection should be no more than *jiffy/2=5ms=5000loops
*/ unsignedlong k = dev->recon_tmo; for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0;
k--)
udelay(1);
if (!k) return0;
}
/* determine if we should use burst I/O */
fast = bulk && scsi_pointer->this_residual >= PPA_BURST_SIZE ?
PPA_BURST_SIZE : 1;
if (r == (unsignedchar) 0xc0)
status = ppa_out(dev, scsi_pointer->ptr, fast); else
status = ppa_in(dev, scsi_pointer->ptr, fast);
if (!status) {
ppa_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);
}
} /* Now check to see if the drive is ready to comunicate */
r = (r_str(ppb) & 0xf0); /* If not, drop back down to the scheduler and wait a timer tick */ if (!(r & 0x80)) return0;
} return1; /* FINISH_RETURN */
}
if (!cmd) {
printk(KERN_ERR "PPA: bug in ppa_interrupt\n"); return;
} if (ppa_engine(dev, cmd)) {
schedule_delayed_work(&dev->ppa_tq, 1); return;
} /* Command must of completed hence it is safe to let go... */ #if PPA_DEBUG > 0 switch ((cmd->result >> 16) & 0xff) { case DID_OK: break; case DID_NO_CONNECT:
printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", scmd_id(cmd)); break; case DID_BUS_BUSY:
printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n"); break; case DID_TIME_OUT:
printk(KERN_DEBUG "ppa: unknown timeout\n"); break; case DID_ABORT:
printk(KERN_DEBUG "ppa: told to abort\n"); break; case DID_PARITY:
printk(KERN_DEBUG "ppa: parity error (???)\n"); break; case DID_ERROR:
printk(KERN_DEBUG "ppa: internal driver error\n"); break; case DID_RESET:
printk(KERN_DEBUG "ppa: told to reset device\n"); break; case DID_BAD_INTR:
printk(KERN_WARNING "ppa: bad interrupt (???)\n"); break; default:
printk(KERN_WARNING "ppa: bad return code (%02x)\n",
(cmd->result >> 16) & 0xff);
} #endif
if (ppa_scsi_pointer(cmd)->phase > 1)
ppa_disconnect(dev);
ppa_pb_dismiss(dev);
dev->cur_cmd = NULL;
scsi_done(cmd);
}
staticint ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
{ struct scsi_pointer *scsi_pointer = ppa_scsi_pointer(cmd); unsignedshort ppb = dev->base; unsignedchar l = 0, h = 0; int retv;
/* First check for any errors that may of occurred *Herewecheckforinternalerrors
*/ if (dev->failed) return0;
switch (scsi_pointer->phase) { case0: /* Phase 0 - Waiting for parport */ if (time_after(jiffies, dev->jstart + HZ)) { /* *Wewaitedmorethanasecond *forparporttocallus
*/
ppa_fail(dev, DID_BUS_BUSY); return0;
} return1; /* wait until ppa_wakeup claims parport */ case1: /* Phase 1 - Connected */
{ /* Perform a sanity check for cable unplugged */ int retv = 2; /* Failed */
ppa_connect(dev, 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 (time_after(jiffies, dev->jstart + (1 * HZ))) {
printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n");
ppa_fail(dev, DID_BUS_BUSY); return0;
} else {
ppa_disconnect(dev); return1; /* Try again in a jiffy */
}
}
scsi_pointer->phase++;
}
fallthrough;
case2: /* Phase 2 - We are now talking to the scsi bus */ if (!ppa_select(dev, scmd_id(cmd))) {
ppa_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 (!ppa_send_command(cmd)) return0;
scsi_pointer->phase++;
fallthrough;
switch (ppa_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(ppa_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 = PPA_EPP_8;
second_pass:
ppa_connect(dev, CONNECT_EPP_MAYBE); /* Select SCSI device */ if (!ppa_select(dev, loop)) {
ppa_disconnect(dev); continue;
}
printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n",
loop, PPA_MODE_STRING[dev->mode]);
/* Send SCSI command */
status = 1;
w_ctr(ppb, 0x0c); for (l = 0; (l < 6) && (status); l++)
status = ppa_out(dev, cmd, 1);
if (!status) {
ppa_disconnect(dev);
ppa_connect(dev, CONNECT_EPP_MAYBE);
w_dtr(ppb, 0x40);
w_ctr(ppb, 0x08);
udelay(30);
w_ctr(ppb, 0x0c);
udelay(1000);
ppa_disconnect(dev);
udelay(1000); if (dev->mode != old_mode) {
dev->mode = old_mode; goto second_pass;
} return -EIO;
}
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(dev);
ppa_connect(dev, CONNECT_EPP_MAYBE);
ppa_reset_pulse(ppb);
udelay(1000);
ppa_disconnect(dev);
udelay(1000); if (dev->mode != old_mode) {
dev->mode = old_mode; goto second_pass;
} return -EIO;
}
ppa_disconnect(dev);
printk(KERN_INFO "ppa: Communication established with ID %i using %s\n",
loop, PPA_MODE_STRING[dev->mode]);
ppa_connect(dev, CONNECT_EPP_MAYBE);
ppa_reset_pulse(ppb);
udelay(1000);
ppa_disconnect(dev);
udelay(1000); return0;
} return -ENODEV;
}
/* 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 (ppa_pb_claim(dev))
schedule_timeout(3 * HZ); if (dev->wanted) {
printk(KERN_ERR "ppa%d: failed to claim parport because " "a pardevice is owning the port for too long " "time!\n", pb->number);
ppa_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;
w_ctr(dev->base, 0x0c);
/* Done configuration */
err = ppa_init(dev);
ppa_pb_release(dev);
if (err) goto out1;
/* now the glue ... */ if (dev->mode == PPA_NIBBLE || dev->mode == PPA_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.