138061Smsmith/*- 255939Snsouch * Copyright (c) 1998, 1999 Nicolas Souchu 338061Smsmith * All rights reserved. 438061Smsmith * 538061Smsmith * Redistribution and use in source and binary forms, with or without 638061Smsmith * modification, are permitted provided that the following conditions 738061Smsmith * are met: 838061Smsmith * 1. Redistributions of source code must retain the above copyright 938061Smsmith * notice, this list of conditions and the following disclaimer. 1038061Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138061Smsmith * notice, this list of conditions and the following disclaimer in the 1238061Smsmith * documentation and/or other materials provided with the distribution. 1338061Smsmith * 1438061Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538061Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638061Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738061Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838061Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938061Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038061Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138061Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238061Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338061Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438061Smsmith * SUCH DAMAGE. 2538061Smsmith * 2638061Smsmith * 2738061Smsmith */ 28119418Sobrien 29119418Sobrien#include <sys/cdefs.h> 30119418Sobrien__FBSDID("$FreeBSD$"); 3138061Smsmith#include <machine/stdarg.h> 3238061Smsmith 3338061Smsmith#include <sys/param.h> 34187576Sjhb#include <sys/lock.h> 35187576Sjhb#include <sys/mutex.h> 3638061Smsmith#include <sys/systm.h> 3755939Snsouch#include <sys/bus.h> 3838061Smsmith 3938061Smsmith#include <dev/ppbus/ppbconf.h> 4038061Smsmith#include <dev/ppbus/ppb_msq.h> 4138061Smsmith 4255939Snsouch#include "ppbus_if.h" 4355939Snsouch 4438061Smsmith/* msq index (see PPB_MAX_XFER) 4538061Smsmith * These are device modes 4638061Smsmith */ 4738061Smsmith#define COMPAT_MSQ 0x0 4838061Smsmith#define NIBBLE_MSQ 0x1 4938061Smsmith#define PS2_MSQ 0x2 5038061Smsmith#define EPP17_MSQ 0x3 5138061Smsmith#define EPP19_MSQ 0x4 5238061Smsmith#define ECP_MSQ 0x5 5338061Smsmith 5438061Smsmith/* 5538061Smsmith * Device mode to submsq conversion 5638061Smsmith */ 5738061Smsmithstatic struct ppb_xfer * 5855939Snsouchmode2xfer(device_t bus, struct ppb_device *ppbdev, int opcode) 5938061Smsmith{ 60184130Sjhb int index, epp, mode; 6138061Smsmith struct ppb_xfer *table; 6238061Smsmith 6338061Smsmith switch (opcode) { 6438061Smsmith case MS_OP_GET: 6555939Snsouch table = ppbdev->get_xfer; 6638061Smsmith break; 6738061Smsmith 6838061Smsmith case MS_OP_PUT: 6955939Snsouch table = ppbdev->put_xfer; 7038061Smsmith break; 7138061Smsmith 7238061Smsmith default: 7387599Sobrien panic("%s: unknown opcode (%d)", __func__, opcode); 7438061Smsmith } 7538061Smsmith 7638061Smsmith /* retrieve the device operating mode */ 77184130Sjhb mode = ppb_get_mode(bus); 78184130Sjhb switch (mode) { 7938061Smsmith case PPB_COMPATIBLE: 8038061Smsmith index = COMPAT_MSQ; 8138061Smsmith break; 8238061Smsmith case PPB_NIBBLE: 8338061Smsmith index = NIBBLE_MSQ; 8438061Smsmith break; 8538061Smsmith case PPB_PS2: 8638061Smsmith index = PS2_MSQ; 8738061Smsmith break; 8838061Smsmith case PPB_EPP: 8955939Snsouch switch ((epp = ppb_get_epp_protocol(bus))) { 9038061Smsmith case EPP_1_7: 9138061Smsmith index = EPP17_MSQ; 9238061Smsmith break; 9338061Smsmith case EPP_1_9: 9438061Smsmith index = EPP19_MSQ; 9538061Smsmith break; 9638061Smsmith default: 9787599Sobrien panic("%s: unknown EPP protocol (0x%x)!", __func__, 9838061Smsmith epp); 9938061Smsmith } 10038061Smsmith break; 10138061Smsmith case PPB_ECP: 10238061Smsmith index = ECP_MSQ; 10338061Smsmith break; 10438061Smsmith default: 105184130Sjhb panic("%s: unknown mode (%d)", __func__, mode); 10638061Smsmith } 10738061Smsmith 10838061Smsmith return (&table[index]); 10938061Smsmith} 11038061Smsmith 11138061Smsmith/* 11238061Smsmith * ppb_MS_init() 11338061Smsmith * 11438061Smsmith * Initialize device dependent submicrosequence of the current mode 11538061Smsmith * 11638061Smsmith */ 11738061Smsmithint 11855939Snsouchppb_MS_init(device_t bus, device_t dev, struct ppb_microseq *loop, int opcode) 11938061Smsmith{ 12055939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 12155939Snsouch struct ppb_xfer *xfer = mode2xfer(bus, ppbdev, opcode); 12238061Smsmith 123230800Sattilio ppb_assert_locked(bus); 12438061Smsmith xfer->loop = loop; 12538061Smsmith 12638061Smsmith return (0); 12738061Smsmith} 12838061Smsmith 12938061Smsmith/* 13038061Smsmith * ppb_MS_exec() 13138061Smsmith * 13238061Smsmith * Execute any microsequence opcode - expensive 13338061Smsmith * 13438061Smsmith */ 13538061Smsmithint 13655939Snsouchppb_MS_exec(device_t bus, device_t dev, int opcode, union ppb_insarg param1, 13738061Smsmith union ppb_insarg param2, union ppb_insarg param3, int *ret) 13838061Smsmith{ 13938061Smsmith struct ppb_microseq msq[] = { 14043295Sdillon { MS_UNKNOWN, { { MS_UNKNOWN }, { MS_UNKNOWN }, { MS_UNKNOWN } } }, 14138061Smsmith MS_RET(0) 14238061Smsmith }; 14338061Smsmith 14438061Smsmith /* initialize the corresponding microseq */ 14538061Smsmith msq[0].opcode = opcode; 14638061Smsmith msq[0].arg[0] = param1; 14738061Smsmith msq[0].arg[1] = param2; 14838061Smsmith msq[0].arg[2] = param3; 14938061Smsmith 15038061Smsmith /* execute the microseq */ 15155939Snsouch return (ppb_MS_microseq(bus, dev, msq, ret)); 15238061Smsmith} 15338061Smsmith 15438061Smsmith/* 15538061Smsmith * ppb_MS_loop() 15638061Smsmith * 15738061Smsmith * Execute a microseq loop 15838061Smsmith * 15938061Smsmith */ 16038061Smsmithint 16155939Snsouchppb_MS_loop(device_t bus, device_t dev, struct ppb_microseq *prolog, 16238061Smsmith struct ppb_microseq *body, struct ppb_microseq *epilog, 16338061Smsmith int iter, int *ret) 16438061Smsmith{ 16538061Smsmith struct ppb_microseq loop_microseq[] = { 16654903Seivind MS_CALL(0), /* execute prolog */ 16738061Smsmith 16838061Smsmith MS_SET(MS_UNKNOWN), /* set size of transfer */ 16938061Smsmith /* loop: */ 17054903Seivind MS_CALL(0), /* execute body */ 17138061Smsmith MS_DBRA(-1 /* loop: */), 17238061Smsmith 17354903Seivind MS_CALL(0), /* execute epilog */ 17438061Smsmith MS_RET(0) 17538061Smsmith }; 17638061Smsmith 17738061Smsmith /* initialize the structure */ 17838061Smsmith loop_microseq[0].arg[0].p = (void *)prolog; 17938061Smsmith loop_microseq[1].arg[0].i = iter; 18038061Smsmith loop_microseq[2].arg[0].p = (void *)body; 18138061Smsmith loop_microseq[4].arg[0].p = (void *)epilog; 18238061Smsmith 18338061Smsmith /* execute the loop */ 18455939Snsouch return (ppb_MS_microseq(bus, dev, loop_microseq, ret)); 18538061Smsmith} 18638061Smsmith 18738061Smsmith/* 18838061Smsmith * ppb_MS_init_msq() 18938061Smsmith * 19038061Smsmith * Initialize a microsequence - see macros in ppb_msq.h 19138061Smsmith * 19238061Smsmith */ 19338061Smsmithint 19438061Smsmithppb_MS_init_msq(struct ppb_microseq *msq, int nbparam, ...) 19538061Smsmith{ 19638061Smsmith int i; 19738061Smsmith int param, ins, arg, type; 19856618Sdfr va_list p_list; 19938061Smsmith 20038061Smsmith va_start(p_list, nbparam); 20138061Smsmith 20238061Smsmith for (i=0; i<nbparam; i++) { 20338061Smsmith /* retrieve the parameter descriptor */ 20438061Smsmith param = va_arg(p_list, int); 20538061Smsmith 20638061Smsmith ins = MS_INS(param); 20738061Smsmith arg = MS_ARG(param); 20838061Smsmith type = MS_TYP(param); 20938061Smsmith 21038061Smsmith /* check the instruction position */ 21138061Smsmith if (arg >= PPB_MS_MAXARGS) 21238061Smsmith panic("%s: parameter out of range (0x%x)!", 21387599Sobrien __func__, param); 21438061Smsmith 21538061Smsmith#if 0 216185003Sjhb printf("%s: param = %d, ins = %d, arg = %d, type = %d\n", 21787599Sobrien __func__, param, ins, arg, type); 21838061Smsmith#endif 21938061Smsmith 22038061Smsmith /* properly cast the parameter */ 22138061Smsmith switch (type) { 22238061Smsmith case MS_TYP_INT: 22338061Smsmith msq[ins].arg[arg].i = va_arg(p_list, int); 22438061Smsmith break; 22538061Smsmith 22638061Smsmith case MS_TYP_CHA: 22766933Sdfr msq[ins].arg[arg].i = (int)va_arg(p_list, int); 22838061Smsmith break; 22938061Smsmith 23038061Smsmith case MS_TYP_PTR: 23138061Smsmith msq[ins].arg[arg].p = va_arg(p_list, void *); 23238061Smsmith break; 23338061Smsmith 23438061Smsmith case MS_TYP_FUN: 23538061Smsmith msq[ins].arg[arg].f = va_arg(p_list, void *); 23638061Smsmith break; 23738061Smsmith 23838061Smsmith default: 23987599Sobrien panic("%s: unknown parameter (0x%x)!", __func__, 24038061Smsmith param); 24138061Smsmith } 24238061Smsmith } 24338061Smsmith 244226385Sbrueffer va_end(p_list); 24538061Smsmith return (0); 24638061Smsmith} 24738061Smsmith 24838061Smsmith/* 24938061Smsmith * ppb_MS_microseq() 25038061Smsmith * 25138061Smsmith * Interprete a microsequence. Some microinstructions are executed at adapter 25238061Smsmith * level to avoid function call overhead between ppbus and the adapter 25338061Smsmith */ 25438061Smsmithint 25555939Snsouchppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret) 25638061Smsmith{ 25755939Snsouch struct ppb_data *ppb = (struct ppb_data *)device_get_softc(bus); 25855939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 25955939Snsouch 26038061Smsmith struct ppb_microseq *mi; /* current microinstruction */ 26139520Snsouch int error; 26238061Smsmith 26338061Smsmith struct ppb_xfer *xfer; 26438061Smsmith 26538061Smsmith /* microsequence executed to initialize the transfer */ 26638061Smsmith struct ppb_microseq initxfer[] = { 26738061Smsmith MS_PTR(MS_UNKNOWN), /* set ptr to buffer */ 26838061Smsmith MS_SET(MS_UNKNOWN), /* set transfer size */ 26938061Smsmith MS_RET(0) 27038061Smsmith }; 27138061Smsmith 272187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 27338061Smsmith if (ppb->ppb_owner != dev) 27438061Smsmith return (EACCES); 27538061Smsmith 27639520Snsouch#define INCR_PC (mi ++) 27738061Smsmith 27839520Snsouch mi = msq; 27938061Smsmith for (;;) { 280185003Sjhb switch (mi->opcode) { 28138061Smsmith case MS_OP_PUT: 28238061Smsmith case MS_OP_GET: 28338061Smsmith 28438061Smsmith /* attempt to choose the best mode for the device */ 28555939Snsouch xfer = mode2xfer(bus, ppbdev, mi->opcode); 28638061Smsmith 28738061Smsmith /* figure out if we should use ieee1284 code */ 28842475Snsouch if (!xfer->loop) { 28942475Snsouch if (mi->opcode == MS_OP_PUT) { 29055939Snsouch if ((error = PPBUS_WRITE( 29155939Snsouch device_get_parent(bus), 29242475Snsouch (char *)mi->arg[0].p, 29342475Snsouch mi->arg[1].i, 0))) 29442475Snsouch goto error; 29538061Smsmith 29642475Snsouch INCR_PC; 29742475Snsouch goto next; 29842475Snsouch } else 29987599Sobrien panic("%s: IEEE1284 read not supported", __func__); 30042475Snsouch } 30142475Snsouch 30238061Smsmith /* XXX should use ppb_MS_init_msq() */ 30338061Smsmith initxfer[0].arg[0].p = mi->arg[0].p; 30438061Smsmith initxfer[1].arg[0].i = mi->arg[1].i; 30538061Smsmith 30638061Smsmith /* initialize transfer */ 30755939Snsouch ppb_MS_microseq(bus, dev, initxfer, &error); 30838061Smsmith 30938061Smsmith if (error) 31038061Smsmith goto error; 31138061Smsmith 31238061Smsmith /* the xfer microsequence should not contain any 31338061Smsmith * MS_OP_PUT or MS_OP_GET! 31438061Smsmith */ 31555939Snsouch ppb_MS_microseq(bus, dev, xfer->loop, &error); 31638061Smsmith 31738061Smsmith if (error) 31838061Smsmith goto error; 31938061Smsmith 32038061Smsmith INCR_PC; 32138061Smsmith break; 32238061Smsmith 323185003Sjhb case MS_OP_RET: 32439134Snsouch if (ret) 32539134Snsouch *ret = mi->arg[0].i; /* return code */ 32638061Smsmith return (0); 32738061Smsmith 32838061Smsmith default: 32938061Smsmith /* executing microinstructions at ppc level is 33038061Smsmith * faster. This is the default if the microinstr 33138061Smsmith * is unknown here 33238061Smsmith */ 33355939Snsouch if ((error = PPBUS_EXEC_MICROSEQ( 33455939Snsouch device_get_parent(bus), &mi))) 33539520Snsouch goto error; 33638061Smsmith break; 33738061Smsmith } 33842475Snsouch next: 33992732Speter continue; 34038061Smsmith } 34138061Smsmitherror: 34239520Snsouch return (error); 34338061Smsmith} 34438061Smsmith 345