Home | History | Annotate | Line # | Download | only in ppbus
ppbus_msq.c revision 1.7.70.1
      1  1.7.70.1       mjf /* $NetBSD: ppbus_msq.c,v 1.7.70.1 2008/06/02 13:23:48 mjf Exp $ */
      2       1.3     bjh21 
      3       1.1  jdolecek /*-
      4       1.1  jdolecek  * Copyright (c) 1998, 1999 Nicolas Souchu
      5       1.1  jdolecek  * All rights reserved.
      6       1.1  jdolecek  *
      7       1.1  jdolecek  * Redistribution and use in source and binary forms, with or without
      8       1.1  jdolecek  * modification, are permitted provided that the following conditions
      9       1.1  jdolecek  * are met:
     10       1.1  jdolecek  * 1. Redistributions of source code must retain the above copyright
     11       1.1  jdolecek  *    notice, this list of conditions and the following disclaimer.
     12       1.1  jdolecek  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  jdolecek  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  jdolecek  *    documentation and/or other materials provided with the distribution.
     15       1.1  jdolecek  *
     16       1.1  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17       1.1  jdolecek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18       1.1  jdolecek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19       1.1  jdolecek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20       1.1  jdolecek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21       1.1  jdolecek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22       1.1  jdolecek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23       1.1  jdolecek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24       1.1  jdolecek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25       1.1  jdolecek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26       1.1  jdolecek  * SUCH DAMAGE.
     27       1.1  jdolecek  *
     28       1.5     bjh21  * FreeBSD: src/sys/dev/ppbus/ppb_msq.c,v 1.9.2.1 2000/05/24 00:20:57 n_hibma Exp
     29       1.1  jdolecek  *
     30       1.1  jdolecek  */
     31       1.5     bjh21 
     32       1.5     bjh21 #include <sys/cdefs.h>
     33  1.7.70.1       mjf __KERNEL_RCSID(0, "$NetBSD: ppbus_msq.c,v 1.7.70.1 2008/06/02 13:23:48 mjf Exp $");
     34       1.5     bjh21 
     35       1.1  jdolecek #include <machine/stdarg.h>
     36       1.1  jdolecek 
     37       1.1  jdolecek #include <sys/param.h>
     38       1.1  jdolecek #include <sys/systm.h>
     39       1.1  jdolecek 
     40       1.1  jdolecek #include <dev/ppbus/ppbus_conf.h>
     41       1.1  jdolecek #include <dev/ppbus/ppbus_base.h>
     42       1.1  jdolecek #include <dev/ppbus/ppbus_device.h>
     43       1.1  jdolecek #include <dev/ppbus/ppbus_msq.h>
     44       1.1  jdolecek #include <dev/ppbus/ppbus_var.h>
     45       1.1  jdolecek 
     46       1.1  jdolecek /*
     47       1.1  jdolecek #include "ppbus_if.h"
     48       1.1  jdolecek */
     49       1.1  jdolecek 
     50       1.6     perry /*
     51       1.1  jdolecek  * msq index (see PPBUS_MAX_XFER)
     52       1.1  jdolecek  * These are device modes
     53       1.1  jdolecek  */
     54       1.1  jdolecek #define COMPAT_MSQ	0x0
     55       1.1  jdolecek #define NIBBLE_MSQ	0x1
     56       1.1  jdolecek #define PS2_MSQ		0x2
     57       1.1  jdolecek #define EPP17_MSQ	0x3
     58       1.1  jdolecek #define EPP19_MSQ	0x4
     59       1.1  jdolecek #define ECP_MSQ		0x5
     60       1.1  jdolecek 
     61       1.1  jdolecek /* Function prototypes */
     62       1.6     perry static struct ppbus_xfer * mode2xfer(struct ppbus_softc *,
     63       1.1  jdolecek 	struct ppbus_device_softc *, int);
     64       1.6     perry 
     65       1.1  jdolecek /*
     66       1.1  jdolecek  * Device mode to submsq conversion
     67       1.1  jdolecek  */
     68       1.1  jdolecek static struct ppbus_xfer *
     69       1.6     perry mode2xfer(struct ppbus_softc * bus, struct ppbus_device_softc * ppbdev,
     70       1.1  jdolecek 	int opcode)
     71       1.1  jdolecek {
     72       1.1  jdolecek 	int index;
     73       1.1  jdolecek 	unsigned int epp;
     74       1.1  jdolecek 	struct ppbus_xfer * table;
     75       1.1  jdolecek 
     76       1.1  jdolecek 	switch (opcode) {
     77       1.1  jdolecek 	case MS_OP_GET:
     78       1.1  jdolecek 		table = ppbdev->get_xfer;
     79       1.1  jdolecek 		break;
     80       1.1  jdolecek 
     81       1.1  jdolecek 	case MS_OP_PUT:
     82       1.1  jdolecek 		table = ppbdev->put_xfer;
     83       1.1  jdolecek 		break;
     84       1.1  jdolecek 
     85       1.1  jdolecek 	default:
     86       1.1  jdolecek 		panic("%s: unknown opcode (%d)", __func__, opcode);
     87       1.1  jdolecek 	}
     88       1.1  jdolecek 
     89       1.1  jdolecek 	/* retrieve the device operating mode */
     90       1.1  jdolecek 	switch (bus->sc_mode) {
     91       1.1  jdolecek 	case PPBUS_COMPATIBLE:
     92       1.1  jdolecek 		index = COMPAT_MSQ;
     93       1.1  jdolecek 		break;
     94       1.1  jdolecek 	case PPBUS_NIBBLE:
     95       1.1  jdolecek 		index = NIBBLE_MSQ;
     96       1.1  jdolecek 		break;
     97       1.1  jdolecek 	case PPBUS_PS2:
     98       1.1  jdolecek 		index = PS2_MSQ;
     99       1.1  jdolecek 		break;
    100       1.1  jdolecek 	case PPBUS_EPP:
    101  1.7.70.1       mjf 		ppbus_read_ivar(bus->sc_dev, PPBUS_IVAR_EPP_PROTO, &epp);
    102       1.1  jdolecek 		switch (epp) {
    103       1.1  jdolecek 		case PPBUS_EPP_1_7:
    104       1.1  jdolecek 			index = EPP17_MSQ;
    105       1.1  jdolecek 			break;
    106       1.1  jdolecek 		case PPBUS_EPP_1_9:
    107       1.1  jdolecek 			index = EPP19_MSQ;
    108       1.1  jdolecek 			break;
    109       1.1  jdolecek 		default:
    110       1.1  jdolecek 			panic("%s: unknown EPP protocol [%u]!", __func__, epp);
    111       1.1  jdolecek 		}
    112       1.1  jdolecek 		break;
    113       1.1  jdolecek 	case PPBUS_ECP:
    114       1.1  jdolecek 		index = ECP_MSQ;
    115       1.1  jdolecek 		break;
    116       1.1  jdolecek 	default:
    117       1.1  jdolecek 		panic("%s: unknown mode (%d)", __func__, ppbdev->mode);
    118       1.1  jdolecek 	}
    119       1.1  jdolecek 
    120       1.1  jdolecek 	return (&table[index]);
    121       1.1  jdolecek }
    122       1.1  jdolecek 
    123       1.1  jdolecek /*
    124       1.1  jdolecek  * ppbus_MS_init()
    125       1.1  jdolecek  *
    126       1.1  jdolecek  * Initialize device dependent submicrosequence of the current mode
    127       1.1  jdolecek  *
    128       1.1  jdolecek  */
    129       1.1  jdolecek int
    130  1.7.70.1       mjf ppbus_MS_init(device_t dev, device_t ppbdev,
    131       1.1  jdolecek 	struct ppbus_microseq * loop, int opcode)
    132       1.1  jdolecek {
    133  1.7.70.1       mjf 	struct ppbus_softc * bus = device_private(dev);
    134       1.6     perry 	struct ppbus_xfer *xfer = mode2xfer(bus, (struct ppbus_device_softc *)
    135       1.1  jdolecek 		ppbdev, opcode);
    136       1.1  jdolecek 
    137       1.1  jdolecek 	xfer->loop = loop;
    138       1.1  jdolecek 
    139       1.1  jdolecek 	return 0;
    140       1.1  jdolecek }
    141       1.1  jdolecek 
    142       1.1  jdolecek /*
    143       1.1  jdolecek  * ppbus_MS_exec()
    144       1.1  jdolecek  *
    145       1.1  jdolecek  * Execute any microsequence opcode - expensive
    146       1.1  jdolecek  *
    147       1.1  jdolecek  */
    148       1.1  jdolecek int
    149  1.7.70.1       mjf ppbus_MS_exec(device_t ppb, device_t dev,
    150       1.6     perry 	int opcode, union ppbus_insarg param1, union ppbus_insarg param2,
    151       1.1  jdolecek 	union ppbus_insarg param3, int * ret)
    152       1.1  jdolecek {
    153       1.1  jdolecek 	struct ppbus_microseq msq[] = {
    154       1.6     perry 		{ MS_UNKNOWN, { { MS_UNKNOWN }, { MS_UNKNOWN },
    155       1.1  jdolecek 			{ MS_UNKNOWN } } },
    156       1.1  jdolecek 		MS_RET(0)
    157       1.1  jdolecek 	};
    158       1.1  jdolecek 
    159       1.1  jdolecek 	/* initialize the corresponding microseq */
    160       1.1  jdolecek 	msq[0].opcode = opcode;
    161       1.1  jdolecek 	msq[0].arg[0] = param1;
    162       1.1  jdolecek 	msq[0].arg[1] = param2;
    163       1.1  jdolecek 	msq[0].arg[2] = param3;
    164       1.1  jdolecek 
    165       1.1  jdolecek 	/* execute the microseq */
    166       1.1  jdolecek 	return (ppbus_MS_microseq(ppb, dev, msq, ret));
    167       1.1  jdolecek }
    168       1.1  jdolecek 
    169       1.1  jdolecek /*
    170       1.1  jdolecek  * ppbus_MS_loop()
    171       1.1  jdolecek  *
    172       1.1  jdolecek  * Execute a microseq loop
    173       1.1  jdolecek  *
    174       1.1  jdolecek  */
    175       1.1  jdolecek int
    176  1.7.70.1       mjf ppbus_MS_loop(device_t ppb, device_t dev,
    177       1.6     perry 	struct ppbus_microseq * prolog, struct ppbus_microseq * body,
    178       1.1  jdolecek 	struct ppbus_microseq * epilog, int iter, int * ret)
    179       1.1  jdolecek {
    180       1.1  jdolecek 	struct ppbus_microseq loop_microseq[] = {
    181       1.1  jdolecek 		MS_CALL(0),			/* execute prolog */
    182       1.1  jdolecek 		MS_SET(MS_UNKNOWN),		/* set size of transfer */
    183       1.1  jdolecek 
    184       1.1  jdolecek 		/* loop: */
    185       1.1  jdolecek 		MS_CALL(0),			/* execute body */
    186       1.1  jdolecek 		MS_DBRA(-1 /* loop: */),
    187       1.1  jdolecek 
    188       1.1  jdolecek 		MS_CALL(0),			/* execute epilog */
    189       1.1  jdolecek 		MS_RET(0)
    190       1.1  jdolecek 	};
    191       1.1  jdolecek 
    192       1.1  jdolecek 	/* initialize the structure */
    193       1.1  jdolecek 	loop_microseq[0].arg[0].p = (void *)prolog;
    194       1.1  jdolecek 	loop_microseq[1].arg[0].i = iter;
    195       1.1  jdolecek 	loop_microseq[2].arg[0].p = (void *)body;
    196       1.1  jdolecek 	loop_microseq[4].arg[0].p = (void *)epilog;
    197       1.1  jdolecek 
    198       1.1  jdolecek 	/* execute the loop */
    199       1.1  jdolecek 	return (ppbus_MS_microseq(ppb, dev, loop_microseq, ret));
    200       1.1  jdolecek }
    201       1.1  jdolecek 
    202       1.1  jdolecek /*
    203       1.1  jdolecek  * ppbus_MS_init_msq()
    204       1.1  jdolecek  *
    205       1.1  jdolecek  * Initialize a microsequence - see macros in ppbus_msq.h
    206       1.6     perry  * KNF does not work here, since using '...' requires you use the
    207       1.1  jdolecek  * standard C way of function definotion.
    208       1.1  jdolecek  *
    209       1.1  jdolecek  */
    210       1.1  jdolecek int
    211       1.1  jdolecek ppbus_MS_init_msq(struct ppbus_microseq * msq, int nbparam, ...)
    212       1.1  jdolecek {
    213       1.1  jdolecek 	int i;
    214       1.1  jdolecek 	int param, ins, arg, type;
    215       1.1  jdolecek 	va_list p_list;
    216       1.1  jdolecek 
    217       1.1  jdolecek 	va_start(p_list, nbparam);
    218       1.1  jdolecek 
    219       1.1  jdolecek 	for(i = 0; i < nbparam; i++) {
    220       1.1  jdolecek 		/* retrieve the parameter descriptor */
    221       1.1  jdolecek 		param = va_arg(p_list, int);
    222       1.1  jdolecek 
    223       1.1  jdolecek 		ins  = MS_INS(param);
    224       1.1  jdolecek 		arg  = MS_ARG(param);
    225       1.1  jdolecek 		type = MS_TYP(param);
    226       1.1  jdolecek 
    227       1.1  jdolecek 		/* check the instruction position */
    228       1.1  jdolecek 		if (arg >= PPBUS_MS_MAXARGS)
    229       1.6     perry 			panic("%s: parameter out of range (0x%x)!", __func__,
    230       1.1  jdolecek 				param);
    231       1.1  jdolecek 
    232       1.1  jdolecek #if 0
    233       1.6     perry 		printf("%s: param = %d, ins = %d, arg = %d, type = %d\n",
    234       1.1  jdolecek 			__func__, param, ins, arg, type);
    235       1.6     perry 
    236       1.1  jdolecek #endif
    237       1.1  jdolecek 
    238       1.1  jdolecek 		/* properly cast the parameter */
    239       1.1  jdolecek 		switch (type) {
    240       1.1  jdolecek 		case MS_TYP_INT:
    241       1.1  jdolecek 			msq[ins].arg[arg].i = va_arg(p_list, int);
    242       1.1  jdolecek 			break;
    243       1.1  jdolecek 
    244       1.1  jdolecek 		case MS_TYP_CHA:
    245       1.2  jdolecek 			/* XXX was:
    246       1.1  jdolecek 			msq[ins].arg[arg].i = (int)va_arg(p_list, char);
    247       1.2  jdolecek 			  which gives warning with gcc 3.3
    248       1.2  jdolecek 			*/
    249       1.2  jdolecek 			msq[ins].arg[arg].i = (int)va_arg(p_list, int);
    250       1.1  jdolecek 			break;
    251       1.1  jdolecek 
    252       1.1  jdolecek 		case MS_TYP_PTR:
    253       1.1  jdolecek 			msq[ins].arg[arg].p = va_arg(p_list, void *);
    254       1.1  jdolecek 			break;
    255       1.1  jdolecek 
    256       1.1  jdolecek 		case MS_TYP_FUN:
    257       1.1  jdolecek 			msq[ins].arg[arg].f = va_arg(p_list, void *);
    258       1.1  jdolecek 			break;
    259       1.1  jdolecek 
    260       1.1  jdolecek 		default:
    261       1.1  jdolecek 			panic("%s: unknown parameter (0x%x)!", __func__, param);
    262       1.1  jdolecek 		}
    263       1.1  jdolecek 	}
    264       1.1  jdolecek 
    265       1.1  jdolecek 	return (0);
    266       1.1  jdolecek }
    267       1.1  jdolecek 
    268       1.1  jdolecek /*
    269       1.1  jdolecek  * ppbus_MS_microseq()
    270       1.1  jdolecek  *
    271       1.1  jdolecek  * Interprete a microsequence. Some microinstructions are executed at adapter
    272       1.1  jdolecek  * level to avoid function call overhead between ppbus and the adapter
    273       1.1  jdolecek  */
    274       1.1  jdolecek int
    275  1.7.70.1       mjf ppbus_MS_microseq(device_t dev, device_t busdev,
    276       1.1  jdolecek 	struct ppbus_microseq * msq, int * ret)
    277       1.1  jdolecek {
    278  1.7.70.1       mjf 	struct ppbus_device_softc * ppbdev = device_private(busdev);
    279  1.7.70.1       mjf 	struct ppbus_softc * bus = device_private(dev);
    280       1.1  jdolecek 	struct ppbus_microseq * mi;		/* current microinstruction */
    281       1.6     perry 	size_t cnt;
    282       1.1  jdolecek 	int error;
    283       1.1  jdolecek 
    284       1.1  jdolecek 	struct ppbus_xfer * xfer;
    285       1.1  jdolecek 
    286       1.1  jdolecek 	/* microsequence executed to initialize the transfer */
    287       1.1  jdolecek 	struct ppbus_microseq initxfer[] = {
    288       1.1  jdolecek 		MS_PTR(MS_UNKNOWN), 	/* set ptr to buffer */
    289       1.1  jdolecek 		MS_SET(MS_UNKNOWN),	/* set transfer size */
    290       1.1  jdolecek 		MS_RET(0)
    291       1.1  jdolecek 	};
    292       1.1  jdolecek 
    293       1.1  jdolecek 	if(bus->ppbus_owner != busdev) {
    294       1.1  jdolecek 		return (EACCES);
    295       1.1  jdolecek 	}
    296       1.1  jdolecek 
    297       1.1  jdolecek #define INCR_PC (mi ++)
    298       1.1  jdolecek 
    299       1.1  jdolecek 	mi = msq;
    300       1.2  jdolecek again:
    301       1.1  jdolecek 	for (;;) {
    302       1.6     perry 		switch (mi->opcode) {
    303       1.1  jdolecek 		case MS_OP_PUT:
    304       1.1  jdolecek 		case MS_OP_GET:
    305       1.1  jdolecek 
    306       1.1  jdolecek 			/* attempt to choose the best mode for the device */
    307       1.1  jdolecek 			xfer = mode2xfer(bus, ppbdev, mi->opcode);
    308       1.1  jdolecek 
    309       1.1  jdolecek 			/* figure out if we should use ieee1284 code */
    310       1.1  jdolecek 			if (!xfer->loop) {
    311       1.1  jdolecek 				if (mi->opcode == MS_OP_PUT) {
    312       1.1  jdolecek 					if ((error = ppbus_write(
    313  1.7.70.1       mjf 						bus->sc_dev,
    314       1.1  jdolecek 						(char *)mi->arg[0].p,
    315       1.1  jdolecek 						mi->arg[1].i, 0, &cnt))) {
    316       1.1  jdolecek 						goto error;
    317       1.1  jdolecek 					}
    318       1.1  jdolecek 
    319       1.1  jdolecek 					INCR_PC;
    320       1.2  jdolecek 					goto again;
    321       1.1  jdolecek 				}
    322       1.1  jdolecek 				else {
    323       1.1  jdolecek 					panic("%s: IEEE1284 read not supported",
    324       1.1  jdolecek 						__func__);
    325       1.1  jdolecek 				}
    326       1.1  jdolecek 			}
    327       1.1  jdolecek 
    328       1.1  jdolecek 			/* XXX should use ppbus_MS_init_msq() */
    329       1.1  jdolecek 			initxfer[0].arg[0].p = mi->arg[0].p;
    330       1.1  jdolecek 			initxfer[1].arg[0].i = mi->arg[1].i;
    331       1.1  jdolecek 
    332       1.1  jdolecek 			/* initialize transfer */
    333       1.1  jdolecek 			ppbus_MS_microseq(dev, busdev, initxfer, &error);
    334       1.1  jdolecek 
    335       1.1  jdolecek 			if (error)
    336       1.1  jdolecek 				goto error;
    337       1.1  jdolecek 
    338       1.1  jdolecek 			/* the xfer microsequence should not contain any
    339       1.1  jdolecek 			 * MS_OP_PUT or MS_OP_GET!
    340       1.1  jdolecek 			 */
    341       1.1  jdolecek 			ppbus_MS_microseq(dev, busdev, xfer->loop, &error);
    342       1.1  jdolecek 
    343       1.1  jdolecek 			if (error)
    344       1.1  jdolecek 				goto error;
    345       1.1  jdolecek 
    346       1.1  jdolecek 			INCR_PC;
    347       1.1  jdolecek 			break;
    348       1.1  jdolecek 
    349       1.1  jdolecek                 case MS_OP_RET:
    350       1.1  jdolecek 			if (ret)
    351       1.1  jdolecek 				*ret = mi->arg[0].i;	/* return code */
    352       1.1  jdolecek 			return (0);
    353       1.1  jdolecek                         break;
    354       1.1  jdolecek 
    355       1.1  jdolecek 		default:
    356       1.1  jdolecek 			/* executing microinstructions at ppc level is
    357       1.1  jdolecek 			 * faster. This is the default if the microinstr
    358       1.1  jdolecek 			 * is unknown here
    359       1.1  jdolecek 			 */
    360       1.6     perry 			if((error =
    361       1.1  jdolecek 				bus->ppbus_exec_microseq(
    362  1.7.70.1       mjf 				bus->sc_dev, &mi))) {
    363       1.6     perry 
    364       1.1  jdolecek 				goto error;
    365       1.1  jdolecek 			}
    366       1.1  jdolecek 			break;
    367       1.1  jdolecek 		}
    368       1.1  jdolecek 	}
    369       1.1  jdolecek error:
    370       1.1  jdolecek 	return (error);
    371       1.1  jdolecek }
    372       1.1  jdolecek 
    373