/* * /sys/i386/isa/ppa3.c * * FreeBSD driver for PPA3 adapter * embedded in the IOMEGA ZIP 100 drive. * * See README file. * * Release: 0.10 * Release: 0.11 * ------------- * - *int32 becomes *int32_t. This may give some warnings during * compilation process. * * Release: 0.20 * ------------- * - Interrupt emulation with timeout(). Some parallel * ports support interrupts, the ZIP drive doesn't. * - This release is a port of the 0.26 Linux driver. * * Release: 0.31 * ------------- * - ppa becomes a controller in the /sys/i386/conf/MACHINE file. * - PS/2 byte mode via ECP supported. * - EPP transfer mode supported but not detected. * - Software interrupt disabled. * - Transfer mode may be defined via the 'flags' field. * - Note: this release is a port of the 0.26-athena Linux driver. * * Release: 0.32 * ------------- * - bug fixed with SUCCESSFULLY_QUEUED return value. * * Release: 0.40 * ------------- * - This release is a port of the 1.01-curtin Linux driver. * * Release: 0.41 * ------------- * - HAVE_SMC patch removed. * - Distributed with 'eppconfig' tool to configure epp_speed. * - This release is a port of the 1.05-curtin Linux driver. * * Release: 0.42-ALPHA * ------------------- * - Better error report. * - EPP+ECP generic detection. * - Warning logs added. * - splsoftclock() level for io transfers. * - This release is a port of the 1.06-curtin Linux driver. * - Bugs fixed in ppaio_outstr() and ppaio_instr() * * Release: 0.50-BETA * ------------------ * - Printer facilities added. * - splbio() level for io transfers. * * Release: 0.51-BETA * ------------------ * - FreeBSD R2.2 port. * * Release: 0.52-BETA * ------------------ * - 'extern struct isa_driver lptdriver;' * added for 2.1.x compatibility. * * Release: 0.53-BETA * ------------------ * - PPA_21x_COMPAT defined. * - (ppaio_wait() return value & 0xc0) compared to 0xc0. * - PPA_SPINTMO increased up to 500000. * * Release: 0.54-BETA * ------------------ * - Fixed for 2.1.x release. * * Release: 0.60-BETA * ------------------ * - PPA_INTRTMO and PPA_LPT removed. * - PPA_BUFFER_SIZE set to 0x12000. * - ppa_warning() added. * - REQUEST_SENSE implemented. * * Release: 0.61-BETA * ------------------ * - PPA_SPINTMO increased up to 5000000. * * ------------------------------------------------------------------- * THIS SOFTWARE IS DISTRIBUTED WITH NO WARRANTY. * ------------------------------------------------------------------- * * This driver is a port of the Linux driver. * * ------------------------------------------------------------------- * NOT SUPPORTED ANYMORE !!! * ------------------------------------------------------------------- */ /* -------------------------------------------------------------------- * HERE ARE THINGS YOU MAY HAVE/WANT TO CHANGE */ /* * PPA_21x_COMPAT defined if your system release is R2.1.x */ #ifndef PPA_ECHECKING #define PPA_ECHECKING 3 /* more error checking for EPP transfer mode, * decreases transfer rate. * 0 = no errors checking * 1 = every 4 bytes * 2 = every 2 bytes * 3 = every byte (DEFAULT and SAFE) */ #endif #ifndef PPA_EPP_SPEED #define PPA_EPP_SPEED 4096 /* delay for EPP mode */ #endif #define PPA_SPEED_HIGH 1 /* high speed delay for SPP modes */ #define PPA_SPEED_LOW 3 /* low speed delay for SPP modes */ #define PPA_SELTMO 5000 /* select timeout */ #define PPA_SPINTMO 5000000 /* wait status timeout */ #define PPA_MAXRETRY 0 /* internal retry count */ /* XXX * This is ALPHA/BETA code, warnings are mandatory. */ #ifndef PPA_WARNING #define PPA_WARNING /* defined to get warnings about timeouts, * except select timeouts */ #endif /* * DO NOT MODIFY ANYTHING UNDER THIS LINE * -------------------------------------------------------------------- */ #include #ifdef KERNEL #include #include #include #include #include #include #include #include #include #ifdef PPA_WARNING #include #endif #ifdef PPA_21x_COMPAT #include #endif #include #endif /* KERNEL */ #include #include #include #ifdef KERNEL #include #endif /*KERNEL */ /* * If DEV_LKM is defined, NPPA must be > 0. */ #ifndef DEV_LKM #include "ppa.h" #endif #if NPPA > 0 #define PPA_VERSION "0.62-BETA" #define barrier() __asm__("": : :"memory") #define PPA_INITIATOR 0x7 #define PPA_SECTOR_SIZE 512 #define PPA_BUFFER_SIZE 0x12000 #define STATUS_MASK 0xff #define PPA_SPL() splbio() #define PPA_ESELECT_TIMEOUT 1 #define PPA_ESPPCMD_TIMEOUT 2 #define PPA_EREPLY_TIMEOUT 3 #define PPA_ESTATUS_TIMEOUT 4 #define PPA_EDATA_OVERFLOW 5 #define PPA_EPPCMD_TIMEOUT 6 #define PPA_EPPDATA_TIMEOUT 7 #define PPA_EPPSTATUS_ERROR 8 #define PPA_ENOPORT 9 #define PPA_EINITFAILED 10 #define PPA_EDATA_STATUS 11 #define PPA_EOTHER 12 #define PPA_OPENNINGS 1 #define PPA_MODE_MASK 0xff #define PPA_EPP_MASK 0xffff00 /* 16 bits should be enough */ #define PPA_EPP_RSHIFT 8 /* according to PPA_MODE_MASK */ #define PPA_AUTODETECT 0x0 /* autodetect NIBBLE or PS/2 mode */ #define PPA_NIBBLE 0x1 /* standard 4 bit mode */ #define PPA_PS2 0x2 /* PS/2 byte mode */ #define PPA_EPP_8 0x3 /* EPP mode, 8 bit */ #define PPA_EPP_16 0x4 /* EPP mode, 16 bit */ #define PPA_EPP_32 0x5 /* EPP mode, 32 bit */ #define PPA_PS2_ECP 0x6 /* ECP in PS/2 mode */ #define PPA_UNKNOWN 0x7 #define SPP_DTR 0 /* SPP data register */ #define SPP_STR 1 /* SPP status register */ #define SPP_CTR 2 /* SPP control register */ #define EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */ #define ECP_FIFO 0x400 /* ECP fifo register */ #define ECP_ECR 0x402 /* ECP extended control register */ #define IN_EPP_MODE(ppa) ((ppa)->ppa_mode == PPA_EPP_8 || \ (ppa)->ppa_mode == PPA_EPP_16 || (ppa)->ppa_mode == PPA_EPP_32) #define CONNECT_EPP_MAYBE 1 #define CONNECT_NORMAL 0 struct ppa_sense { struct scsi_sense cmd; unsigned int stat; unsigned int count; }; struct ppa_data { int ppa_base; unsigned short ppa_unit; #ifdef PPA_LPT struct isa_device * ppa_lptdev; #endif struct ppa_sense ppa_sense; unsigned char ppa_buffer[PPA_BUFFER_SIZE]; unsigned int ppa_stat; unsigned int ppa_count; unsigned char ppa_mode; unsigned char ppa_port_delay; struct scsi_link sc_link; int ppa_epp_speed; }; #define ppaio_outsb(ppa,port,addr,cnt) \ outsb ((ppa)->ppa_base + port, addr, cnt) #define ppaio_outsw(ppa,port,addr,cnt) \ outsw ((ppa)->ppa_base + port, addr, cnt) #define ppaio_outsl(ppa,port,addr,cnt) \ outsl ((ppa)->ppa_base + port, addr, cnt) #define ppaio_insb(ppa,port,addr,cnt) \ insb ((ppa)->ppa_base + port, addr, cnt) #define ppaio_insw(ppa,port,addr,cnt) \ insw ((ppa)->ppa_base + port, addr, cnt) #define ppaio_insl(ppa,port,addr,cnt) \ insl ((ppa)->ppa_base + port, addr, cnt) #define r_dtr(ppa) ((char) inb((ppa)->ppa_base + SPP_DTR)) #define r_str(ppa) ((char) inb((ppa)->ppa_base + SPP_STR)) #define r_ctr(ppa) ((char) inb((ppa)->ppa_base + SPP_CTR)) #define r_epp(ppa) ((char) inb((ppa)->ppa_base + EPP_DATA)) #define r_fifo(ppa) ((char) inb((ppa)->ppa_base + ECP_FIFO)) #define r_ecr(ppa) ((char) inb((ppa)->ppa_base + ECP_ECR)) #define w_dtr(ppa,byte) { \ outb((ppa)->ppa_base + SPP_DTR, byte); \ } #define w_str(ppa,byte) { \ outb((ppa)->ppa_base + SPP_STR, byte); \ } #define w_ctr(ppa,byte) { \ outb((ppa)->ppa_base + SPP_CTR, byte); \ DELAY ((ppa)->ppa_port_delay); \ } #define w_epp(ppa,byte) outb((ppa)->ppa_base + EPP_DATA, byte) #define w_fifo(ppa,byte) outb((ppa)->ppa_base + ECP_FIFO, byte) #define w_ecr(ppa,byte) outb((ppa)->ppa_base + ECP_ECR, byte) static inline int ppaio_do_scsi __P((struct ppa_data *, int, int, char *, int, char *, int, int *, int *)); static struct ppa_data * ppadata[NPPA]; static int ppaprobe __P((struct isa_device *)); static int ppaattach __P((struct isa_device *)); static int32_t ppa_scsi_cmd __P((struct scsi_xfer *)); static void ppaminphys __P((struct buf *)); static u_int32_t ppa_adapter_info __P((int)); static int ppaio_detect __P((struct ppa_data *)); #ifdef KERNEL static struct scsi_adapter ppa_switch = { ppa_scsi_cmd, ppaminphys, 0, 0, ppa_adapter_info, "ppa", { 0, 0 } }; /* * The below structure is so we have a default dev struct * for out link struct. */ static struct scsi_device ppa_dev = { NULL, /* Use default error handler */ NULL, /* have a queue, served by this */ NULL, /* have no async handler */ NULL, /* Use default 'done' routine */ "ppa", 0, { 0, 0 } }; struct isa_driver ppadriver = { ppaprobe, ppaattach, "ppa" }; #ifdef PPA_21x_COMPAT static struct kern_devconf kdc_ppa[NPPA] = { { 0, 0, 0, /* filled in by dev_attach */ "ppa", 0, { MDDT_ISA, 0, "bio" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, &kdc_isa0, /* parent */ 0, /* parentdata */ DC_UNCONFIGURED, /* always start out here */ "Iomega PPA3 Parallel Port SCSI host adapter", DC_CLS_MISC }}; #endif #ifdef PPA_21x_COMPAT #ifndef DEV_LKM static inline void ppa_registerdev (struct isa_device * id) { if (id->id_unit) kdc_ppa[id->id_unit] = kdc_ppa[0]; kdc_ppa[id->id_unit].kdc_unit = id->id_unit; kdc_ppa[id->id_unit].kdc_parentdata = id; dev_attach(&kdc_ppa[id->id_unit]); } #endif #endif #endif /* KERNEL */ static int ppaunit = 0; static u_int32_t ppa_adapter_info (int unit) { return 1; } static int ppa_init (int unit) { struct ppa_data * ppa = ppadata[unit]; int rs; if ((rs = ppaio_detect (ppa))) { switch (rs) { case PPA_ENOPORT: printf ("ppa%d: parallel port not found at 0x%x.\n", unit, ppa->ppa_base); break; case PPA_EINITFAILED: printf ("ppa%d: controller initialisation failed.\n", unit); break; default: printf ("ppa%d: ppa_init() failed, error %d.\n", unit, rs); } return 1; } return 0; } #if defined (PPA_21x_COMPAT) && defined(PPA_LPT) extern struct isa_driver lptdriver; #endif #ifdef PPA_LPT static int ppa_lptprobe (struct ppa_data * ppa) { struct isa_device * dvp; printf ("ppa%d: searching disabled polling lpt driver... ", ppa->ppa_unit); for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) { if (dvp->id_enabled) continue; if (dvp->id_driver == &lptdriver && dvp->id_irq == 0) { printf ("found.\n"); goto probe; } } printf ("not found.\n"); return 1; probe: dvp->id_iobase = ppa->ppa_base; ppa->ppa_lptdev = dvp; (*ppa->ppa_lptdev->id_driver->probe) (ppa->ppa_lptdev); return 0; } #endif static int ppaprobe (struct isa_device * dev) { int unit = ppaunit; struct ppa_data * ppa; int rv = -1; if (unit >= NPPA) { printf("ppa%d: unit number too high\n", unit); return 0; } dev->id_unit = unit; if (ppadata[unit]) { printf("ppa%d: memory already allocated\n", unit); return 0; } ppa = malloc (sizeof(struct ppa_data), M_TEMP, M_NOWAIT); if (!ppa) { printf("ppa%d: cannot malloc!\n", unit); return 0; } bzero(ppa, sizeof(struct ppa_data)); ppadata[unit] = ppa; ppa->ppa_base = dev->id_iobase; ppa->ppa_port_delay = PPA_SPEED_LOW; ppa->ppa_unit = unit; #define GET_PPA_MODE(dev) \ (dev->id_flags & PPA_MODE_MASK) ppa->ppa_mode = GET_PPA_MODE (dev); #define GET_EPP_SPEED(dev) \ ((dev->id_flags & PPA_EPP_MASK) ? \ (dev->id_flags & PPA_EPP_MASK) >> PPA_EPP_RSHIFT : \ PPA_EPP_SPEED) ppa->ppa_epp_speed = GET_EPP_SPEED (dev); if (ppa->ppa_mode >= PPA_UNKNOWN) { printf ("ppa%d: invalid mode (0x%x), " \ "autodetect mode selected.\n", ppa->ppa_unit, ppa->ppa_mode); ppa->ppa_mode = PPA_AUTODETECT; } if (ppa->ppa_mode) switch (ppa->ppa_mode) { case PPA_NIBBLE: printf ("ppa%d: SPP (4 bit) mode forced.\n", ppa->ppa_unit); break; case PPA_PS2: printf ("ppa%d: PS/2 (8 bit) mode forced.\n", ppa->ppa_unit); break; case PPA_EPP_8: printf ("ppa%d: EPP 8 bit mode forced, " \ "ppa_epp_speed = %d at 0x%x\n", ppa->ppa_unit, ppa->ppa_epp_speed, &ppa->ppa_epp_speed); break; case PPA_EPP_16: printf ("ppa%d: EPP 16 bit mode forced, " \ "ppa_epp_speed = %d at 0x%x\n", ppa->ppa_unit, ppa->ppa_epp_speed, &ppa->ppa_epp_speed); break; case PPA_EPP_32: printf ("ppa%d: EPP 32 bit mode forced, " \ "ppa_epp_speed = %d at 0x%x\n", ppa->ppa_unit, ppa->ppa_epp_speed, &ppa->ppa_epp_speed); break; case PPA_PS2_ECP: printf ("ppa%d: PS/2 (8 bit) mode forced "\ "with ECP.\n", ppa->ppa_unit); break; default: panic ("ppa_probe(): invalid mode (0x%x)!", ppa->ppa_mode); } #ifdef PPA_21x_COMPAT #ifndef DEV_LKM ppa_registerdev(dev); #endif #endif if ((rv = ppa_init(unit)) != 0) { #ifdef DEBUG_PPA3 log (LOG_DEBUG, "ppaprobe(): ppa_init() error (%d)\n", rv); #endif ppadata[unit] = NULL; free(ppa, M_TEMP); return 0; } #ifdef PPA_LPT ppa->ppa_lptdev = 0; if (IN_EPP_MODE (ppa)) printf ("ppa%d: lpt unavailable in EPP mode.\n", ppa->ppa_unit); else ppa_lptprobe (ppa); #endif ppaunit ++; return 4; } /* * Attach all the sub-devices we can find. */ static int ppaattach (struct isa_device * dev) { int unit = dev->id_unit; struct ppa_data * ppa = ppadata[unit]; struct scsibus_data * scbus; ppa->sc_link.adapter_unit = unit; ppa->sc_link.adapter_targ = PPA_INITIATOR; ppa->sc_link.adapter = &ppa_switch; ppa->sc_link.device = &ppa_dev; ppa->sc_link.opennings = PPA_OPENNINGS; /* * Prepare the scsibus_data area for the upperlevel * scsi code. */ scbus = scsi_alloc_bus(); if(!scbus) return 0; scbus->adapter_link = &ppa->sc_link; #ifdef PPA_21x_COMPAT /* * Ask the adapter what subunits are present. */ kdc_ppa[unit].kdc_state = DC_BUSY; /* host adapters are always busy */ #endif scsi_attachdevs(scbus); #ifdef PPA_LPT if (ppa->ppa_lptdev) (*ppa->ppa_lptdev->id_driver->attach) (ppa->ppa_lptdev); #endif return 1; } static void ppaminphys(struct buf * bp) { if (bp->b_bcount > PPA_BUFFER_SIZE) bp->b_bcount = PPA_BUFFER_SIZE; return; } static inline void ppa_warning (struct ppa_data * ppa, struct scsi_xfer * xs, int timeout) { switch (timeout) { case 0: case PPA_ESELECT_TIMEOUT: break; case PPA_EPPCMD_TIMEOUT: log (LOG_WARNING, "ppa%d: EPP command timeout\n", ppa->ppa_unit); break; case PPA_EPPDATA_TIMEOUT: log (LOG_WARNING, "ppa%d: EPP data timeout\n", ppa->ppa_unit); break; case PPA_EPPSTATUS_ERROR: log (LOG_WARNING, "ppa%d: EPP status error\n", ppa->ppa_unit); break; case PPA_ESTATUS_TIMEOUT: log (LOG_WARNING, "ppa%d: SPP status timeout\n", ppa->ppa_unit); break; case PPA_EDATA_OVERFLOW: log (LOG_WARNING, "ppa%d: data overflow\n", ppa->ppa_unit); break; case PPA_EDATA_STATUS: log (LOG_WARNING, "ppa%d: unknown transfer status\n", ppa->ppa_unit); break; case PPA_ESPPCMD_TIMEOUT: log (LOG_WARNING, "ppa%d: SPP command timeout\n", ppa->ppa_unit); break; case PPA_EREPLY_TIMEOUT: log (LOG_WARNING, "ppa%d: command reply timeout\n", ppa->ppa_unit); break; default: log (LOG_WARNING, "ppa%d: timeout = %d\n", ppa->ppa_unit, timeout); break; } } static inline void ppaintr (struct ppa_data * ppa, struct scsi_xfer * xs) { register int timeout; if (xs->datalen && !(xs->flags & SCSI_DATA_IN)) bcopy (xs->data, ppa->ppa_buffer, xs->datalen); timeout = ppaio_do_scsi (ppa, PPA_INITIATOR, xs->sc_link->target, (char *) xs->cmd, xs->cmdlen, ppa->ppa_buffer, xs->datalen, &ppa->ppa_stat, &ppa->ppa_count); #ifdef PPA_WARNING ppa_warning (ppa, xs, timeout); #endif #ifdef DEBUG_PPA3 log (LOG_DEBUG, "ppa_do_scsi = %d, status = 0x%x, count = %d\n", timeout, ppa->ppa_stat, ppa->ppa_count); #endif #define RESERVED_BITS_MASK 0x3e /* 00111110b */ #define NO_SENSE 0x0 #define CHECK_CONDITION 0x02 switch (ppa->ppa_stat & RESERVED_BITS_MASK) { case NO_SENSE: break; case CHECK_CONDITION: default: ppa->ppa_sense.cmd.op_code = REQUEST_SENSE; ppa->ppa_sense.cmd.length = sizeof (xs->sense); ppa->ppa_sense.cmd.control = 0; timeout = ppaio_do_scsi (ppa, PPA_INITIATOR, xs->sc_link->target, (char *) &ppa->ppa_sense.cmd, sizeof (ppa->ppa_sense.cmd), (char *) &xs->sense, sizeof (xs->sense), &ppa->ppa_sense.stat, &ppa->ppa_sense.count); xs->error = XS_SENSE; goto error; } switch (timeout) { case 0: break; case PPA_EPPCMD_TIMEOUT: default: xs->error = XS_TIMEOUT; goto error; } if (xs->datalen && (xs->flags & SCSI_DATA_IN)) bcopy (ppa->ppa_buffer, xs->data, xs->datalen); done: xs->resid = 0; xs->error = XS_NOERROR; error: xs->flags |= ITSDONE; scsi_done (xs); return; } static int32_t ppa_scsi_cmd (struct scsi_xfer * xs) { int s; if (xs->sc_link->lun > 0) { xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; } if (xs->flags & SCSI_DATA_UIO) { printf ("UIO not supported by ppa_driver !\n"); xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; } #ifdef DEBUG_PPA3 { int i; log (LOG_DEBUG, "ppa_scsi_cmd(): xs->flags = 0x%x, "\ "xs->data = 0x%x, xs->datalen = %d\n", xs->flags, xs->data, xs->datalen); for (i=0; icmdlen; i++) log (LOG_DEBUG, "%2x", ((u_char *) xs->cmd)[i]); log (LOG_DEBUG, "\n"); } #endif if (xs->flags & SCSI_NOMASK) { ppaintr (ppadata[xs->sc_link->adapter_unit], xs); return COMPLETE; } s = PPA_SPL(); ppaintr (ppadata[xs->sc_link->adapter_unit], xs); splx (s); return SUCCESSFULLY_QUEUED; } #define ppaio_d_pulse(ppa,b) { \ w_dtr(ppa, b); \ w_ctr(ppa, 0xc); \ w_ctr(ppa, 0xe); \ w_ctr(ppa, 0xc); \ w_ctr(ppa, 0x4); \ w_ctr(ppa, 0xc); \ } #define ppaio_disconnect(ppa) { \ ppaio_d_pulse(ppa, 0); \ ppaio_d_pulse(ppa, 0x3c); \ ppaio_d_pulse(ppa, 0x20); \ ppaio_d_pulse(ppa, 0xf); \ } #define ppaio_c_pulse(ppa,b) { \ w_dtr(ppa, b); \ w_ctr(ppa, 0x4); \ w_ctr(ppa, 0x6); \ w_ctr(ppa, 0x4); \ w_ctr(ppa, 0xc); \ } #define ppaio_connect(ppa,how) { \ ppaio_c_pulse (ppa, 0); \ ppaio_c_pulse (ppa, 0x3c); \ ppaio_c_pulse (ppa, 0x20); \ if ((how == CONNECT_EPP_MAYBE) && IN_EPP_MODE(ppa)) { \ ppaio_c_pulse (ppa, 0xcf); \ } else { \ ppaio_c_pulse (ppa, 0x8f); \ } \ } static void ecp_sync (struct ppa_data * ppa) { int i, r; r = r_ecr (ppa); if ((r & 0xe0) != 0x80) return; for (i=0; i<100; i++) { r = r_ecr (ppa); if (r & 0x1) return; DELAY (100); } printf ("ppa%d: ECP sync failed as data still " \ "present in FIFO.\n", ppa->ppa_unit); return; } /* * Start of Chipset kludges */ #ifdef PPA_PC87332 static inline int pc87332_port(struct ppa_data * ppa) { /* A routine to detect and kludge pc87332 chipsets into the * "optimum" mode for parallel port data transfer. * This assumes EPP is better than ECP... * (Which it is for disk drives but not printers and scanners) */ /* This is where an pc87332 can hide */ unsigned short index_addr[4] = { 0x0398, 0x026e, 0x015c, 0x002e }; /* Bits 0&1 of FAR (Function Address Register) which specify where * the LPT port will show up at. */ unsigned short port_ref[4] = { 0x378, 0x3bc, 0x278, 0xffff }; unsigned char a; int loop; for (loop = 0; loop < 4; loop++) { /* Clear the "wax" out of the pc87332, only needed after hard * reset. */ inb(index_addr[loop]); inb(index_addr[loop]); inb(index_addr[loop]); inb(index_addr[loop]); /* Anyone home ?? */ outb(index_addr[loop], 0xff); a = inb(index_addr[loop]); switch (a) { case (0x0f): /* PC87732 */ printf("ppa%d: NatSemi PC8733x ", ppa->ppa_unit); break; case (0x1f): /* PC87306 */ printf("ppa%d: NatSemi PC8730x ", ppa->ppa_unit); break; default: continue; } /* Is this pc87332 on the desired port */ outb(index_addr[loop], 0x01); a = inb(index_addr[loop] + 1); if (port_ref[a & 0x03] != ppa->ppa_base) { printf ("on port 0x%x, ignored.\n", port_ref[a & 0x03]); continue; } /* Found a pc87332 */ /* Try to enable EPP modes * with hardware data direction */ if (ppa->ppa_base != 0x3bc) { /* EPP 1.9 */ outb(index_addr[loop], 0x04); a = inb(index_addr[loop] + 1); a = (a & 0xfb) | 0x03; outb(index_addr[loop] + 1, a); outb(index_addr[loop] + 1, a); /* Hardware data direction selection */ outb(index_addr[loop], 0x02); a = inb(index_addr[loop] + 1); a = (a & 0x7f); outb(index_addr[loop] + 1, a); outb(index_addr[loop] + 1, a); ppa->ppa_mode = PPA_EPP_32; printf(" in EPP mode, ppa_epp_speed = %d at 0x%x\n", ppa->ppa_epp_speed, &ppa->ppa_epp_speed); } else { /* There is not enough address space for the 0x3bc port * to have EPP registers so we will kludge it into an * ECP * port to allow bi-directional byte mode... */ /* ECP */ outb(index_addr[loop], 0x4); a = inb(index_addr[loop] + 1); a = (a & 0xfb) | 0x06; outb(index_addr[loop] + 1, a); outb(index_addr[loop] + 1, a); ppa->ppa_mode = PPA_PS2; printf(" in PS2 mode\n"); } outb(index_addr[loop], 0x4); a = inb(index_addr[loop] + 1); return ppa->ppa_mode; } return 0; } #endif static inline int generic_port(struct ppa_data * ppa) { /* Generic parallel port detection * This will try to discover if the port is * EPP, ECP, PS/2 or NIBBLE (In that order, approx....) */ char save_control, r; /* First reset the EPP timeout bit */ r = r_str(ppa); w_str(ppa, r); w_str(ppa, r & 0xfe); r = r_str(ppa); if (!(r & 0x01)) { /* If that EPP timeout bit is not reset, DON'T use EPP */ ppa->ppa_mode = PPA_EPP_32; printf("ppa%d: Generic Chipset in EPP mode, " \ "ppa_epp_speed = %d at 0x%x\n", ppa->ppa_unit, ppa->ppa_epp_speed, &ppa->ppa_epp_speed); return ppa->ppa_mode; } /* Now check for ECP */ w_ecr(ppa, 0x20); r = r_ecr(ppa); if ((r & 0xe0) == 0x20) { /* Search for SMC style EPP+ECP mode */ w_ecr(ppa, 0x80); /* First reset the EPP timeout bit */ r = r_str(ppa); w_str(ppa, r); w_str(ppa, r & 0xfe); r = r_str(ppa); if (!(r & 0x01)) { /* If EPP timeout bit is not reset, DON'T use EPP */ ppa->ppa_mode = PPA_EPP_32; printf("ppa%d: Generic Chipset in EPP+ECP mode, " \ "ppa_epp_speed = %d at 0x%x\n", ppa->ppa_unit, ppa->ppa_epp_speed, &ppa->ppa_epp_speed); return ppa->ppa_mode; } w_ecr(ppa, 0x20); ppa->ppa_mode = PPA_PS2; printf("ppa%d: Generic Chipset in PS2 mode\n", ppa->ppa_unit); return ppa->ppa_mode; } save_control = r_ctr(ppa); ppa->ppa_mode = PPA_PS2; w_ctr(ppa, 0xec); w_dtr(ppa, 0x55); r = r_dtr(ppa); if (r != (char) 0xff) { ppa->ppa_mode = PPA_NIBBLE; if (r != (char) 0x55) return 0; w_dtr(ppa, 0xaa); if (r_dtr(ppa) != (char) 0xaa) return 0; printf("ppa%d: Generic Chipset in NIBBLE mode\n", ppa->ppa_unit); } else printf("ppa%d: Generic Chipset in PS2 mode\n", ppa->ppa_unit); w_ctr(ppa, save_control); return ppa->ppa_mode; } static int ppaio_init (struct ppa_data * ppa) { char retval; ppaio_disconnect (ppa); ppaio_connect (ppa, CONNECT_NORMAL); w_ctr (ppa, 0x6); if ((retval = (r_str (ppa) & 0xf0)) != (char) 0xf0) { printf ("ppa%d: retval is 0x%x, should be 0xf0\n", ppa->ppa_unit, retval); return PPA_EINITFAILED; } w_ctr (ppa, 0x4); if ((retval = (r_str (ppa) & 0xf0)) != (char) 0x80) { printf ("ppa%d: retval is 0x%x, should be 0x80\n", ppa->ppa_unit, retval); return PPA_EINITFAILED; } /* * This is SCSI reset signal. */ w_dtr (ppa, 0x40); w_ctr (ppa, 0x8); DELAY (50); w_ctr (ppa, 0xc); ppaio_disconnect(ppa); return 0; } static int ppaio_detect (struct ppa_data * ppa) { int rs, retv; w_ctr(ppa, 0x0c); /* To avoid missing PS2 ports */ w_dtr(ppa, 0xaa); if (r_dtr(ppa) != (char) 0xaa) return PPA_ENOPORT; /* * Attempt to initialise the controller. */ retv = ppa->ppa_mode; #ifdef PPA_PC87332 if (!retv) retv = pc87332_port(ppa); #endif if (!retv) generic_port(ppa); /* * PS/2 mode forced with ECP. */ if (ppa->ppa_mode == PPA_PS2_ECP) { w_ecr(ppa, 0x20); ppa->ppa_mode = PPA_PS2; } if ((rs = ppaio_init(ppa))) return rs; return 0; } static inline char ppaio_select (struct ppa_data * ppa, int initiator, int target) { register char r; register int k; r = r_str(ppa); /* TODO */ w_dtr(ppa, (1 << target)); w_ctr(ppa, 0xe); w_ctr(ppa, 0xc); w_dtr(ppa, (1 << initiator)); w_ctr(ppa, 0x8); k = 0; while (!(r = (r_str(ppa) & 0xf0)) && (k++ < PPA_SELTMO)) barrier(); if (k >= PPA_SELTMO) return 0; return r; } static inline char ppaio_wait (struct ppa_data * ppa) { register int k; register char r; k = 0; while (!((r = r_str(ppa)) & 0x80) && (k++ < PPA_SPINTMO)) barrier (); /* * Return some status information. * Semantics : 0xc0 = ZIP wants more data * 0xd0 = ZIP wants to send more data * 0xe0 = ??? * 0xf0 = end of transfer, ZIP is sending status */ if (k < PPA_SPINTMO) return (r & 0xf0); return 0; /* command timed out */ } static inline int ppa_check_epp_status (struct ppa_data * ppa) { register char r; r = r_str (ppa); if (r & 1) { /* EPP timeout, according to the PC87332 manual */ /* Semantics of clearing EPP timeout bit. * PC87332 - reading SPP_STR does it... * SMC - write 1 to EPP timeout bit * Others - (???) write 0 to EPP timeout bit */ w_str (ppa, r); w_str (ppa, r & 0xfe); return PPA_EPPDATA_TIMEOUT; } if (!(r & 0x80)) return PPA_EPPSTATUS_ERROR; return 0; } static inline int ppa_force_epp_byte (struct ppa_data * ppa, char byte) { char r; w_epp (ppa, byte); r = r_str (ppa); if (!(r & 1)) return 0; if (ppa->ppa_epp_speed) { /* EPP timeout, according to the PC87332 manual */ /* Semantics of clearing EPP timeout bit. * PC87332 - reading SPP_STR does it... * SMC - write 1 to EPP timeout bit * Others - (???) write 0 to EPP timeout bit */ w_str (ppa, r); w_str (ppa, r & 0xfe); DELAY (ppa->ppa_epp_speed); w_epp (ppa, byte); r = r_str (ppa); } if (r & 1) { w_str (ppa, r); w_str (ppa, r & 0xfe); return 1; } return 0; } static inline int ppaio_outstr (struct ppa_data * ppa, char * buffer) { register int k; #if PPA_ECHECKING > 0 int r; #endif switch (ppa->ppa_mode) { case PPA_NIBBLE: case PPA_PS2: for (k=0;k 0 case PPA_EPP_32: #if PPA_ECHECKING < 2 w_ctr (ppa,0x4); for (k=0; kppa_mode); return 1; } panic ("ppaio_outstr(): code never executed !"); } static inline int ppaio_instr (struct ppa_data * ppa, char * buffer) { register int k; register char h, l; #if PPA_ECHECKING > 0 int r; #endif switch (ppa->ppa_mode) { case PPA_NIBBLE: for (k=0;k> 4) & 0x0f) + (h & 0xf0); } w_ctr(ppa,0xc); return 0; case PPA_PS2: for (k=0;k 0 case PPA_EPP_32: #if PPA_ECHECKING < 2 w_ctr (ppa, 0x24); for (k=0; kppa_mode); return 1; } panic ("ppaio_instr(): code never executed !"); } static inline int ppaio_outbyte (struct ppa_data * ppa, char byte) { register int k; switch (ppa->ppa_mode) { case PPA_NIBBLE: case PPA_PS2: w_dtr(ppa,byte); w_ctr(ppa,0xe); w_ctr(ppa,0xc); return 0; case PPA_EPP_8: case PPA_EPP_16: case PPA_EPP_32: w_ctr(ppa,0x4); w_epp(ppa,byte); k = ppa_check_epp_status (ppa); w_ctr(ppa,0xc); ecp_sync (ppa); return k; default: printf ("ppaio_outbyte(): " \ "unknown transfer mode (%d)!\n", ppa->ppa_mode); return 1; } panic ("ppaio_outbyte(): code never executed !"); } static inline int ppaio_inbyte (struct ppa_data * ppa, char * buffer) { register int k; register char h, l; switch (ppa->ppa_mode) { case PPA_NIBBLE: w_ctr(ppa,0x4); h = r_str(ppa); w_ctr(ppa,0x6); l = r_str(ppa); *buffer = ((l >> 4) & 0x0f) + (h & 0xf0); w_ctr(ppa,0xc); return 0; case PPA_PS2: w_ctr(ppa,0x25); *buffer = r_dtr(ppa); w_ctr(ppa,0x27); w_ctr(ppa,0x5); w_ctr(ppa,0x4); w_ctr(ppa,0xc); return 0; case PPA_EPP_8: case PPA_EPP_16: case PPA_EPP_32: w_ctr(ppa,0x4); *buffer = r_epp(ppa); k = ppa_check_epp_status (ppa); w_ctr(ppa,0xc); ecp_sync (ppa); return k; default: printf ("ppaio_inbyte(): " \ "unknown transfer mode (%d)!\n", ppa->ppa_mode); return 1; } panic ("ppaio_inbyte(): code never executed !"); } static inline int ppaio_do_scsi (struct ppa_data * ppa, int host, int target, char * command, int clen, char * buffer, int blen, int * result, int * count) { register char r; char l, h; int dir, bulk, fast; int error = 0; register int k, cnt; ppaio_connect(ppa, CONNECT_EPP_MAYBE); r = ppaio_select(ppa,host,target); if (r == 0) { error = PPA_ESELECT_TIMEOUT; goto error; } /* * Send the command ... */ if (IN_EPP_MODE (ppa)) { w_ctr(ppa,0x4); for (k=0;kppa_port_delay = PPA_SPEED_HIGH; while (r != (char) 0xf0) { if ((r & 0xc0) != 0xc0) { error = PPA_EDATA_STATUS; goto error; } if (cnt >= blen) { error = PPA_EDATA_OVERFLOW; goto error; } fast = (bulk && ((blen - cnt) >= PPA_SECTOR_SIZE) && (((int) (buffer + cnt)) & 0x3) == 0); if (fast) { if (dir) error = ppaio_outstr (ppa, &buffer[cnt]); else error = ppaio_instr (ppa, &buffer[cnt]); cnt += PPA_SECTOR_SIZE; } else { if (dir) error = ppaio_outbyte (ppa, buffer[cnt]); else error = ppaio_inbyte (ppa, &buffer[cnt]); cnt ++; } if (error) goto error; if (!(r = ppaio_wait(ppa))) { error = PPA_ESTATUS_TIMEOUT; goto error; } } ppa->ppa_port_delay = PPA_SPEED_LOW; *count = cnt; if (ppaio_inbyte (ppa, &l)) { error = PPA_EOTHER; goto error; } if (ppaio_wait (ppa) == 0) { error = PPA_EOTHER+1; goto error; } if (ppaio_inbyte (ppa, &h)) { error = PPA_EOTHER+2; goto error; } ppaio_disconnect(ppa); *result = ((int) h << 8) | ((int) l & STATUS_MASK); return 0; error: ppa->ppa_port_delay = PPA_SPEED_LOW; ppaio_disconnect (ppa); return error; } #endif