1 /* $NetBSD: ppi.c,v 1.22 2014/07/25 08:10:36 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1996-2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1990, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)ppi.c 8.1 (Berkeley) 6/16/93 61 */ 62 63 /* 64 * Printer/Plotter GPIB interface 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: ppi.c,v 1.22 2014/07/25 08:10:36 dholland Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/systm.h> 72 #include <sys/callout.h> 73 #include <sys/conf.h> 74 #include <sys/device.h> 75 #include <sys/malloc.h> 76 #include <sys/proc.h> 77 #include <sys/uio.h> 78 79 #include <dev/gpib/gpibvar.h> 80 81 #include <dev/gpib/ppiio.h> 82 83 struct ppi_softc { 84 device_t sc_dev; 85 gpib_chipset_tag_t sc_ic; 86 gpib_handle_t sc_hdl; 87 88 int sc_address; /* GPIB address */ 89 int sc_flags; 90 int sc_sec; 91 struct ppiparam sc_param; 92 #define sc_burst sc_param.burst 93 #define sc_timo sc_param.timo 94 #define sc_delay sc_param.delay 95 struct callout sc_timo_ch; 96 struct callout sc_start_ch; 97 }; 98 99 /* sc_flags values */ 100 #define PPIF_ALIVE 0x01 101 #define PPIF_OPEN 0x02 102 #define PPIF_UIO 0x04 103 #define PPIF_TIMO 0x08 104 #define PPIF_DELAY 0x10 105 106 int ppimatch(device_t, cfdata_t, void *); 107 void ppiattach(device_t, device_t, void *); 108 109 CFATTACH_DECL_NEW(ppi, sizeof(struct ppi_softc), 110 ppimatch, ppiattach, NULL, NULL); 111 112 extern struct cfdriver ppi_cd; 113 114 void ppicallback(void *, int); 115 void ppistart(void *); 116 117 void ppitimo(void *); 118 int ppirw(dev_t, struct uio *); 119 int ppihztoms(int); 120 int ppimstohz(int); 121 122 dev_type_open(ppiopen); 123 dev_type_close(ppiclose); 124 dev_type_read(ppiread); 125 dev_type_write(ppiwrite); 126 dev_type_ioctl(ppiioctl); 127 128 const struct cdevsw ppi_cdevsw = { 129 .d_open = ppiopen, 130 .d_close = ppiclose, 131 .d_read = ppiread, 132 .d_write = ppiwrite, 133 .d_ioctl = ppiioctl, 134 .d_stop = nostop, 135 .d_tty = notty, 136 .d_poll = nopoll, 137 .d_mmap = nommap, 138 .d_kqfilter = nokqfilter, 139 .d_discard = nodiscard, 140 .d_flag = D_OTHER 141 }; 142 143 #define UNIT(x) minor(x) 144 145 #ifdef DEBUG 146 int ppidebug = 0x80; 147 #define PDB_FOLLOW 0x01 148 #define PDB_IO 0x02 149 #define PDB_NOCHECK 0x80 150 #define DPRINTF(mask, str) if (ppidebug & (mask)) printf str 151 #else 152 #define DPRINTF(mask, str) /* nothing */ 153 #endif 154 155 int 156 ppimatch(device_t parent, cfdata_t match, void *aux) 157 { 158 159 return (1); 160 } 161 162 void 163 ppiattach(device_t parent, device_t self, void *aux) 164 { 165 struct ppi_softc *sc = device_private(self); 166 struct gpib_attach_args *ga = aux; 167 168 printf("\n"); 169 170 sc->sc_ic = ga->ga_ic; 171 sc->sc_address = ga->ga_address; 172 173 callout_init(&sc->sc_timo_ch, 0); 174 callout_init(&sc->sc_start_ch, 0); 175 176 if (gpibregister(sc->sc_ic, sc->sc_address, ppicallback, sc, 177 &sc->sc_hdl)) { 178 aprint_error_dev(sc->sc_dev, "can't register callback\n"); 179 return; 180 } 181 182 sc->sc_flags = PPIF_ALIVE; 183 } 184 185 int 186 ppiopen(dev_t dev, int flags, int fmt, struct lwp *l) 187 { 188 struct ppi_softc *sc; 189 190 sc = device_lookup_private(&ppi_cd, UNIT(dev)); 191 if (sc == NULL) 192 return (ENXIO); 193 194 if ((sc->sc_flags & PPIF_ALIVE) == 0) 195 return (ENXIO); 196 197 DPRINTF(PDB_FOLLOW, ("ppiopen(%" PRIx64 ", %x): flags %x\n", 198 dev, flags, sc->sc_flags)); 199 200 if (sc->sc_flags & PPIF_OPEN) 201 return (EBUSY); 202 sc->sc_flags |= PPIF_OPEN; 203 sc->sc_burst = PPI_BURST; 204 sc->sc_timo = ppimstohz(PPI_TIMO); 205 sc->sc_delay = ppimstohz(PPI_DELAY); 206 sc->sc_sec = -1; 207 return (0); 208 } 209 210 int 211 ppiclose(dev_t dev, int flags, int fmt, struct lwp *l) 212 { 213 struct ppi_softc *sc; 214 215 sc = device_lookup_private(&ppi_cd, UNIT(dev)); 216 217 DPRINTF(PDB_FOLLOW, ("ppiclose(%" PRIx64 ", %x): flags %x\n", 218 dev, flags, sc->sc_flags)); 219 220 sc->sc_flags &= ~PPIF_OPEN; 221 return (0); 222 } 223 224 void 225 ppicallback(void *v, int action) 226 { 227 struct ppi_softc *sc = v; 228 229 DPRINTF(PDB_FOLLOW, ("ppicallback: v=%p, action=%d\n", v, action)); 230 231 switch (action) { 232 case GPIBCBF_START: 233 ppistart(sc); 234 case GPIBCBF_INTR: 235 /* no-op */ 236 break; 237 #ifdef DEBUG 238 default: 239 DPRINTF(PDB_FOLLOW, ("ppicallback: unknown action %d\n", 240 action)); 241 break; 242 #endif 243 } 244 } 245 246 void 247 ppistart(void *v) 248 { 249 struct ppi_softc *sc = v; 250 251 DPRINTF(PDB_FOLLOW, ("ppistart(%x)\n", device_unit(sc->sc_dev))); 252 253 sc->sc_flags &= ~PPIF_DELAY; 254 wakeup(sc); 255 } 256 257 void 258 ppitimo(void *arg) 259 { 260 struct ppi_softc *sc = arg; 261 262 DPRINTF(PDB_FOLLOW, ("ppitimo(%x)\n", device_unit(sc->sc_dev))); 263 264 sc->sc_flags &= ~(PPIF_UIO|PPIF_TIMO); 265 wakeup(sc); 266 } 267 268 int 269 ppiread(dev_t dev, struct uio *uio, int flags) 270 { 271 272 DPRINTF(PDB_FOLLOW, ("ppiread(%" PRIx64 ", %p)\n", dev, uio)); 273 274 return (ppirw(dev, uio)); 275 } 276 277 int 278 ppiwrite(dev_t dev, struct uio *uio, int flags) 279 { 280 281 DPRINTF(PDB_FOLLOW, ("ppiwrite(%" PRIx64 ", %p)\n", dev, uio)); 282 283 return (ppirw(dev, uio)); 284 } 285 286 int 287 ppirw(dev_t dev, struct uio *uio) 288 { 289 struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev)); 290 int s1, s2, len, cnt; 291 char *cp; 292 int error = 0, gotdata = 0; 293 int buflen, address; 294 char *buf; 295 296 if (uio->uio_resid == 0) 297 return (0); 298 299 address = sc->sc_address; 300 301 DPRINTF(PDB_FOLLOW|PDB_IO, 302 ("ppirw(%" PRIx64 ", %p, %c): burst %d, timo %d, resid %x\n", 303 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 304 sc->sc_burst, sc->sc_timo, uio->uio_resid)); 305 306 buflen = min(sc->sc_burst, uio->uio_resid); 307 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 308 sc->sc_flags |= PPIF_UIO; 309 if (sc->sc_timo > 0) { 310 sc->sc_flags |= PPIF_TIMO; 311 callout_reset(&sc->sc_timo_ch, sc->sc_timo, ppitimo, sc); 312 } 313 len = cnt = 0; 314 while (uio->uio_resid > 0) { 315 len = min(buflen, uio->uio_resid); 316 cp = buf; 317 if (uio->uio_rw == UIO_WRITE) { 318 error = uiomove(cp, len, uio); 319 if (error) 320 break; 321 } 322 again: 323 s1 = splsoftclock(); 324 s2 = splbio(); 325 if (sc->sc_flags & PPIF_UIO) { 326 if (gpibrequest(sc->sc_ic, sc->sc_hdl) == 0) 327 (void) tsleep(sc, PRIBIO + 1, "ppirw", 0); 328 } 329 /* 330 * Check if we timed out during sleep or uiomove 331 */ 332 splx(s2); 333 if ((sc->sc_flags & PPIF_UIO) == 0) { 334 DPRINTF(PDB_IO, 335 ("ppirw: uiomove/sleep timo, flags %x\n", 336 sc->sc_flags)); 337 if (sc->sc_flags & PPIF_TIMO) { 338 callout_stop(&sc->sc_timo_ch); 339 sc->sc_flags &= ~PPIF_TIMO; 340 } 341 splx(s1); 342 break; 343 } 344 splx(s1); 345 /* 346 * Perform the operation 347 */ 348 if (uio->uio_rw == UIO_WRITE) 349 cnt = gpibsend(sc->sc_ic, address, sc->sc_sec, 350 cp, len); 351 else 352 cnt = gpibrecv(sc->sc_ic, address, sc->sc_sec, 353 cp, len); 354 s1 = splbio(); 355 gpibrelease(sc->sc_ic, sc->sc_hdl); 356 DPRINTF(PDB_IO, ("ppirw: %s(%d, %x, %p, %d) -> %d\n", 357 uio->uio_rw == UIO_READ ? "recv" : "send", 358 address, sc->sc_sec, cp, len, cnt)); 359 splx(s1); 360 if (uio->uio_rw == UIO_READ) { 361 if (cnt) { 362 error = uiomove(cp, cnt, uio); 363 if (error) 364 break; 365 gotdata++; 366 } 367 /* 368 * Didn't get anything this time, but did in the past. 369 * Consider us done. 370 */ 371 else if (gotdata) 372 break; 373 } 374 s1 = splsoftclock(); 375 /* 376 * Operation timeout (or non-blocking), quit now. 377 */ 378 if ((sc->sc_flags & PPIF_UIO) == 0) { 379 DPRINTF(PDB_IO, ("ppirw: timeout/done\n")); 380 splx(s1); 381 break; 382 } 383 /* 384 * Implement inter-read delay 385 */ 386 if (sc->sc_delay > 0) { 387 sc->sc_flags |= PPIF_DELAY; 388 callout_reset(&sc->sc_start_ch, sc->sc_delay, 389 ppistart, sc); 390 error = tsleep(sc, (PCATCH|PZERO) + 1, "gpib", 0); 391 if (error) { 392 splx(s1); 393 break; 394 } 395 } 396 splx(s1); 397 /* 398 * Must not call uiomove again til we've used all data 399 * that we already grabbed. 400 */ 401 if (uio->uio_rw == UIO_WRITE && cnt != len) { 402 cp += cnt; 403 len -= cnt; 404 cnt = 0; 405 goto again; 406 } 407 } 408 s1 = splsoftclock(); 409 if (sc->sc_flags & PPIF_TIMO) { 410 callout_stop(&sc->sc_timo_ch); 411 sc->sc_flags &= ~PPIF_TIMO; 412 } 413 if (sc->sc_flags & PPIF_DELAY) { 414 callout_stop(&sc->sc_start_ch); 415 sc->sc_flags &= ~PPIF_DELAY; 416 } 417 splx(s1); 418 /* 419 * Adjust for those chars that we uiomove'ed but never wrote 420 */ 421 if (uio->uio_rw == UIO_WRITE && cnt != len) { 422 uio->uio_resid += (len - cnt); 423 DPRINTF(PDB_IO, ("ppirw: short write, adjust by %d\n", 424 len - cnt)); 425 } 426 free(buf, M_DEVBUF); 427 DPRINTF(PDB_FOLLOW|PDB_IO, ("ppirw: return %d, resid %d\n", 428 error, uio->uio_resid)); 429 return (error); 430 } 431 432 int 433 ppiioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 434 { 435 struct ppi_softc *sc = device_lookup_private(&ppi_cd, UNIT(dev)); 436 struct ppiparam *pp, *upp; 437 int error = 0; 438 439 switch (cmd) { 440 case PPIIOCGPARAM: 441 pp = &sc->sc_param; 442 upp = (struct ppiparam *)data; 443 upp->burst = pp->burst; 444 upp->timo = ppihztoms(pp->timo); 445 upp->delay = ppihztoms(pp->delay); 446 break; 447 case PPIIOCSPARAM: 448 pp = &sc->sc_param; 449 upp = (struct ppiparam *)data; 450 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || 451 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) 452 return (EINVAL); 453 pp->burst = upp->burst; 454 pp->timo = ppimstohz(upp->timo); 455 pp->delay = ppimstohz(upp->delay); 456 break; 457 case PPIIOCSSEC: 458 sc->sc_sec = *(int *)data; 459 break; 460 default: 461 return (EINVAL); 462 } 463 return (error); 464 } 465 466 int 467 ppihztoms(int h) 468 { 469 extern int hz; 470 int m = h; 471 472 if (m > 0) 473 m = m * 1000 / hz; 474 return (m); 475 } 476 477 int 478 ppimstohz(int m) 479 { 480 extern int hz; 481 int h = m; 482 483 if (h > 0) { 484 h = h * hz / 1000; 485 if (h == 0) 486 h = 1000 / hz; 487 } 488 return (h); 489 } 490