File:  [DragonFly] / src / sys / dev / misc / ppi / ppi.c
Revision 1.7: download - view: text, annotated - select for diffs
Thu May 13 23:49:17 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*-
    2:  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  * $FreeBSD: src/sys/dev/ppbus/ppi.c,v 1.21.2.3 2000/08/07 18:24:43 peter Exp $
   27:  * $DragonFly: src/sys/dev/misc/ppi/ppi.c,v 1.7 2004/05/13 23:49:17 dillon Exp $
   28:  *
   29:  */
   30: #include "opt_ppb_1284.h"
   31: 
   32: #include <sys/param.h>
   33: #include <sys/systm.h>
   34: #include <sys/module.h>
   35: #include <sys/bus.h>
   36: #include <sys/conf.h>
   37: #include <sys/kernel.h>
   38: #include <sys/uio.h>
   39: #include <sys/fcntl.h>
   40: 
   41: #include <machine/clock.h>
   42: #include <machine/bus.h>
   43: #include <machine/resource.h>
   44: #include <sys/rman.h>
   45: 
   46: #include <bus/ppbus/ppbconf.h>
   47: #include <bus/ppbus/ppb_msq.h>
   48: 
   49: #ifdef PERIPH_1284
   50: #include <bus/ppbus/ppb_1284.h>
   51: #endif
   52: 
   53: #include "ppi.h"
   54: 
   55: #include "ppbus_if.h"
   56: 
   57: #include <bus/ppbus/ppbio.h>
   58: 
   59: #define BUFSIZE		512
   60: 
   61: struct ppi_data {
   62: 
   63:     int		ppi_unit;
   64:     int		ppi_flags;
   65: #define HAVE_PPBUS	(1<<0)
   66: #define HAD_PPBUS	(1<<1)
   67: 
   68:     int		ppi_count;
   69:     int		ppi_mode;			/* IEEE1284 mode */
   70:     char	ppi_buffer[BUFSIZE];
   71: 
   72: #ifdef PERIPH_1284
   73:     struct resource *intr_resource;	/* interrupt resource */
   74:     void *intr_cookie;			/* interrupt registration cookie */
   75: #endif /* PERIPH_1284 */
   76: };
   77: 
   78: #define DEVTOSOFTC(dev) \
   79: 	((struct ppi_data *)device_get_softc(dev))
   80: #define UNITOSOFTC(unit) \
   81: 	((struct ppi_data *)devclass_get_softc(ppi_devclass, (unit)))
   82: #define UNITODEVICE(unit) \
   83: 	(devclass_get_device(ppi_devclass, (unit)))
   84: 
   85: static devclass_t ppi_devclass;
   86: 
   87: static	d_open_t	ppiopen;
   88: static	d_close_t	ppiclose;
   89: static	d_ioctl_t	ppiioctl;
   90: static	d_write_t	ppiwrite;
   91: static	d_read_t	ppiread;
   92: 
   93: #define CDEV_MAJOR 82
   94: static struct cdevsw ppi_cdevsw = {
   95: 	/* name */	"ppi",
   96: 	/* maj */	CDEV_MAJOR,
   97: 	/* flags */	0,
   98: 	/* port */	NULL,
   99: 	/* clone */	NULL,
  100: 
  101: 	/* open */	ppiopen,
  102: 	/* close */	ppiclose,
  103: 	/* read */	ppiread,
  104: 	/* write */	ppiwrite,
  105: 	/* ioctl */	ppiioctl,
  106: 	/* poll */	nopoll,
  107: 	/* mmap */	nommap,
  108: 	/* strategy */	nostrategy,
  109: 	/* dump */	nodump,
  110: 	/* psize */	nopsize
  111: };
  112: 
  113: #ifdef PERIPH_1284
  114: 
  115: static void
  116: ppi_enable_intr(device_t ppidev)
  117: {
  118: 	char r;
  119: 	device_t ppbus = device_get_parent(ppidev);
  120: 
  121: 	r = ppb_rctr(ppbus);
  122: 	ppb_wctr(ppbus, r | IRQENABLE);
  123: 
  124: 	return;
  125: }
  126: 
  127: static void
  128: ppi_disable_intr(device_t ppidev)
  129: {
  130: 	char r;
  131:         device_t ppbus = device_get_parent(ppidev);
  132: 
  133: 	r = ppb_rctr(ppbus);
  134: 	ppb_wctr(ppbus, r & ~IRQENABLE);
  135: 
  136: 	return;
  137: }
  138: 
  139: #endif /* PERIPH_1284 */
  140: 
  141: static void
  142: ppi_identify(driver_t *driver, device_t parent)
  143: {
  144: 
  145: 	BUS_ADD_CHILD(parent, 0, "ppi", 0);
  146: }
  147: 
  148: /*
  149:  * ppi_probe()
  150:  */
  151: static int
  152: ppi_probe(device_t dev)
  153: {
  154: 	struct ppi_data *ppi;
  155: 
  156: 	/* probe is always ok */
  157: 	device_set_desc(dev, "Parallel I/O");
  158: 
  159: 	ppi = DEVTOSOFTC(dev);
  160: 	bzero(ppi, sizeof(struct ppi_data));
  161: 
  162: 	return (0);
  163: }
  164: 
  165: /*
  166:  * ppi_attach()
  167:  */
  168: static int
  169: ppi_attach(device_t dev)
  170: {
  171: #ifdef PERIPH_1284
  172: 	uintptr_t irq;
  173: 	int zero = 0;
  174: 	struct ppi_data *ppi = DEVTOSOFTC(dev);
  175: 
  176: 	/* retrive the irq */
  177: 	BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq);
  178: 
  179: 	/* declare our interrupt handler */
  180: 	ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ,
  181: 						&zero, irq, irq, 1, RF_ACTIVE);
  182: #endif /* PERIPH_1284 */
  183: 
  184: 	make_dev(&ppi_cdevsw, device_get_unit(dev),	/* XXX cleanup */
  185: 		 UID_ROOT, GID_WHEEL,
  186: 		 0600, "ppi%d", device_get_unit(dev));
  187: 
  188: 	return (0);
  189: }
  190: 
  191: #ifdef PERIPH_1284
  192: /*
  193:  * Cable
  194:  * -----
  195:  *
  196:  * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
  197:  *
  198:  * nStrobe   <-> nAck		1  <-> 10
  199:  * nAutofd   <-> Busy		11 <-> 14
  200:  * nSelectin <-> Select		17 <-> 13
  201:  * nInit     <-> nFault		15 <-> 16
  202:  *
  203:  */
  204: static void
  205: ppiintr(void *arg)
  206: {
  207: 	device_t ppidev = (device_t)arg;
  208:         device_t ppbus = device_get_parent(ppidev);
  209: 	struct ppi_data *ppi = DEVTOSOFTC(ppidev);
  210: 
  211: 	ppi_disable_intr(ppidev);
  212: 
  213: 	switch (ppb_1284_get_state(ppbus)) {
  214: 
  215: 	/* accept IEEE1284 negociation then wakeup an waiting process to
  216: 	 * continue negociation at process level */
  217: 	case PPB_FORWARD_IDLE:
  218: 		/* Event 1 */
  219: 		if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
  220: 							(SELECT | nBUSY)) {
  221: 			/* IEEE1284 negociation */
  222: #ifdef DEBUG_1284
  223: 			printf("N");
  224: #endif
  225: 
  226: 			/* Event 2 - prepare for reading the ext. value */
  227: 			ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
  228: 
  229: 			ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
  230: 
  231: 		} else {
  232: #ifdef DEBUG_1284
  233: 			printf("0x%x", ppb_rstr(ppbus));
  234: #endif
  235: 			ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
  236: 			break;
  237: 		}
  238: 
  239: 		/* wake up any process waiting for negociation from
  240: 		 * remote master host */
  241: 
  242: 		/* XXX should set a variable to warn the process about
  243: 		 * the interrupt */
  244: 
  245: 		wakeup(ppi);
  246: 		break;
  247: 	default:
  248: #ifdef DEBUG_1284
  249: 		printf("?%d", ppb_1284_get_state(ppbus));
  250: #endif
  251: 		ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
  252: 		ppb_set_mode(ppbus, PPB_COMPATIBLE);
  253: 		break;
  254: 	}
  255: 
  256: 	ppi_enable_intr(ppidev);
  257: 
  258: 	return;
  259: }
  260: #endif /* PERIPH_1284 */
  261: 
  262: static int
  263: ppiopen(dev_t dev, int flags, int fmt, d_thread_t *td)
  264: {
  265: 	u_int unit = minor(dev);
  266: 	struct ppi_data *ppi = UNITOSOFTC(unit);
  267: 	device_t ppidev = UNITODEVICE(unit);
  268:         device_t ppbus = device_get_parent(ppidev);
  269: 	int res;
  270: 
  271: 	if (!ppi)
  272: 		return (ENXIO);
  273: 
  274: 	if (!(ppi->ppi_flags & HAVE_PPBUS)) {
  275: 		if ((res = ppb_request_bus(ppbus, ppidev,
  276: 			(flags & O_NONBLOCK) ? PPB_DONTWAIT :
  277: 						(PPB_WAIT | PPB_INTR))))
  278: 			return (res);
  279: 
  280: 		ppi->ppi_flags |= HAVE_PPBUS;
  281: 
  282: #ifdef PERIPH_1284
  283: 		if (ppi->intr_resource) {
  284: 			/* register our interrupt handler */
  285: 			BUS_SETUP_INTR(device_get_parent(ppidev), ppidev, ppi->intr_resource,
  286: 				       INTR_TYPE_TTY, ppiintr, dev, &ppi->intr_cookie);
  287: 		}
  288: #endif /* PERIPH_1284 */
  289: 	}
  290: 	ppi->ppi_count += 1;
  291: 
  292: 	return (0);
  293: }
  294: 
  295: static int
  296: ppiclose(dev_t dev, int flags, int fmt, d_thread_t *td)
  297: {
  298: 	u_int unit = minor(dev);
  299: 	struct ppi_data *ppi = UNITOSOFTC(unit);
  300: 	device_t ppidev = UNITODEVICE(unit);
  301:         device_t ppbus = device_get_parent(ppidev);
  302: 
  303: 	ppi->ppi_count --;
  304: 	if (!ppi->ppi_count) {
  305: 
  306: #ifdef PERIPH_1284
  307: 		switch (ppb_1284_get_state(ppbus)) {
  308: 		case PPB_PERIPHERAL_IDLE:
  309: 			ppb_peripheral_terminate(ppbus, 0);
  310: 			break;
  311: 		case PPB_REVERSE_IDLE:
  312: 		case PPB_EPP_IDLE:
  313: 		case PPB_ECP_FORWARD_IDLE:
  314: 		default:
  315: 			ppb_1284_terminate(ppbus);
  316: 			break;
  317: 		}
  318: #endif /* PERIPH_1284 */
  319: 
  320: 		/* unregistration of interrupt forced by release */
  321: 		ppb_release_bus(ppbus, ppidev);
  322: 
  323: 		ppi->ppi_flags &= ~HAVE_PPBUS;
  324: 	}
  325: 
  326: 	return (0);
  327: }
  328: 
  329: /*
  330:  * ppiread()
  331:  *
  332:  * IEEE1284 compliant read.
  333:  *
  334:  * First, try negociation to BYTE then NIBBLE mode
  335:  * If no data is available, wait for it otherwise transfer as much as possible
  336:  */
  337: static int
  338: ppiread(dev_t dev, struct uio *uio, int ioflag)
  339: {
  340: #ifdef PERIPH_1284
  341: 	u_int unit = minor(dev);
  342: 	struct ppi_data *ppi = UNITOSOFTC(unit);
  343: 	device_t ppidev = UNITODEVICE(unit);
  344:         device_t ppbus = device_get_parent(ppidev);
  345: 	int len, error = 0;
  346: 
  347: 	switch (ppb_1284_get_state(ppbus)) {
  348: 	case PPB_PERIPHERAL_IDLE:
  349: 		ppb_peripheral_terminate(ppbus, 0);
  350: 		/* fall throught */
  351: 
  352: 	case PPB_FORWARD_IDLE:
  353: 		/* if can't negociate NIBBLE mode then try BYTE mode,
  354: 		 * the peripheral may be a computer
  355: 		 */
  356: 		if ((ppb_1284_negociate(ppbus,
  357: 			ppi->ppi_mode = PPB_NIBBLE, 0))) {
  358: 
  359: 			/* XXX Wait 2 seconds to let the remote host some
  360: 			 * time to terminate its interrupt
  361: 			 */
  362: 			tsleep(ppi, 0, "ppiread", 2*hz);
  363: 			
  364: 			if ((error = ppb_1284_negociate(ppbus,
  365: 				ppi->ppi_mode = PPB_BYTE, 0)))
  366: 				return (error);
  367: 		}
  368: 		break;
  369: 
  370: 	case PPB_REVERSE_IDLE:
  371: 	case PPB_EPP_IDLE:
  372: 	case PPB_ECP_FORWARD_IDLE:
  373: 	default:
  374: 		break;
  375: 	}
  376: 
  377: #ifdef DEBUG_1284
  378: 	printf("N");
  379: #endif
  380: 	/* read data */
  381: 	len = 0;
  382: 	while (uio->uio_resid) {
  383: 		if ((error = ppb_1284_read(ppbus, ppi->ppi_mode,
  384: 			ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
  385: 			&len))) {
  386: 			goto error;
  387: 		}
  388: 
  389: 		if (!len)
  390: 			goto error;		/* no more data */
  391: 
  392: #ifdef DEBUG_1284
  393: 		printf("d");
  394: #endif
  395: 		if ((error = uiomove(ppi->ppi_buffer, len, uio)))
  396: 			goto error;
  397: 	}
  398: 
  399: error:
  400: 
  401: #else /* PERIPH_1284 */
  402: 	int error = ENODEV;
  403: #endif
  404: 
  405: 	return (error);
  406: }
  407: 
  408: /*
  409:  * ppiwrite()
  410:  *
  411:  * IEEE1284 compliant write
  412:  *
  413:  * Actually, this is the peripheral side of a remote IEEE1284 read
  414:  *
  415:  * The first part of the negociation (IEEE1284 device detection) is
  416:  * done at interrupt level, then the remaining is done by the writing
  417:  * process
  418:  *
  419:  * Once negociation done, transfer data
  420:  */
  421: static int
  422: ppiwrite(dev_t dev, struct uio *uio, int ioflag)
  423: {
  424: #ifdef PERIPH_1284
  425: 	u_int unit = minor(dev);
  426: 	struct ppi_data *ppi = UNITOSOFTC(unit);
  427: 	device_t ppidev = UNITODEVICE(unit);
  428:         device_t ppbus = device_get_parent(ppidev);
  429: 	int len, error = 0, sent;
  430: 
  431: #if 0
  432: 	int ret;
  433: 
  434: 	#define ADDRESS		MS_PARAM(0, 0, MS_TYP_PTR)
  435: 	#define LENGTH		MS_PARAM(0, 1, MS_TYP_INT)
  436: 
  437: 	struct ppb_microseq msq[] = {
  438: 		  { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
  439: 		  MS_RET(0)
  440: 	};
  441: 
  442: 	/* negociate ECP mode */
  443: 	if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
  444: 		printf("ppiwrite: ECP negociation failed\n");
  445: 	}
  446: 
  447: 	while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
  448: 		uiomove(ppi->ppi_buffer, len, uio);
  449: 
  450: 		ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
  451: 
  452: 		error = ppb_MS_microseq(ppbus, msq, &ret);
  453: 	}
  454: #endif
  455: 
  456: 	/* we have to be peripheral to be able to send data, so
  457: 	 * wait for the appropriate state
  458: 	 */
  459:  	if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
  460: 		ppb_1284_terminate(ppbus);
  461: 
  462:  	while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
  463: 		/* XXX should check a variable before sleeping */
  464: #ifdef DEBUG_1284
  465: 		printf("s");
  466: #endif
  467: 
  468: 		ppi_enable_intr(ppidev);
  469: 
  470: 		/* sleep until IEEE1284 negociation starts */
  471: 		error = tsleep(ppi, PCATCH, "ppiwrite", 0);
  472: 
  473: 		switch (error) {
  474: 		case 0:
  475: 			/* negociate peripheral side with BYTE mode */
  476: 			ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
  477: 			break;
  478: 		case EWOULDBLOCK:
  479: 			break;
  480: 		default:
  481: 			goto error;
  482: 		}
  483: 	}
  484: #ifdef DEBUG_1284
  485: 	printf("N");
  486: #endif
  487: 
  488: 	/* negociation done, write bytes to master host */
  489: 	while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
  490: 		uiomove(ppi->ppi_buffer, len, uio);
  491: 		if ((error = byte_peripheral_write(ppbus,
  492: 						ppi->ppi_buffer, len, &sent)))
  493: 			goto error;
  494: #ifdef DEBUG_1284
  495: 		printf("d");
  496: #endif
  497: 	}
  498: 
  499: error:
  500: 
  501: #else /* PERIPH_1284 */
  502: 	int error = ENODEV;
  503: #endif
  504: 
  505: 	return (error);
  506: }
  507: 
  508: static int
  509: ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, d_thread_t *td)
  510: {
  511: 	u_int unit = minor(dev);
  512: 	device_t ppidev = UNITODEVICE(unit);
  513:         device_t ppbus = device_get_parent(ppidev);
  514: 	int error = 0;
  515: 	u_int8_t *val = (u_int8_t *)data;
  516: 
  517: 	switch (cmd) {
  518: 
  519: 	case PPIGDATA:			/* get data register */
  520: 		*val = ppb_rdtr(ppbus);
  521: 		break;
  522: 	case PPIGSTATUS:		/* get status bits */
  523: 		*val = ppb_rstr(ppbus);
  524: 		break;
  525: 	case PPIGCTRL:			/* get control bits */
  526: 		*val = ppb_rctr(ppbus);
  527: 		break;
  528: 	case PPIGEPPD:			/* get EPP data bits */
  529: 		*val = ppb_repp_D(ppbus);
  530: 		break;
  531: 	case PPIGECR:			/* get ECP bits */
  532: 		*val = ppb_recr(ppbus);
  533: 		break;
  534: 	case PPIGFIFO:			/* read FIFO */
  535: 		*val = ppb_rfifo(ppbus);
  536: 		break;
  537: 	case PPISDATA:			/* set data register */
  538: 		ppb_wdtr(ppbus, *val);
  539: 		break;
  540: 	case PPISSTATUS:		/* set status bits */
  541: 		ppb_wstr(ppbus, *val);
  542: 		break;
  543: 	case PPISCTRL:			/* set control bits */
  544: 		ppb_wctr(ppbus, *val);
  545: 		break;
  546: 	case PPISEPPD:			/* set EPP data bits */
  547: 		ppb_wepp_D(ppbus, *val);
  548: 		break;
  549: 	case PPISECR:			/* set ECP bits */
  550: 		ppb_wecr(ppbus, *val);
  551: 		break;
  552: 	case PPISFIFO:			/* write FIFO */
  553: 		ppb_wfifo(ppbus, *val);
  554: 		break;
  555: 	case PPIGEPPA:			/* get EPP address bits */
  556: 		*val = ppb_repp_A(ppbus);
  557: 		break;
  558: 	case PPISEPPA:			/* set EPP address bits */
  559: 		ppb_wepp_A(ppbus, *val);
  560: 		break;
  561: 	default:
  562: 		error = ENOTTY;
  563: 		break;
  564: 	}
  565:     
  566: 	return (error);
  567: }
  568: 
  569: static device_method_t ppi_methods[] = {
  570: 	/* device interface */
  571: 	DEVMETHOD(device_identify,	ppi_identify),
  572: 	DEVMETHOD(device_probe,		ppi_probe),
  573: 	DEVMETHOD(device_attach,	ppi_attach),
  574: 
  575: 	{ 0, 0 }
  576: };
  577: 
  578: static driver_t ppi_driver = {
  579: 	"ppi",
  580: 	ppi_methods,
  581: 	sizeof(struct ppi_data),
  582: };
  583: DRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0);