diff options
author | nsouch <nsouch@FreeBSD.org> | 1999-01-10 12:04:56 +0000 |
---|---|---|
committer | nsouch <nsouch@FreeBSD.org> | 1999-01-10 12:04:56 +0000 |
commit | 88ae26fef69887203a871fca927f456a66c2cad4 (patch) | |
tree | 9e8c963e572bd5f141fcfc50127d8185cf16e87c /sys/dev/ppbus/ppi.c | |
parent | 44bde66cb074ad8bc5cdb36460c6ef9f4628ea69 (diff) | |
download | FreeBSD-src-88ae26fef69887203a871fca927f456a66c2cad4.zip FreeBSD-src-88ae26fef69887203a871fca927f456a66c2cad4.tar.gz |
Major ppbus commit with:
+ ECP parallel port chipset FIFO detection
+ DMA+FIFO parallel I/O handled as chipset specific
+ nlpt updated in order to use the above enhanced parallel I/O.
Use 'lptcontrol -e' to use enhanced I/O
+ Various options documented in LINT
+ Full IEEE1284 NIBBLE and BYTE modes support. See ppbus(4) for
an overview of the IEEE1284 standard
+ Detection of PnP parallel devices at boot
+ Read capability added to nlpt driver to get IEEE1284 compliant
printer status with a simple 'cat /dev/lpt0'
+ IEEE1284 peripheral emulation added to BYTE mode. Two computers
may dialog according to IEEE1284 signaling method.
See PERIPH_1284 option and /sys/dev/ppbus/ppi.c
All this code is supposed to provide basic functions for IEEE1284 programming.
ppi.c and nlpt.c may act as examples.
Diffstat (limited to 'sys/dev/ppbus/ppi.c')
-rw-r--r-- | sys/dev/ppbus/ppi.c | 322 |
1 files changed, 314 insertions, 8 deletions
diff --git a/sys/dev/ppbus/ppi.c b/sys/dev/ppbus/ppi.c index 3103ee3..e0072f3 100644 --- a/sys/dev/ppbus/ppi.c +++ b/sys/dev/ppbus/ppi.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ppi.c,v 1.7 1998/06/07 17:09:49 dfr Exp $ + * $Id: ppi.c,v 1.8 1998/12/07 21:58:16 archie Exp $ * */ #include "ppi.h" @@ -34,18 +34,35 @@ #include <sys/systm.h> #include <sys/conf.h> #include <sys/kernel.h> +#include <sys/uio.h> #include <sys/malloc.h> #include <sys/fcntl.h> +#include <machine/clock.h> + #include <dev/ppbus/ppbconf.h> +#include <dev/ppbus/ppb_msq.h> + +#include "opt_ppb_1284.h" + +#ifdef PERIPH_1284 +#include <dev/ppbus/ppb_1284.h> +#endif + #include <dev/ppbus/ppi.h> +#define BUFSIZE 512 struct ppi_data { int ppi_unit; int ppi_flags; #define HAVE_PPBUS (1<<0) +#define HAD_PPBUS (1<<1) + + int ppi_count; + int ppi_mode; /* IEEE1284 mode */ + char ppi_buffer[BUFSIZE]; struct ppb_device ppi_dev; }; @@ -70,13 +87,41 @@ DATA_SET(ppbdriver_set, ppidriver); static d_open_t ppiopen; static d_close_t ppiclose; static d_ioctl_t ppiioctl; +static d_write_t ppiwrite; +static d_read_t ppiread; #define CDEV_MAJOR 82 static struct cdevsw ppi_cdevsw = - { ppiopen, ppiclose, noread, nowrite, /* 82 */ + { ppiopen, ppiclose, ppiread, ppiwrite, /* 82 */ ppiioctl, nullstop, nullreset, nodevtotty, seltrue, nommap, nostrat, "ppi", NULL, -1 }; +#ifdef PERIPH_1284 + +static void +ppi_enable_intr(struct ppi_data *ppi) +{ + char r; + + r = ppb_rctr(&ppi->ppi_dev); + ppb_wctr(&ppi->ppi_dev, r | IRQENABLE); + + return; +} + +static void +ppi_disable_intr(struct ppi_data *ppi) +{ + char r; + + r = ppb_rctr(&ppi->ppi_dev); + ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE); + + return; +} + +#endif /* PERIPH_1284 */ + /* * ppiprobe() */ @@ -125,9 +170,72 @@ ppiattach(struct ppb_device *dev) return (1); } +/* + * Cable + * ----- + * + * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks: + * + * nStrobe <-> nAck 1 <-> 10 + * nAutofd <-> Busy 11 <-> 14 + * nSelectin <-> Select 17 <-> 13 + * nInit <-> nFault 15 <-> 16 + * + */ static void ppiintr(int unit) { +#ifdef PERIPH_1284 + struct ppi_data *ppi = ppidata[unit]; + + ppi_disable_intr(ppi); + + switch (ppi->ppi_dev.ppb->state) { + + /* accept IEEE1284 negociation then wakeup an waiting process to + * continue negociation at process level */ + case PPB_FORWARD_IDLE: + /* Event 1 */ + if ((ppb_rstr(&ppi->ppi_dev) & (SELECT | nBUSY)) == + (SELECT | nBUSY)) { + /* IEEE1284 negociation */ +#ifdef DEBUG_1284 + printf("N"); +#endif + + /* Event 2 - prepare for reading the ext. value */ + ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN); + + ppi->ppi_dev.ppb->state = PPB_NEGOCIATION; + + } else { +#ifdef DEBUG_1284 + printf("0x%x", ppb_rstr(&ppi->ppi_dev)); +#endif + ppb_peripheral_terminate(&ppi->ppi_dev, PPB_DONTWAIT); + break; + } + + /* wake up any process waiting for negociation from + * remote master host */ + + /* XXX should set a variable to warn the process about + * the interrupt */ + + wakeup(ppi); + break; + default: +#ifdef DEBUG_1284 + printf("?%d", ppi->ppi_dev.ppb->state); +#endif + ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE; + ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE); + break; + } + + ppi_enable_intr(ppi); +#endif /* PERIPH_1284 */ + return; } @@ -141,11 +249,16 @@ ppiopen(dev_t dev, int flags, int fmt, struct proc *p) if (unit >= nppi) return (ENXIO); - if (!(ppi->ppi_flags & HAVE_PPBUS)) - if ((res = ppb_request_bus(&ppi->ppi_dev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR)))) + if (!(ppi->ppi_flags & HAVE_PPBUS)) { + if ((res = ppb_request_bus(&ppi->ppi_dev, + (flags & O_NONBLOCK) ? PPB_DONTWAIT : + (PPB_WAIT | PPB_INTR)))) return (res); - ppi->ppi_flags |= HAVE_PPBUS; + ppi->ppi_flags |= HAVE_PPBUS; + } + ppi->ppi_count += 1; + return (0); } @@ -155,12 +268,206 @@ ppiclose(dev_t dev, int flags, int fmt, struct proc *p) u_int unit = minor(dev); struct ppi_data *ppi = ppidata[unit]; - if (ppi->ppi_flags & HAVE_PPBUS) + ppi->ppi_count --; + if (!ppi->ppi_count) { + +#ifdef PERIPH_1284 + switch (ppi->ppi_dev.ppb->state) { + case PPB_PERIPHERAL_IDLE: + ppb_peripheral_terminate(&ppi->ppi_dev, 0); + break; + case PPB_REVERSE_IDLE: + case PPB_EPP_IDLE: + case PPB_ECP_FORWARD_IDLE: + default: + ppb_1284_terminate(&ppi->ppi_dev); + break; + } +#endif /* PERIPH_1284 */ + ppb_release_bus(&ppi->ppi_dev); - ppi->ppi_flags &= ~HAVE_PPBUS; + ppi->ppi_flags &= ~HAVE_PPBUS; + } + return (0); } +/* + * ppiread() + * + * IEEE1284 compliant read. + * + * First, try negociation to BYTE then NIBBLE mode + * If no data is available, wait for it otherwise transfer as much as possible + */ +static int +ppiread(dev_t dev, struct uio *uio, int ioflag) +{ +#ifdef PERIPH_1284 + u_int unit = minor(dev); + struct ppi_data *ppi = ppidata[unit]; + int len, error = 0; + + switch (ppi->ppi_dev.ppb->state) { + case PPB_PERIPHERAL_IDLE: + ppb_peripheral_terminate(&ppi->ppi_dev, 0); + /* fall throught */ + + case PPB_FORWARD_IDLE: + /* if can't negociate NIBBLE mode then try BYTE mode, + * the peripheral may be a computer + */ + if ((ppb_1284_negociate(&ppi->ppi_dev, + ppi->ppi_mode = PPB_NIBBLE, 0))) { + + /* XXX Wait 2 seconds to let the remote host some + * time to terminate its interrupt + */ + tsleep(ppi, PPBPRI, "ppiread", 2*hz); + + if ((error = ppb_1284_negociate(&ppi->ppi_dev, + ppi->ppi_mode = PPB_BYTE, 0))) + return (error); + } + break; + + case PPB_REVERSE_IDLE: + case PPB_EPP_IDLE: + case PPB_ECP_FORWARD_IDLE: + default: + break; + } + +#ifdef DEBUG_1284 + printf("N"); +#endif + /* read data */ + len = 0; + while (uio->uio_resid) { + if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode, + ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid), + &len))) { + goto error; + } + + if (!len) + goto error; /* no more data */ + +#ifdef DEBUG_1284 + printf("d"); +#endif + if ((error = uiomove(ppi->ppi_buffer, len, uio))) + goto error; + } + +error: + +#else /* PERIPH_1284 */ + int error = ENODEV; +#endif + + return (error); +} + +/* + * ppiwrite() + * + * IEEE1284 compliant write + * + * Actually, this is the peripheral side of a remote IEEE1284 read + * + * The first part of the negociation (IEEE1284 device detection) is + * done at interrupt level, then the remaining is done by the writing + * process + * + * Once negociation done, transfer data + */ +static int +ppiwrite(dev_t dev, struct uio *uio, int ioflag) +{ +#ifdef PERIPH_1284 + u_int unit = minor(dev); + struct ppi_data *ppi = ppidata[unit]; + struct ppb_data *ppb = ppi->ppi_dev.ppb; + int len, error = 0, sent; + +#if 0 + int ret; + + #define ADDRESS MS_PARAM(0, 0, MS_TYP_PTR) + #define LENGTH MS_PARAM(0, 1, MS_TYP_INT) + + struct ppb_microseq msq[] = { + { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } }, + MS_RET(0) + }; + + /* negociate ECP mode */ + if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) { + printf("ppiwrite: ECP negociation failed\n"); + } + + while (!error && (len = min(uio->uio_resid, BUFSIZE))) { + uiomove(ppi->ppi_buffer, len, uio); + + ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len); + + error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret); + } +#endif + + /* we have to be peripheral to be able to send data, so + * wait for the appropriate state + */ + if (ppb->state < PPB_PERIPHERAL_NEGOCIATION) + ppb_1284_terminate(&ppi->ppi_dev); + + while (ppb->state != PPB_PERIPHERAL_IDLE) { + /* XXX should check a variable before sleeping */ +#ifdef DEBUG_1284 + printf("s"); +#endif + + ppi_enable_intr(ppi); + + /* sleep until IEEE1284 negociation starts */ + error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0); + + switch (error) { + case 0: + /* negociate peripheral side with BYTE mode */ + ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0); + break; + case EWOULDBLOCK: + break; + default: + goto error; + } + } +#ifdef DEBUG_1284 + printf("N"); +#endif + + /* negociation done, write bytes to master host */ + while (len = min(uio->uio_resid, BUFSIZE)) { + uiomove(ppi->ppi_buffer, len, uio); + if ((error = byte_peripheral_write(&ppi->ppi_dev, + ppi->ppi_buffer, len, &sent))) + goto error; +#ifdef DEBUG_1284 + printf("d"); +#endif + } + +error: + +#else /* PERIPH_1284 */ + int error = ENODEV; +#endif + + return (error); +} + static int ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { @@ -208,7 +515,6 @@ ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) case PPISFIFO: /* write FIFO */ ppb_wfifo(&ppi->ppi_dev, *val); break; - default: error = ENOTTY; break; |