1*c7fb772bSthorpej /* $NetBSD: gpib.c,v 1.26 2021/08/07 16:19:10 thorpej Exp $ */
212379e3bSgmcgarry
312379e3bSgmcgarry /*-
412379e3bSgmcgarry * Copyright (c) 2003 The NetBSD Foundation, Inc.
512379e3bSgmcgarry * All rights reserved.
612379e3bSgmcgarry *
712379e3bSgmcgarry * This code is derived from software contributed to The NetBSD Foundation
812379e3bSgmcgarry * by Gregory McGarry.
912379e3bSgmcgarry *
1012379e3bSgmcgarry * Redistribution and use in source and binary forms, with or without
1112379e3bSgmcgarry * modification, are permitted provided that the following conditions
1212379e3bSgmcgarry * are met:
1312379e3bSgmcgarry * 1. Redistributions of source code must retain the above copyright
1412379e3bSgmcgarry * notice, this list of conditions and the following disclaimer.
1512379e3bSgmcgarry * 2. Redistributions in binary form must reproduce the above copyright
1612379e3bSgmcgarry * notice, this list of conditions and the following disclaimer in the
1712379e3bSgmcgarry * documentation and/or other materials provided with the distribution.
1812379e3bSgmcgarry *
1912379e3bSgmcgarry * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2012379e3bSgmcgarry * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2112379e3bSgmcgarry * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2212379e3bSgmcgarry * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2312379e3bSgmcgarry * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2412379e3bSgmcgarry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2512379e3bSgmcgarry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2612379e3bSgmcgarry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2712379e3bSgmcgarry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2812379e3bSgmcgarry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2912379e3bSgmcgarry * POSSIBILITY OF SUCH DAMAGE.
3012379e3bSgmcgarry */
3112379e3bSgmcgarry
3212379e3bSgmcgarry #include <sys/cdefs.h>
33*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: gpib.c,v 1.26 2021/08/07 16:19:10 thorpej Exp $");
3412379e3bSgmcgarry
3512379e3bSgmcgarry #include <sys/param.h>
3612379e3bSgmcgarry #include <sys/systm.h>
3712379e3bSgmcgarry #include <sys/conf.h>
3812379e3bSgmcgarry #include <sys/device.h>
3912379e3bSgmcgarry #include <sys/ioctl.h>
4012379e3bSgmcgarry #include <sys/malloc.h>
4112379e3bSgmcgarry #include <sys/proc.h>
4212379e3bSgmcgarry
4312379e3bSgmcgarry #include <dev/gpib/gpibvar.h>
4412379e3bSgmcgarry
4512379e3bSgmcgarry #include <dev/gpib/gpibio.h> /* XXX */
4612379e3bSgmcgarry
4712379e3bSgmcgarry #include "locators.h"
4812379e3bSgmcgarry
49d41f17e2Stsutsui #ifndef DEBUG
5012379e3bSgmcgarry #define DEBUG
51d41f17e2Stsutsui #endif
5212379e3bSgmcgarry
5312379e3bSgmcgarry #ifdef DEBUG
5412379e3bSgmcgarry int gpibdebug = 0xff;
5512379e3bSgmcgarry #define DBG_FOLLOW 0x01
5612379e3bSgmcgarry #define DBG_INTR 0x02
5712379e3bSgmcgarry #define DBG_FAIL 0x04
5812379e3bSgmcgarry #define DPRINTF(mask, str) if (gpibdebug & (mask)) printf str
5912379e3bSgmcgarry #else
6012379e3bSgmcgarry #define DPRINTF(mask, str) /* nothing */
6112379e3bSgmcgarry #endif
6212379e3bSgmcgarry
63529e91fcScegger int gpibmatch(device_t, cfdata_t, void *);
64529e91fcScegger void gpibattach(device_t, device_t, void *);
6512379e3bSgmcgarry
66cbab9cadSchs CFATTACH_DECL_NEW(gpib, sizeof(struct gpib_softc),
6712379e3bSgmcgarry gpibmatch, gpibattach, NULL, NULL);
6812379e3bSgmcgarry
69cbab9cadSchs static int gpibsubmatch1(device_t, cfdata_t, const int *, void *);
70cbab9cadSchs static int gpibsubmatch2(device_t, cfdata_t, const int *, void *);
7112379e3bSgmcgarry static int gpibprint(void *, const char *);
7212379e3bSgmcgarry
7312379e3bSgmcgarry dev_type_open(gpibopen);
7412379e3bSgmcgarry dev_type_close(gpibclose);
7512379e3bSgmcgarry dev_type_read(gpibread);
7612379e3bSgmcgarry dev_type_write(gpibwrite);
7712379e3bSgmcgarry dev_type_ioctl(gpibioctl);
7812379e3bSgmcgarry dev_type_poll(gpibpoll);
7912379e3bSgmcgarry
8012379e3bSgmcgarry const struct cdevsw gpib_cdevsw = {
81a68f9396Sdholland .d_open = gpibopen,
82a68f9396Sdholland .d_close = gpibclose,
83a68f9396Sdholland .d_read = gpibread,
84a68f9396Sdholland .d_write = gpibwrite,
85a68f9396Sdholland .d_ioctl = gpibioctl,
86a68f9396Sdholland .d_stop = nostop,
87a68f9396Sdholland .d_tty = notty,
88a68f9396Sdholland .d_poll = gpibpoll,
89a68f9396Sdholland .d_mmap = nommap,
90a68f9396Sdholland .d_kqfilter = nokqfilter,
91f9228f42Sdholland .d_discard = nodiscard,
92a68f9396Sdholland .d_flag = D_OTHER
9312379e3bSgmcgarry };
9412379e3bSgmcgarry
9512379e3bSgmcgarry extern struct cfdriver gpib_cd;
9612379e3bSgmcgarry
9712379e3bSgmcgarry #define GPIBUNIT(dev) (minor(dev) & 0x0f)
9812379e3bSgmcgarry
9912379e3bSgmcgarry int gpibtimeout = 100000; /* # of status tests before we give up */
10012379e3bSgmcgarry
10112379e3bSgmcgarry int
gpibmatch(device_t parent,cfdata_t match,void * aux)102529e91fcScegger gpibmatch(device_t parent, cfdata_t match, void *aux)
10312379e3bSgmcgarry {
10412379e3bSgmcgarry
10512379e3bSgmcgarry return (1);
10612379e3bSgmcgarry }
10712379e3bSgmcgarry
10812379e3bSgmcgarry void
gpibattach(device_t parent,device_t self,void * aux)109529e91fcScegger gpibattach(device_t parent, device_t self, void *aux)
11012379e3bSgmcgarry {
11192c7bba3Sthorpej struct gpib_softc *sc = device_private(self);
112cbab9cadSchs cfdata_t cf = device_cfdata(self);
11312379e3bSgmcgarry struct gpibdev_attach_args *gda = aux;
11412379e3bSgmcgarry struct gpib_attach_args ga;
11512379e3bSgmcgarry int address;
11612379e3bSgmcgarry
117cbab9cadSchs sc->sc_dev = self;
11812379e3bSgmcgarry sc->sc_ic = gda->ga_ic;
11912379e3bSgmcgarry
12012379e3bSgmcgarry /*
12112379e3bSgmcgarry * If the configuration file specified a host address, then
12212379e3bSgmcgarry * use it in favour of registers/switches or the default (30).
12312379e3bSgmcgarry */
12412379e3bSgmcgarry if (cf->cf_loc[GPIBDEVCF_ADDRESS] != GPIBDEVCF_ADDRESS_DEFAULT)
12512379e3bSgmcgarry sc->sc_myaddr = cf->cf_loc[GPIBDEVCF_ADDRESS];
12612379e3bSgmcgarry else if (gda->ga_address != GPIBDEVCF_ADDRESS_DEFAULT)
12712379e3bSgmcgarry sc->sc_myaddr = gda->ga_address;
12812379e3bSgmcgarry else
12912379e3bSgmcgarry sc->sc_myaddr = 30;
13012379e3bSgmcgarry
13112379e3bSgmcgarry printf(": host address %d\n", sc->sc_myaddr);
13212379e3bSgmcgarry
13312379e3bSgmcgarry /* record our softc pointer */
13412379e3bSgmcgarry sc->sc_ic->bus = sc;
13512379e3bSgmcgarry
13612379e3bSgmcgarry /* Initialize the slave request queue */
13712379e3bSgmcgarry TAILQ_INIT(&sc->sc_queue);
13812379e3bSgmcgarry
13912379e3bSgmcgarry /* attach addressed devices */
14012379e3bSgmcgarry for (address=0; address<GPIB_NDEVS; address++) {
14112379e3bSgmcgarry ga.ga_ic = sc->sc_ic;
14212379e3bSgmcgarry ga.ga_address = address;
1432685996bSthorpej config_search(sc->sc_dev, &ga,
144*c7fb772bSthorpej CFARGS(.search = gpibsubmatch1));
14512379e3bSgmcgarry }
14612379e3bSgmcgarry
14712379e3bSgmcgarry /* attach the wild-carded devices - probably protocol busses */
14812379e3bSgmcgarry ga.ga_ic = sc->sc_ic;
1492685996bSthorpej config_search(sc->sc_dev, &ga,
150*c7fb772bSthorpej CFARGS(.search = gpibsubmatch2));
15112379e3bSgmcgarry }
15212379e3bSgmcgarry
15312379e3bSgmcgarry int
gpibsubmatch1(device_t parent,cfdata_t cf,const int * ldesc,void * aux)154529e91fcScegger gpibsubmatch1(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
15512379e3bSgmcgarry {
156cbab9cadSchs struct gpib_softc *sc = device_private(parent);
15712379e3bSgmcgarry struct gpib_attach_args *ga = aux;
15812379e3bSgmcgarry
15912379e3bSgmcgarry if (cf->cf_loc[GPIBCF_ADDRESS] != ga->ga_address)
16012379e3bSgmcgarry return (0);
16112379e3bSgmcgarry
16212379e3bSgmcgarry if (cf->cf_loc[GPIBCF_ADDRESS] == sc->sc_myaddr)
16312379e3bSgmcgarry return (0);
16412379e3bSgmcgarry
1652685996bSthorpej if (config_probe(parent, cf, ga)) {
16612379e3bSgmcgarry if (gpib_alloc(sc, ga->ga_address))
16712379e3bSgmcgarry return (0);
168*c7fb772bSthorpej config_attach(parent, cf, ga, gpibprint, CFARGS_NONE);
16912379e3bSgmcgarry return (0);
17012379e3bSgmcgarry }
17112379e3bSgmcgarry return (0);
17212379e3bSgmcgarry }
17312379e3bSgmcgarry
17412379e3bSgmcgarry int
gpibsubmatch2(device_t parent,cfdata_t cf,const int * ldesc,void * aux)175529e91fcScegger gpibsubmatch2(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
17612379e3bSgmcgarry {
17712379e3bSgmcgarry struct gpib_attach_args *ga = aux;
17812379e3bSgmcgarry
17912379e3bSgmcgarry if (cf->cf_loc[GPIBCF_ADDRESS] != GPIBCF_ADDRESS_DEFAULT)
18012379e3bSgmcgarry return (0);
18112379e3bSgmcgarry
18212379e3bSgmcgarry ga->ga_address = GPIBCF_ADDRESS_DEFAULT;
1832685996bSthorpej if (config_probe(parent, cf, ga)) {
184*c7fb772bSthorpej config_attach(parent, cf, ga, gpibdevprint, CFARGS_NONE);
18512379e3bSgmcgarry return (0);
18612379e3bSgmcgarry }
18712379e3bSgmcgarry return (0);
18812379e3bSgmcgarry }
18912379e3bSgmcgarry
19012379e3bSgmcgarry int
gpibprint(void * aux,const char * pnp)191454af1c0Sdsl gpibprint(void *aux, const char *pnp)
19212379e3bSgmcgarry {
19312379e3bSgmcgarry struct gpib_attach_args *ga = aux;
19412379e3bSgmcgarry
19512379e3bSgmcgarry if (ga->ga_address != GPIBCF_ADDRESS_DEFAULT)
19612379e3bSgmcgarry printf(" address %d", ga->ga_address);
19712379e3bSgmcgarry return (UNCONF);
19812379e3bSgmcgarry }
19912379e3bSgmcgarry
20012379e3bSgmcgarry int
gpibdevprint(void * aux,const char * pnp)201454af1c0Sdsl gpibdevprint(void *aux, const char *pnp)
20212379e3bSgmcgarry {
20312379e3bSgmcgarry
20412379e3bSgmcgarry if (pnp != NULL)
20512379e3bSgmcgarry printf("gpib at %s", pnp);
20612379e3bSgmcgarry return (UNCONF);
20712379e3bSgmcgarry }
20812379e3bSgmcgarry
20912379e3bSgmcgarry /*
21012379e3bSgmcgarry * Called by hardware driver, pass to device driver.
21112379e3bSgmcgarry */
21212379e3bSgmcgarry int
gpibintr(void * v)213454af1c0Sdsl gpibintr(void *v)
21412379e3bSgmcgarry {
21512379e3bSgmcgarry struct gpib_softc *sc = v;
21612379e3bSgmcgarry gpib_handle_t hdl;
21712379e3bSgmcgarry
21812379e3bSgmcgarry DPRINTF(DBG_INTR, ("gpibintr: sc=%p\n", sc));
21912379e3bSgmcgarry
22012379e3bSgmcgarry hdl = TAILQ_FIRST(&sc->sc_queue);
22112379e3bSgmcgarry (hdl->hq_callback)(hdl->hq_softc, GPIBCBF_INTR);
22212379e3bSgmcgarry return (0);
22312379e3bSgmcgarry }
22412379e3bSgmcgarry
22512379e3bSgmcgarry /*
22612379e3bSgmcgarry * Create a callback handle.
22712379e3bSgmcgarry */
22812379e3bSgmcgarry int
_gpibregister(struct gpib_softc * sc,int slave,gpib_callback_t callback,void * arg,gpib_handle_t * hdl)22971fbb921Smsaitoh _gpibregister(struct gpib_softc *sc, int slave, gpib_callback_t callback,
23071fbb921Smsaitoh void *arg, gpib_handle_t *hdl)
23112379e3bSgmcgarry {
23212379e3bSgmcgarry
233d47bcd29Schs *hdl = malloc(sizeof(struct gpibqueue), M_DEVBUF, M_WAITOK);
23412379e3bSgmcgarry (*hdl)->hq_slave = slave;
23512379e3bSgmcgarry (*hdl)->hq_callback = callback;
23612379e3bSgmcgarry (*hdl)->hq_softc = arg;
23712379e3bSgmcgarry
23812379e3bSgmcgarry return (0);
23912379e3bSgmcgarry }
24012379e3bSgmcgarry
24112379e3bSgmcgarry /*
24212379e3bSgmcgarry * Request exclusive access to the GPIB bus.
24312379e3bSgmcgarry */
24412379e3bSgmcgarry int
_gpibrequest(struct gpib_softc * sc,gpib_handle_t hdl)24582357f6dSdsl _gpibrequest(struct gpib_softc *sc, gpib_handle_t hdl)
24612379e3bSgmcgarry {
24712379e3bSgmcgarry
24812379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("_gpibrequest: sc=%p hdl=%p\n", sc, hdl));
24912379e3bSgmcgarry
25012379e3bSgmcgarry TAILQ_INSERT_TAIL(&sc->sc_queue, hdl, hq_list);
25112379e3bSgmcgarry if (TAILQ_FIRST(&sc->sc_queue) == hdl)
25212379e3bSgmcgarry return (1);
25312379e3bSgmcgarry
25412379e3bSgmcgarry return (0);
25512379e3bSgmcgarry }
25612379e3bSgmcgarry
25712379e3bSgmcgarry /*
25812379e3bSgmcgarry * Release exclusive access to the GPIB bus.
25912379e3bSgmcgarry */
26012379e3bSgmcgarry void
_gpibrelease(struct gpib_softc * sc,gpib_handle_t hdl)26182357f6dSdsl _gpibrelease(struct gpib_softc *sc, gpib_handle_t hdl)
26212379e3bSgmcgarry {
26312379e3bSgmcgarry
26412379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("_gpibrelease: sc=%p hdl=%p\n", sc, hdl));
26512379e3bSgmcgarry
26612379e3bSgmcgarry TAILQ_REMOVE(&sc->sc_queue, hdl, hq_list);
26712379e3bSgmcgarry if ((hdl = TAILQ_FIRST(&sc->sc_queue)) != NULL)
26812379e3bSgmcgarry (*hdl->hq_callback)(hdl->hq_softc, GPIBCBF_START);
26912379e3bSgmcgarry }
27012379e3bSgmcgarry
27112379e3bSgmcgarry
27212379e3bSgmcgarry /*
27312379e3bSgmcgarry * Asynchronous wait.
27412379e3bSgmcgarry */
27512379e3bSgmcgarry void
_gpibawait(struct gpib_softc * sc)27682357f6dSdsl _gpibawait(struct gpib_softc *sc)
27712379e3bSgmcgarry {
27812379e3bSgmcgarry int slave;
27912379e3bSgmcgarry
28012379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("_gpibawait: sc=%p\n", sc));
28112379e3bSgmcgarry
28212379e3bSgmcgarry slave = TAILQ_FIRST(&sc->sc_queue)->hq_slave;
28312379e3bSgmcgarry (*sc->sc_ic->ppwatch)(sc->sc_ic->cookie, slave);
28412379e3bSgmcgarry }
28512379e3bSgmcgarry
28612379e3bSgmcgarry /*
28712379e3bSgmcgarry * Synchronous (spin) wait.
28812379e3bSgmcgarry */
28912379e3bSgmcgarry int
_gpibswait(struct gpib_softc * sc,int slave)29082357f6dSdsl _gpibswait(struct gpib_softc *sc, int slave)
29112379e3bSgmcgarry {
29212379e3bSgmcgarry int timo = gpibtimeout;
29312379e3bSgmcgarry int (*pptest)(void *, int);
29412379e3bSgmcgarry
29512379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("_gpibswait: sc=%p\n", sc));
29612379e3bSgmcgarry
29712379e3bSgmcgarry pptest = sc->sc_ic->pptest;
29812379e3bSgmcgarry while ((*pptest)(sc->sc_ic->cookie, slave) == 0) {
29912379e3bSgmcgarry if (--timo == 0) {
300cbab9cadSchs aprint_error_dev(sc->sc_dev, "swait timeout\n");
30112379e3bSgmcgarry return(-1);
30212379e3bSgmcgarry }
30312379e3bSgmcgarry }
30412379e3bSgmcgarry return (0);
30512379e3bSgmcgarry }
30612379e3bSgmcgarry
30712379e3bSgmcgarry /*
30812379e3bSgmcgarry * Resource accounting: check if the address has already been
30912379e3bSgmcgarry * claimed and allocated.
31012379e3bSgmcgarry */
31112379e3bSgmcgarry int
gpib_isalloc(struct gpib_softc * sc,u_int8_t address)312454af1c0Sdsl gpib_isalloc(struct gpib_softc *sc, u_int8_t address)
31312379e3bSgmcgarry {
31412379e3bSgmcgarry
31512379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpib_isalloc: sc=%p address=%d\n", sc, address));
31612379e3bSgmcgarry
31712379e3bSgmcgarry #ifdef DIAGNOSTIC
31812379e3bSgmcgarry if (address >= GPIB_NDEVS)
31912379e3bSgmcgarry panic("gpib_isalloc: device address out of range");
32012379e3bSgmcgarry #endif
32112379e3bSgmcgarry
32212379e3bSgmcgarry return ((sc->sc_rmap & (1 << address)) != 0);
32312379e3bSgmcgarry }
32412379e3bSgmcgarry
32512379e3bSgmcgarry /*
32612379e3bSgmcgarry * Resource accounting: allocate the address.
32712379e3bSgmcgarry */
32812379e3bSgmcgarry int
gpib_alloc(struct gpib_softc * sc,u_int8_t address)329454af1c0Sdsl gpib_alloc(struct gpib_softc *sc, u_int8_t address)
33012379e3bSgmcgarry {
33112379e3bSgmcgarry
33212379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpib_alloc: sc=%p address=%d\n", sc, address));
33312379e3bSgmcgarry
33412379e3bSgmcgarry #ifdef DIAGNOSTIC
33512379e3bSgmcgarry if (address >= GPIB_NDEVS)
33612379e3bSgmcgarry panic("gpib_alloc: device address out of range");
33712379e3bSgmcgarry #endif
33812379e3bSgmcgarry
33912379e3bSgmcgarry if (!gpib_isalloc(sc, address)) {
34012379e3bSgmcgarry sc->sc_rmap |= (1 << address);
34112379e3bSgmcgarry return (0);
34212379e3bSgmcgarry }
34312379e3bSgmcgarry return (1);
34412379e3bSgmcgarry }
34512379e3bSgmcgarry
34612379e3bSgmcgarry /*
34712379e3bSgmcgarry * Resource accounting: deallocate the address.
34812379e3bSgmcgarry */
34912379e3bSgmcgarry void
gpib_dealloc(struct gpib_softc * sc,u_int8_t address)350454af1c0Sdsl gpib_dealloc(struct gpib_softc *sc, u_int8_t address)
35112379e3bSgmcgarry {
35212379e3bSgmcgarry
35312379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpib_free: sc=%p address=%d\n", sc, address));
35412379e3bSgmcgarry
35512379e3bSgmcgarry #ifdef DIAGNOSTIC
35612379e3bSgmcgarry if (address >= GPIB_NDEVS)
35712379e3bSgmcgarry panic("gpib_free: device address out of range");
35812379e3bSgmcgarry
35912379e3bSgmcgarry if (!gpib_isalloc(sc, address))
36012379e3bSgmcgarry panic("gpib_free: not allocated");
36112379e3bSgmcgarry #endif
36212379e3bSgmcgarry
36312379e3bSgmcgarry sc->sc_rmap &= ~(1 << address);
36412379e3bSgmcgarry }
36512379e3bSgmcgarry
36612379e3bSgmcgarry int
_gpibsend(struct gpib_softc * sc,int slave,int sec,void * ptr,int origcnt)36782357f6dSdsl _gpibsend(struct gpib_softc *sc, int slave, int sec, void *ptr, int origcnt)
36812379e3bSgmcgarry {
36912379e3bSgmcgarry int rv;
37012379e3bSgmcgarry int cnt = 0;
37112379e3bSgmcgarry u_int8_t cmds[4];
37212379e3bSgmcgarry int i = 0;
37312379e3bSgmcgarry
37412379e3bSgmcgarry DPRINTF(DBG_FOLLOW,
37512379e3bSgmcgarry ("_gpibsend: sc=%p slave %d sec=%d ptr=%p cnt=%d\n",
37612379e3bSgmcgarry sc, slave, sec, ptr, origcnt));
37712379e3bSgmcgarry
37812379e3bSgmcgarry /*
37912379e3bSgmcgarry * For compatibility, call the hardware driver directly.
38012379e3bSgmcgarry */
38112379e3bSgmcgarry if (sc->sc_ic->send != NULL) {
38212379e3bSgmcgarry rv = (*sc->sc_ic->send)(sc->sc_ic->cookie,
38312379e3bSgmcgarry slave, sec, ptr, origcnt);
38412379e3bSgmcgarry return (rv);
38512379e3bSgmcgarry }
38612379e3bSgmcgarry
38712379e3bSgmcgarry if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
38812379e3bSgmcgarry goto senderror;
38912379e3bSgmcgarry cmds[i++] = GPIBCMD_UNL;
39012379e3bSgmcgarry cmds[i++] = GPIBCMD_TAG | sc->sc_myaddr;
39112379e3bSgmcgarry cmds[i++] = GPIBCMD_LAG | slave;
39212379e3bSgmcgarry if (sec >= 0 || sec == -2) {
39312379e3bSgmcgarry if (sec == -2) /* selected device clear KLUDGE */
39412379e3bSgmcgarry cmds[i++] = GPIBCMD_SDC;
39512379e3bSgmcgarry else
39612379e3bSgmcgarry cmds[i++] = GPIBCMD_SCG | sec;
39712379e3bSgmcgarry }
39812379e3bSgmcgarry if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, i) != i)
39912379e3bSgmcgarry goto senderror;
40012379e3bSgmcgarry if ((*sc->sc_ic->gts)(sc->sc_ic->cookie))
40112379e3bSgmcgarry goto senderror;
40212379e3bSgmcgarry if (origcnt) {
40312379e3bSgmcgarry cnt = (*sc->sc_ic->senddata)(sc->sc_ic->cookie, ptr, origcnt);
40412379e3bSgmcgarry if (cnt != origcnt)
40512379e3bSgmcgarry goto senderror;
40612379e3bSgmcgarry if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
40712379e3bSgmcgarry goto senderror;
40812379e3bSgmcgarry }
40912379e3bSgmcgarry return (origcnt);
41012379e3bSgmcgarry
41112379e3bSgmcgarry senderror:
41212379e3bSgmcgarry (*sc->sc_ic->ifc)(sc->sc_ic->cookie);
41312379e3bSgmcgarry DPRINTF(DBG_FAIL,
41412379e3bSgmcgarry ("%s: _gpibsend failed: slave %d, sec %x, sent %d of %d bytes\n",
415cbab9cadSchs device_xname(sc->sc_dev), slave, sec, cnt, origcnt));
41612379e3bSgmcgarry return (cnt);
41712379e3bSgmcgarry }
41812379e3bSgmcgarry
41912379e3bSgmcgarry int
_gpibrecv(struct gpib_softc * sc,int slave,int sec,void * ptr,int origcnt)42082357f6dSdsl _gpibrecv(struct gpib_softc *sc, int slave, int sec, void *ptr, int origcnt)
42112379e3bSgmcgarry {
42212379e3bSgmcgarry int rv;
42312379e3bSgmcgarry u_int8_t cmds[4];
42412379e3bSgmcgarry int cnt = 0;
42512379e3bSgmcgarry int i = 0;
42612379e3bSgmcgarry
42712379e3bSgmcgarry DPRINTF(DBG_FOLLOW,
42812379e3bSgmcgarry ("_gpibrecv: sc=%p slave=%d sec=%d buf=%p cnt=%d\n",
42912379e3bSgmcgarry sc, slave, sec, ptr, origcnt));
43012379e3bSgmcgarry
43112379e3bSgmcgarry /*
43212379e3bSgmcgarry * For compatibility, call the hardware driver directly.
43312379e3bSgmcgarry */
43412379e3bSgmcgarry if (sc->sc_ic->recv != NULL) {
43512379e3bSgmcgarry rv = (*sc->sc_ic->recv)(sc->sc_ic->cookie,
43612379e3bSgmcgarry slave, sec, ptr, origcnt);
43712379e3bSgmcgarry return (rv);
43812379e3bSgmcgarry }
43912379e3bSgmcgarry
44012379e3bSgmcgarry /*
44112379e3bSgmcgarry * slave < 0 implies continuation of a previous receive
44212379e3bSgmcgarry * that probably timed out.
44312379e3bSgmcgarry */
44412379e3bSgmcgarry if (slave >= 0) {
44512379e3bSgmcgarry if ((*sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
44612379e3bSgmcgarry goto recverror;
44712379e3bSgmcgarry cmds[i++] = GPIBCMD_UNL;
44812379e3bSgmcgarry cmds[i++] = GPIBCMD_LAG | sc->sc_myaddr;
44912379e3bSgmcgarry cmds[i++] = GPIBCMD_TAG | slave;
45012379e3bSgmcgarry if (sec >= 0)
45112379e3bSgmcgarry cmds[i++] = GPIBCMD_SCG | sec;
45212379e3bSgmcgarry if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, i) != i)
45312379e3bSgmcgarry goto recverror;
45412379e3bSgmcgarry if ((*sc->sc_ic->gts)(sc->sc_ic->cookie))
45512379e3bSgmcgarry goto recverror;
45612379e3bSgmcgarry }
45712379e3bSgmcgarry if (origcnt) {
45812379e3bSgmcgarry cnt = (*sc->sc_ic->recvdata)(sc->sc_ic->cookie, ptr, origcnt);
45912379e3bSgmcgarry if (cnt != origcnt)
46012379e3bSgmcgarry goto recverror;
46112379e3bSgmcgarry if ((sc->sc_ic->tc)(sc->sc_ic->cookie, 0))
46212379e3bSgmcgarry goto recverror;
46312379e3bSgmcgarry cmds[0] = (slave == GPIB_BROADCAST_ADDR) ?
46412379e3bSgmcgarry GPIBCMD_UNA : GPIBCMD_UNT;
46512379e3bSgmcgarry if ((*sc->sc_ic->sendcmds)(sc->sc_ic->cookie, cmds, 1) != 1)
46612379e3bSgmcgarry goto recverror;
46712379e3bSgmcgarry }
46812379e3bSgmcgarry return (origcnt);
46912379e3bSgmcgarry
47012379e3bSgmcgarry recverror:
47112379e3bSgmcgarry (*sc->sc_ic->ifc)(sc->sc_ic->cookie);
47212379e3bSgmcgarry DPRINTF(DBG_FAIL,
47312379e3bSgmcgarry ("_gpibrecv: failed, sc=%p slave %d, sec %x, got %d of %d bytes\n",
47412379e3bSgmcgarry sc, slave, sec, cnt, origcnt));
47512379e3bSgmcgarry return (cnt);
47612379e3bSgmcgarry }
47712379e3bSgmcgarry
47812379e3bSgmcgarry /*
47912379e3bSgmcgarry * /dev/gpib? interface
48012379e3bSgmcgarry */
48112379e3bSgmcgarry
48212379e3bSgmcgarry int
gpibopen(dev_t dev,int flags,int mode,struct lwp * l)4833e484e61Scegger gpibopen(dev_t dev, int flags, int mode, struct lwp *l)
48412379e3bSgmcgarry {
48512379e3bSgmcgarry struct gpib_softc *sc;
48612379e3bSgmcgarry
4873e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
48812379e3bSgmcgarry if (sc == NULL)
48912379e3bSgmcgarry return (ENXIO);
49012379e3bSgmcgarry
49112379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibopen: sc=%p\n", sc));
49212379e3bSgmcgarry
49312379e3bSgmcgarry if (sc->sc_flags & GPIBF_ACTIVE)
49412379e3bSgmcgarry return (EBUSY);
49512379e3bSgmcgarry sc->sc_flags |= GPIBF_ACTIVE;
49612379e3bSgmcgarry
49712379e3bSgmcgarry return (0);
49812379e3bSgmcgarry }
49912379e3bSgmcgarry
50012379e3bSgmcgarry int
gpibclose(dev_t dev,int flag,int mode,struct lwp * l)5013e484e61Scegger gpibclose(dev_t dev, int flag, int mode, struct lwp *l)
50212379e3bSgmcgarry {
50312379e3bSgmcgarry struct gpib_softc *sc;
50412379e3bSgmcgarry
5053e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
50612379e3bSgmcgarry if (sc == NULL)
50712379e3bSgmcgarry return (ENXIO);
50812379e3bSgmcgarry
50912379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibclose: sc=%p\n", sc));
51012379e3bSgmcgarry
51112379e3bSgmcgarry sc->sc_flags &= ~GPIBF_ACTIVE;
51212379e3bSgmcgarry
51312379e3bSgmcgarry return (0);
51412379e3bSgmcgarry }
51512379e3bSgmcgarry
51612379e3bSgmcgarry int
gpibread(dev_t dev,struct uio * uio,int flags)5173e484e61Scegger gpibread(dev_t dev, struct uio *uio, int flags)
51812379e3bSgmcgarry {
51912379e3bSgmcgarry struct gpib_softc *sc;
52012379e3bSgmcgarry
5213e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
52212379e3bSgmcgarry if (sc == NULL)
52312379e3bSgmcgarry return (ENXIO);
52412379e3bSgmcgarry
52512379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibread: sc=%p\n", sc));
52612379e3bSgmcgarry
52712379e3bSgmcgarry return (EOPNOTSUPP);
52812379e3bSgmcgarry }
52912379e3bSgmcgarry
53012379e3bSgmcgarry int
gpibwrite(dev_t dev,struct uio * uio,int flags)5313e484e61Scegger gpibwrite(dev_t dev, struct uio *uio, int flags)
53212379e3bSgmcgarry {
53312379e3bSgmcgarry struct gpib_softc *sc;
53412379e3bSgmcgarry
5353e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
53612379e3bSgmcgarry if (sc == NULL)
53712379e3bSgmcgarry return (ENXIO);
53812379e3bSgmcgarry
53912379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibwrite: sc=%p\n", sc));
54012379e3bSgmcgarry
54112379e3bSgmcgarry return (EOPNOTSUPP);
54212379e3bSgmcgarry }
54312379e3bSgmcgarry
54412379e3bSgmcgarry int
gpibioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)5453e484e61Scegger gpibioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
54612379e3bSgmcgarry {
54712379e3bSgmcgarry struct gpib_softc *sc;
54812379e3bSgmcgarry
5493e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
55012379e3bSgmcgarry if (sc == NULL)
55112379e3bSgmcgarry return (ENXIO);
55212379e3bSgmcgarry
55312379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibioctl(%lu, '%c',%lu): sc=%p\n",
55412379e3bSgmcgarry IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd & 0xff, sc));
55512379e3bSgmcgarry
55612379e3bSgmcgarry switch (cmd) {
55712379e3bSgmcgarry case GPIB_INFO:
55812379e3bSgmcgarry (*(int *)data) = 0xa5a5a5a5;
55912379e3bSgmcgarry break;
56012379e3bSgmcgarry }
56112379e3bSgmcgarry
56212379e3bSgmcgarry return (EINVAL);
56312379e3bSgmcgarry }
56412379e3bSgmcgarry
56512379e3bSgmcgarry int
gpibpoll(dev_t dev,int events,struct lwp * l)5663e484e61Scegger gpibpoll(dev_t dev, int events, struct lwp *l)
56712379e3bSgmcgarry {
56812379e3bSgmcgarry struct gpib_softc *sc;
56912379e3bSgmcgarry
5703e484e61Scegger sc = device_lookup_private(&gpib_cd, GPIBUNIT(dev));
57112379e3bSgmcgarry if (sc == NULL)
57212379e3bSgmcgarry return (ENXIO);
57312379e3bSgmcgarry
57412379e3bSgmcgarry DPRINTF(DBG_FOLLOW, ("gpibpoll: sc=%p\n", sc));
57512379e3bSgmcgarry
57612379e3bSgmcgarry return (0);
57712379e3bSgmcgarry }
578