summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppbus/ppi.c
diff options
context:
space:
mode:
authornsouch <nsouch@FreeBSD.org>1999-01-10 12:04:56 +0000
committernsouch <nsouch@FreeBSD.org>1999-01-10 12:04:56 +0000
commit88ae26fef69887203a871fca927f456a66c2cad4 (patch)
tree9e8c963e572bd5f141fcfc50127d8185cf16e87c /sys/dev/ppbus/ppi.c
parent44bde66cb074ad8bc5cdb36460c6ef9f4628ea69 (diff)
downloadFreeBSD-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.c322
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;
OpenPOWER on IntegriCloud