PPA update

Martin Mares (mj@mj.gts.cz)
Sun, 13 Jul 1997 22:20:05 +0200


Hi,

I've played a bit with the PPA driver and found it doesn't work at all
with my ECP/EPP ports. I've found a couple of bugs then and re-wrote the
/proc interface (now 3x shorter).

Have a nice fortnight

-- 
Martin `MJ' Mares   <mj@gts.cz>   http://atrey.karlin.mff.cuni.cz/~mj/
Faculty of Math and Physics, Charles University, Prague, Czech Rep., Earth
"What color is a chameleon on a mirror?"

--- ./drivers/pnp/parport_init.c.mj Sun Jul 13 19:26:51 1997 +++ ./drivers/pnp/parport_init.c Sun Jul 13 19:47:52 1997 @@ -196,7 +196,7 @@ /* * Clear TIMEOUT BIT in EPP MODE */ -static int epp_clear_timeout(struct parport *pb) +int epp_clear_timeout(struct parport *pb) { int r; @@ -810,6 +810,7 @@ EXPORT_SYMBOL(parport_unregister_device); EXPORT_SYMBOL(parport_enumerate); EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok); +EXPORT_SYMBOL(epp_clear_timeout); #ifdef CONFIG_PNP_PARPORT_AUTOPROBE EXPORT_SYMBOL(parport_probe); --- ./drivers/scsi/ppa.c.mj Sun Jul 13 18:56:12 1997 +++ ./drivers/scsi/ppa.c Sun Jul 13 21:17:00 1997 @@ -113,6 +113,14 @@ * Hmm... I think I know a way but it will send the driver into * ALPHA state again. * [Curtin-1-08-STABLE] + * + * More hacks by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, 13-07-97 + * - Allowed user override of protocol type in ppa_struct. + * - Correct programming of ECR register for ECP+EPP ports. Without this, + * PPA didn't work with most ECP+EPP ports not previously set to the + * EPP mode manually. + * - Using correct algorithm for resetting of the EPP timeout bit. + * - New /proc interface. */ #include <linux/config.h> @@ -161,21 +169,31 @@ } ppa_struct; static void ppa_interrupt(void *data); -/* I know that this is a mess but it works!! */ -#define NO_HOSTS 4 + +/* + * Table of known PPA hosts. Feel free to change PPA_AUTODETECT to specific + * protocol type if the auto-detection doesn't work for you. + */ + +#define NO_HOSTS 4 /* Should be enough as we can't have more than 4 parports */ + static ppa_struct ppa_hosts[NO_HOSTS] = { {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL, - {0, 0, ppa_interrupt, NULL}, NULL}, + {0, 0, ppa_interrupt, NULL}, NULL }, {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL, - {0, 0, ppa_interrupt, NULL}, NULL}, + {0, 0, ppa_interrupt, NULL}, NULL }, {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL, - {0, 0, ppa_interrupt, NULL}, NULL}, + {0, 0, ppa_interrupt, NULL}, NULL }, {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL, - {0, 0, ppa_interrupt, NULL}, NULL} + {0, 0, ppa_interrupt, NULL}, NULL } }; -/* This is a global option */ +/* + * Default timing parameters. If you can, use the /proc interface instead of + * chaning the global values here. + */ + static int ppa_speed = -1; /* Set to >0 to act as a global value */ static int ppa_speed_fast = -1; /* ditto.. */ static int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */ @@ -236,17 +254,19 @@ static int ppa_pb_claim(int host_no) { - if (parport_claim(ppa_hosts[host_no].dev)) { - sleep_on(&ppa_hosts[host_no].ppa_wait_q); - ppa_hosts[host_no].ppa_wait_q = NULL; + ppa_struct *h = &ppa_hosts[host_no]; + + if (parport_claim(h->dev)) { + sleep_on(&h->ppa_wait_q); + h->ppa_wait_q = NULL; /* Check to see if we were aborted or reset */ - if (ppa_hosts[host_no].dev->port->cad != - ppa_hosts[host_no].dev) { + if (h->dev->port->cad != h->dev) { printk("Abort detected on ppa%i\n", host_no); return 1; } } + return 0; } @@ -473,6 +493,7 @@ ppa_hosts[host_no].timeout++; printk("PPA: EPP timeout on port 0x%04x\n", PPA_BASE(host_no)); + epp_clear_timeout(ppa_hosts[host_no].dev->port); ppa_fail(host_no, DID_BUS_BUSY); return 0; } @@ -519,6 +540,7 @@ w_str(host_no, r & 0xfe); ppa_hosts[host_no].timeout++; printk("PPA: warning: EPP timeout\n"); + epp_clear_timeout(ppa_hosts[host_no].dev->port); ppa_fail(host_no, DID_BUS_BUSY); return 0; } else @@ -1127,8 +1149,9 @@ struct Scsi_Host *hreg; int rs; int ports; - int i, nhosts; + int i, nhosts, mode; struct parport *pb = parport_enumerate(); + ppa_struct *h; printk("PPA driver version: %s\n", PPA_VERSION); nhosts = 0; @@ -1139,44 +1162,60 @@ /* We only understand PC-style ports */ if (modes & PARPORT_MODE_SPP) { + h = &ppa_hosts[i]; + /* transfer global values here */ if (ppa_speed >= 0) - ppa_hosts[i].speed = ppa_speed; + h->speed = ppa_speed; if (ppa_speed_fast >= 0) - ppa_hosts[i].speed_fast = ppa_speed_fast; - - ppa_hosts[i].dev = parport_register_device(pb, "ppa", + h->speed_fast = ppa_speed_fast; + + h->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, NULL, - PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]); - + PARPORT_DEV_TRAN, (void *) h); + /* Claim the bus so it remembers what we do to the * control registers. [ CTR and ECP ] */ ppa_pb_claim(i); w_ctr(i, 0x0c); - ppa_hosts[i].mode = PPA_NIBBLE; - if (modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) { - ppa_hosts[i].mode = PPA_EPP_32; - printk("PPA: Parport [ EPP ]\n"); - } else if (modes & PARPORT_MODE_ECP) { - w_ecr(i, 0x20); - ppa_hosts[i].mode = PPA_PS2; - printk("PPA: Parport [ ECP in PS2 submode ]\n"); - } else if (modes & PARPORT_MODE_PS2) { - ppa_hosts[i].mode = PPA_PS2; - printk("PPA: Parport [ PS2 ]\n"); + if (!(mode = h->mode)) { + if (modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) + mode = PPA_EPP_32; + else if (modes & (PARPORT_MODE_ECP | PARPORT_MODE_PS2)) + mode = PPA_PS2; + else + mode = PPA_NIBBLE; } + printk("PPA: Parport [ %s ]\n", PPA_MODE_STRING[mode]); + + /* In case we have an ECP port, switch it to the desired mode. */ + if (modes & (PARPORT_MODE_ECP | PARPORT_MODE_ECPEPP)) { + w_ecr(i, 0x00); /* We must reset it to the standard mode first */ + switch (mode) { + case PPA_PS2: + w_ecr(i, 0x20); + break; + case PPA_EPP_8: + case PPA_EPP_16: + case PPA_EPP_32: + w_ecr(i, 0x80); + break; + } + } + /* Done configuration */ + h->mode = mode; ppa_pb_release(i); rs = ppa_init(i); if (rs) { - parport_unregister_device(ppa_hosts[i].dev); + parport_unregister_device(h->dev); continue; } /* now the glue ... */ - switch (ppa_hosts[i].mode) { + switch (mode) { case PPA_NIBBLE: case PPA_PS2: ports = 3; @@ -1197,7 +1236,7 @@ hreg->n_io_port = ports; hreg->dma_channel = -1; hreg->unique_id = i; - ppa_hosts[i].host = hreg->host_no; + h->host = hreg->host_no; nhosts++; } } @@ -1225,105 +1264,74 @@ return 0; } -static int ppa_proc_write(int hostno, char *buffer, int length) +static int ppa_proc_write(ppa_struct *h, char *buffer, int length) { unsigned long x; - const char *inv_num = "ppa /proc entry passed invalid number\n"; + const char *inv_num = KERN_ERR "ppa: /proc entry passed an invalid number\n"; if ((length > 15) && (ppa_strncmp(buffer, "ppa_speed_fast=", 15) == 0)) { x = simple_strtoul(buffer + 15, NULL, 0); - if (x <= ppa_hosts[hostno].speed) - ppa_hosts[hostno].speed_fast = x; + if (x <= h->speed) + h->speed_fast = x; else printk(inv_num); return length; } if ((length > 10) && (ppa_strncmp(buffer, "ppa_speed=", 10) == 0)) { x = simple_strtoul(buffer + 10, NULL, 0); - if (x >= ppa_hosts[hostno].speed_fast) - ppa_hosts[hostno].speed = x; + if (x >= h->speed_fast) + h->speed = x; else printk(inv_num); return length; } if ((length > 10) && (ppa_strncmp(buffer, "epp_speed=", 10) == 0)) { x = simple_strtoul(buffer + 10, NULL, 0); - ppa_hosts[hostno].epp_speed = x; + h->epp_speed = x; return length; } if ((length > 12) && (ppa_strncmp(buffer, "epp_timeout=", 12) == 0)) { x = simple_strtoul(buffer + 12, NULL, 0); - ppa_hosts[hostno].timeout = x; + h->timeout = x; return length; } if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) { x = simple_strtoul(buffer + 5, NULL, 0); - ppa_hosts[hostno].mode = x; + h->mode = x; return length; } - printk("ppa /proc: invalid variable\n"); - return (-EINVAL); + printk(KERN_ERR "ppa: /proc: invalid variable\n"); + return -EINVAL; } int ppa_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { - int i; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; + int i, len; + char *p = buffer; + ppa_struct *h; - for (i = 0; i < 4; i++) + for (i = 0; i < NO_HOSTS; i++) if (ppa_hosts[i].host == hostno) break; + if (i >= NO_HOSTS) + return -ENXIO; + h = &ppa_hosts[i]; if (inout) - return ppa_proc_write(i, buffer, length); - - size = sprintf(buffer + len, "Version : %s\n", PPA_VERSION); - len += size; - pos = begin + len; - size = sprintf(buffer + len, "Parport : %s\n", - ppa_hosts[i].dev->port->name); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "Mode : %s\n", - PPA_MODE_STRING[ppa_hosts[i].mode]); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "\nTiming Parameters\n"); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "ppa_speed %i\n", - ppa_hosts[i].speed); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "ppa_speed_fast %i\n", - ppa_hosts[i].speed_fast); - len += size; - pos = begin + len; + return ppa_proc_write(h, buffer, length); + p += sprintf(p, "Version:\t%s\n", PPA_VERSION); + p += sprintf(p, "Parport:\t%s\n", h->dev->port->name); + p += sprintf(p, "Mode:\t%s\n", PPA_MODE_STRING[h->mode]); + p += sprintf(p, "ppa_speed:\t%i\n", h->speed); + p += sprintf(p, "ppa_speed_fast:\t%i\n", h->speed_fast); if (IN_EPP_MODE(ppa_hosts[i].mode)) { - size = sprintf(buffer + len, "epp_speed %i\n", - ppa_hosts[i].epp_speed); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "\nInternal Counters\n"); - len += size; - pos = begin + len; - - size = sprintf(buffer + len, "epp_timeout %i\n", - ppa_hosts[i].timeout); - len += size; - pos = begin + len; + p += sprintf(p, "epp_speed:\t%i\n", h->epp_speed); + p += sprintf(p, "epp_timeout_count:\t%i\n", h->timeout); } - *start = buffer + (offset + begin); - len -= (offset - begin); + *start = buffer + offset; + len = p - *start; if (len > length) len = length; return len; --- ./include/linux/parport.h.mj Sun Jul 13 19:27:04 1997 +++ ./include/linux/parport.h Sun Jul 13 20:14:25 1997 @@ -227,4 +227,6 @@ return inb(port->base+1); } +extern int epp_clear_timeout(struct parport *); + #endif /* _PARPORT_H_ */