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