Home | History | Annotate | Line # | Download | only in gpib
cs80bus.c revision 1.1
      1 /*	$NetBSD: cs80bus.c,v 1.1 2003/06/02 03:51:04 gmcgarry Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Gregory McGarry.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: cs80bus.c,v 1.1 2003/06/02 03:51:04 gmcgarry Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/device.h>
     45 #include <sys/endian.h>
     46 #include <sys/malloc.h>
     47 
     48 #include <dev/gpib/gpibvar.h>
     49 #include <dev/gpib/cs80busvar.h>
     50 
     51 #define DEBUG
     52 
     53 #ifdef DEBUG
     54 int cs80busdebug = 0xff;
     55 #define DBG_FOLLOW	0x01
     56 #define DBG_STATUS	0x02
     57 #define DBG_FAIL	0x04
     58 #define DPRINTF(mask, str)	if (cs80busdebug & (mask)) printf str
     59 #else
     60 #define DPRINTF(mask, str)	/* nothing */
     61 #endif
     62 
     63 #include "locators.h"
     64 #define	cs80buscf_slave		cf_loc[CS80BUSCF_SLAVE]
     65 #define	cs80buscf_punit		cf_loc[CS80BUSCF_PUNIT]
     66 
     67 int	cs80busmatch(struct device *, struct cfdata *, void *);
     68 void	cs80busattach(struct device *, struct device *, void *);
     69 
     70 CFATTACH_DECL(cs80bus, sizeof(struct cs80bus_softc),
     71 	cs80busmatch, cs80busattach, NULL, NULL);
     72 
     73 static int	cs80bus_alloc(struct cs80bus_softc *, int, int);
     74 static int	cs80bussearch(struct device *, struct cfdata *, void *);
     75 static int	cs80busprint(void *, const char *);
     76 
     77 /*
     78  * HP's CS80/SS80 command set can be found on `newer' devices, while
     79  * the HP's Amigo command set is used on before-you-were-born
     80  * devices.  Devices that respond to CS80/SS80 (and probably Amigo, too)
     81  * are tagged with a 16-bit ID.
     82  *
     83  * CS80/SS80 has a 2-level addressing scheme; slave, the analog
     84  * of a SCSI ID, and punit, the analog of a SCSI LUN.  Unforunately,
     85  * IDs are on a per-slave basis; punits are often used for disk
     86  * drives that have an accompanying tape drive on the second punit.
     87  *
     88  * We treat CS80/SS80 as an indirect bus.  However, since we are given
     89  * some ID information, it is unreasonable to disallow cloning of
     90  * CS80/SS80 devices.
     91  *
     92  * To deal with all of this, we use the semi-twisted scheme
     93  * in cs80bus_attach_children().  For each GPIB slave, we loop
     94  * through all of the possibly-configured children, allowing
     95  * them to modify the punit parameter (but NOT the slave!).
     96  *
     97  */
     98 
     99 int
    100 cs80busmatch(parent, match, aux)
    101 	struct device *parent;
    102 	struct cfdata *match;
    103 	void *aux;
    104 {
    105 
    106 	return (1);
    107 }
    108 
    109 void
    110 cs80busattach(parent, self, aux)
    111 	struct device *parent, *self;
    112 	void *aux;
    113 {
    114 	struct cs80bus_softc *sc = (struct cs80bus_softc *)self;
    115 	struct gpib_attach_args *ga = aux;
    116 	struct cs80bus_attach_args ca;
    117 	int slave;
    118 	u_int16_t id;
    119 
    120 	printf("\n");
    121 
    122 	sc->sc_ic = ga->ga_ic;
    123 
    124 	for (slave = 0; slave < 8; slave++) {
    125 
    126 		if (gpib_isalloc((void *)sc->sc_dev.dv_parent, slave))
    127 			continue;
    128 
    129 		if (gpibrecv(sc->sc_ic, GPIB_BROADCAST_ADDR,
    130 		    slave, &id, 2) != 2)
    131 			continue;
    132 
    133 		BE16TOH(id);
    134 
    135 		DPRINTF(DBG_STATUS, ("cs80busattach: found id 0x%x\n", id));
    136 
    137 		if ((id & 0x200) == 0)
    138 			continue;
    139 
    140 		ca.ca_ic = sc->sc_ic;
    141 		ca.ca_slave = slave;
    142 		ca.ca_id = id;
    143 
    144 		(void)config_search(cs80bussearch, &sc->sc_dev, &ca);
    145 	}
    146 }
    147 
    148 int
    149 cs80bussearch(parent, cf, aux)
    150 	struct device *parent;
    151 	struct cfdata *cf;
    152 	void *aux;
    153 {
    154 	struct cs80bus_softc *sc = (struct cs80bus_softc *)parent;
    155 	struct cs80bus_attach_args *ca = aux;
    156 
    157 	/*
    158 	 * Set punit if operator specified one in the kernel
    159 	 * configuration file.
    160 	 */
    161 	if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT &&
    162 	    cf->cs80buscf_punit < CS80BUS_NPUNITS)
    163 		ca->ca_punit = cf->cs80buscf_punit;
    164 	else
    165 		/* default punit */
    166 		ca->ca_punit = 0;
    167 
    168 	DPRINTF(DBG_FOLLOW, ("cs80bussearch: id=0x%x slave=%d punit=%d\n",
    169 	    ca->ca_id, ca->ca_slave, ca->ca_punit));
    170 
    171 	if (config_match(parent, cf, ca) > 0) {
    172 
    173 		DPRINTF(DBG_FOLLOW,
    174 		    ("cs80bussearch: got id=0x%x slave=%d punit %d\n",
    175 		    ca->ca_id, ca->ca_slave, ca->ca_punit));
    176 
    177 		/*
    178 		 * The device probe has succeeded, and filled in
    179 		 * the punit information.  Make sure the configuration
    180 		 * allows for this slave/punit combination.
    181 		 */
    182 		if (cf->cs80buscf_slave != CS80BUSCF_SLAVE_DEFAULT &&
    183 		    cf->cs80buscf_slave != ca->ca_slave)
    184 			goto out;
    185 		if (cf->cs80buscf_punit != CS80BUSCF_PUNIT_DEFAULT &&
    186 		    cf->cs80buscf_punit != ca->ca_punit)
    187 			goto out;
    188 
    189 		/*
    190 		 * Allocate the device's address from the bus's
    191 		 * resource map.
    192 		 */
    193 		if (cs80bus_alloc(sc, ca->ca_slave, ca->ca_punit))
    194 			goto out;
    195 
    196 		/*
    197 		 * This device is allowed; attach it.
    198 		 */
    199 		config_attach(parent, cf, ca, cs80busprint);
    200 	}
    201 out:
    202 	return (0);
    203 }
    204 
    205 int
    206 cs80busprint(aux, pnp)
    207 	void *aux;
    208 	const char *pnp;
    209 {
    210 	struct cs80bus_attach_args *ca = aux;
    211 
    212 	printf(" slave %d punit %d", ca->ca_slave, ca->ca_punit);
    213 	return (UNCONF);
    214 }
    215 
    216 static int
    217 cs80bus_alloc(sc, slave, punit)
    218 	struct cs80bus_softc *sc;
    219 	int slave, punit;
    220 {
    221 
    222 	DPRINTF(DBG_FOLLOW, ("cs80bus_alloc: sc=%p\n", sc));
    223 
    224 	if (slave >= CS80BUS_NSLAVES || punit >= CS80BUS_NPUNITS)
    225 		panic("cs80bus_alloc: device address out of range");
    226 
    227 	gpib_alloc((void *)sc->sc_dev.dv_parent, slave);
    228 
    229 	if (sc->sc_rmap[slave][punit] == 0) {
    230 		sc->sc_rmap[slave][punit] = 1;
    231 		return (0);
    232 	}
    233 	return (1);
    234 }
    235 
    236 
    237 
    238 /*
    239  *  CS80/SS80 (secondary) command functions
    240  */
    241 
    242 int
    243 cs80describe(v, slave, punit, csd)
    244 	void *v;
    245 	int slave;
    246 	int punit;
    247 	struct cs80_description *csd;
    248 {
    249 	struct cs80bus_softc *sc = v;
    250 	struct cs80_describecmd desc;
    251 	u_int8_t stat;
    252 
    253 	DPRINTF(DBG_FOLLOW, ("cs80describe: sc=%p slave=%d\n", sc, slave));
    254 
    255         /*
    256          * Note command is always issued to unit 0.
    257          */
    258 
    259         desc.c_unit = CS80CMD_SUNIT(0);
    260         desc.c_vol = CS80CMD_SVOL(0);
    261 	desc.c_cmd = CS80CMD_DESC;
    262         (void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &desc, sizeof(desc));
    263         (void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, csd, sizeof(*csd));
    264         (void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
    265 	if (stat != 0) {
    266 		DPRINTF(DBG_FAIL, ("cs80describe: failed, stat=0x%x\n", stat));
    267 		return (1);
    268 	}
    269 	BE16TOH(csd->d_iuw);
    270 	BE16TOH(csd->d_cmaxxfr);
    271 	BE16TOH(csd->d_sectsize);
    272 	BE16TOH(csd->d_blocktime);
    273 	BE16TOH(csd->d_uavexfr);
    274 	BE16TOH(csd->d_retry);
    275 	BE16TOH(csd->d_access);
    276 	BE32TOH(csd->d_maxcylhead);
    277 	BE16TOH(csd->d_maxsect);
    278 	BE16TOH(csd->d_maxvsecth);
    279 	BE32TOH(csd->d_maxvsectl);
    280 
    281 	return (0);
    282 }
    283 
    284 int
    285 cs80reset(v, slave, punit)
    286 	void *v;
    287 	int slave;
    288 	int punit;
    289 {
    290 	struct cs80bus_softc *sc = v;
    291 	struct cs80_clearcmd clear;
    292 	struct cs80_srcmd sr;
    293 	struct cs80_ssmcmd ssm;
    294 
    295 	DPRINTF(DBG_FOLLOW, ("cs80reset: sc=%p slave=%d punit=%d\n", sc,
    296 	    slave, punit));
    297 
    298 	clear.c_unit = CS80CMD_SUNIT(punit);
    299 	clear.c_cmd = CS80CMD_CLEAR;
    300 	if (cs80send(sc, slave, punit, CS80CMD_TCMD, &clear, sizeof(clear))) {
    301 		DPRINTF(DBG_FAIL, ("cs80reset: CLEAR failed\n"));
    302 		return (1);
    303 	}
    304 
    305 	sr.c_unit = CS80CMD_SUNIT(15);		/* XXX */
    306 	sr.c_nop = CS80CMD_NOP;
    307 	sr.c_cmd = CS80CMD_SREL;
    308 	sr.c_param = 0xc0;			/* XXX */
    309 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &sr, sizeof(sr))) {
    310 		DPRINTF(DBG_FAIL, ("cs80reset: SREL failed\n"));
    311 		return (1);
    312 	}
    313 
    314 	ssm.c_unit = CS80CMD_SUNIT(punit);
    315 	ssm.c_cmd = CS80CMD_SSM;
    316 	ssm.c_refm = htobe16(REF_MASK);
    317 	ssm.c_fefm = htobe16(FEF_MASK);
    318 	ssm.c_aefm = htobe16(AEF_MASK);
    319 	ssm.c_iefm = htobe16(IEF_MASK);
    320 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &ssm, sizeof(ssm))) {
    321 		DPRINTF(DBG_FAIL, ("cs80reset: SSM failed\n"));
    322 		return (1);
    323 	}
    324 
    325 	return (0);
    326 }
    327 
    328 int
    329 cs80status(v, slave, punit, css)
    330 	void *v;
    331 	int slave;
    332 	int punit;
    333 	struct cs80_stat *css;
    334 {
    335 	struct cs80bus_softc *sc = v;
    336 	struct cs80_statuscmd rs;
    337 	u_int8_t stat;
    338 
    339 	rs.c_unit = CS80CMD_SUNIT(punit);
    340 	rs.c_sram = CS80CMD_SRAM;
    341 	rs.c_param = 0;		/* single vector (i.e. sector number) */
    342 	rs.c_cmd = CS80CMD_STATUS;
    343 	memset((caddr_t)css, 0, sizeof(*css));
    344 	(void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &rs, sizeof(rs));
    345 	(void) gpibrecv(sc->sc_ic, slave, CS80CMD_EXEC, css, sizeof(*css));
    346 	(void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
    347 	if (stat != 0) {
    348 		DPRINTF(DBG_FAIL, ("cs80status: failed, stat=0x%x\n", stat));
    349 		return (1);
    350 	}
    351 	BE16TOH(css->c_ref);
    352 	BE16TOH(css->c_fef);
    353 	BE16TOH(css->c_aef);
    354 	BE16TOH(css->c_ief);
    355 	BE32TOH(css->c_blk);
    356 
    357 	return (0);
    358 }
    359 
    360 int
    361 cs80setoptions(v, slave, punit, options)
    362 	void *v;
    363 	int slave;
    364 	int punit;
    365 	u_int8_t options;
    366 {
    367 	struct cs80bus_softc *sc = v;
    368 	struct cs80_soptcmd opt;
    369 
    370 	opt.c_unit = CS80CMD_SUNIT(punit);
    371 	opt.c_nop = CS80CMD_NOP;
    372 	opt.c_opt = CS80CMD_SOPT;
    373 	opt.c_param = options;
    374 	if (cs80send(sc, slave, punit, CS80CMD_SCMD, &opt, sizeof(opt))) {
    375 		DPRINTF(DBG_FAIL, ("cs80setoptions: failed\n"));
    376 		return (1);
    377 	}
    378 
    379 	return (0);
    380 }
    381 
    382 int
    383 cs80send(v, slave, punit, cmd, ptr, cnt)
    384 	void *v;
    385 	int slave;
    386 	int punit;
    387 	int cmd;
    388 	void *ptr;
    389 	int cnt;
    390 {
    391 	struct cs80bus_softc *sc = v;
    392 	u_int8_t *buf = ptr;
    393 	u_int8_t stat;
    394 
    395 	DPRINTF(DBG_FOLLOW,
    396 	    ("cs80send: sc=%p slave=%d punit=%d cmd=%d ptr=%p cnt=%d\n", sc,
    397 	    slave, punit, cmd, buf, cnt));
    398 
    399 	if (gpibsend(sc->sc_ic, slave, cmd, buf, cnt) != cnt) {
    400 		DPRINTF(DBG_FAIL, ("cs80send: SCMD failed\n"));
    401 		return (1);
    402 	}
    403 	if (gpibswait(sc->sc_ic, slave)) {
    404 		DPRINTF(DBG_FAIL, ("cs80send: wait failed\n"));
    405 		return (1);
    406 	}
    407 	if (gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1) != 1) {
    408 		DPRINTF(DBG_FAIL, ("cs80send: QSTAT failed\n"));
    409 		return (1);
    410 	}
    411 	if (stat != 0) {
    412 		DPRINTF(DBG_FAIL, ("cs80send: failed, stat=0x%x\n", stat));
    413 		return (1);
    414 	}
    415 
    416 	return (0);
    417 }
    418