1 /* $NetBSD: ppi.c,v 1.10 1996/10/13 03:14:20 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ppi.c 8.1 (Berkeley) 6/16/93 36 */ 37 38 /* 39 * Printer/Plotter HPIB interface 40 */ 41 42 #include "ppi.h" 43 #if NPPI > 0 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/errno.h> 48 #include <sys/uio.h> 49 #include <sys/malloc.h> 50 51 #include <hp300/dev/device.h> 52 #include <hp300/dev/ppiioctl.h> 53 54 int ppimatch(), ppistart(); 55 void ppiattach(), ppitimo(); 56 struct driver ppidriver = { 57 ppimatch, ppiattach, "ppi", ppistart, 58 }; 59 60 struct ppi_softc { 61 int sc_flags; 62 struct devqueue sc_dq; 63 struct hp_device *sc_hd; 64 struct ppiparam sc_param; 65 #define sc_burst sc_param.burst 66 #define sc_timo sc_param.timo 67 #define sc_delay sc_param.delay 68 int sc_sec; 69 } ppi_softc[NPPI]; 70 71 /* sc_flags values */ 72 #define PPIF_ALIVE 0x01 73 #define PPIF_OPEN 0x02 74 #define PPIF_UIO 0x04 75 #define PPIF_TIMO 0x08 76 #define PPIF_DELAY 0x10 77 78 #define UNIT(x) minor(x) 79 80 #ifdef DEBUG 81 int ppidebug = 0x80; 82 #define PDB_FOLLOW 0x01 83 #define PDB_IO 0x02 84 #define PDB_NOCHECK 0x80 85 #endif 86 87 int 88 ppimatch(hd) 89 register struct hp_device *hd; 90 { 91 register struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; 92 93 #ifdef DEBUG 94 if ((ppidebug & PDB_NOCHECK) == 0) 95 #endif 96 /* 97 * XXX: the printer/plotter doesn't seem to really return 98 * an ID but this will at least prevent us from mistaking 99 * a cs80 disk or tape for a ppi device. 100 */ 101 if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200) 102 return (0); 103 104 sc->sc_hd = hd; 105 return (1); 106 } 107 108 void 109 ppiattach(hd) 110 register struct hp_device *hd; 111 { 112 struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; 113 114 printf("\n"); 115 116 sc->sc_flags = PPIF_ALIVE; 117 sc->sc_dq.dq_softc = sc; 118 sc->sc_dq.dq_ctlr = hd->hp_ctlr; 119 sc->sc_dq.dq_unit = hd->hp_unit; 120 sc->sc_dq.dq_slave = hd->hp_slave; 121 sc->sc_dq.dq_driver = &ppidriver; 122 } 123 124 ppiopen(dev, flags) 125 dev_t dev; 126 { 127 register int unit = UNIT(dev); 128 register struct ppi_softc *sc = &ppi_softc[unit]; 129 130 if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0) 131 return(ENXIO); 132 #ifdef DEBUG 133 if (ppidebug & PDB_FOLLOW) 134 printf("ppiopen(%x, %x): flags %x\n", 135 dev, flags, sc->sc_flags); 136 #endif 137 if (sc->sc_flags & PPIF_OPEN) 138 return(EBUSY); 139 sc->sc_flags |= PPIF_OPEN; 140 sc->sc_burst = PPI_BURST; 141 sc->sc_timo = ppimstohz(PPI_TIMO); 142 sc->sc_delay = ppimstohz(PPI_DELAY); 143 sc->sc_sec = -1; 144 return(0); 145 } 146 147 ppiclose(dev, flags) 148 dev_t dev; 149 { 150 register int unit = UNIT(dev); 151 register struct ppi_softc *sc = &ppi_softc[unit]; 152 153 #ifdef DEBUG 154 if (ppidebug & PDB_FOLLOW) 155 printf("ppiclose(%x, %x): flags %x\n", 156 dev, flags, sc->sc_flags); 157 #endif 158 sc->sc_flags &= ~PPIF_OPEN; 159 return(0); 160 } 161 162 ppistart(unit) 163 int unit; 164 { 165 #ifdef DEBUG 166 if (ppidebug & PDB_FOLLOW) 167 printf("ppistart(%x)\n", unit); 168 #endif 169 ppi_softc[unit].sc_flags &= ~PPIF_DELAY; 170 wakeup(&ppi_softc[unit]); 171 return (0); 172 } 173 174 void 175 ppitimo(unit) 176 int unit; 177 { 178 #ifdef DEBUG 179 if (ppidebug & PDB_FOLLOW) 180 printf("ppitimo(%x)\n", unit); 181 #endif 182 ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO); 183 wakeup(&ppi_softc[unit]); 184 } 185 186 ppiread(dev, uio) 187 dev_t dev; 188 struct uio *uio; 189 { 190 191 #ifdef DEBUG 192 if (ppidebug & PDB_FOLLOW) 193 printf("ppiread(%x, %x)\n", dev, uio); 194 #endif 195 return (ppirw(dev, uio)); 196 } 197 198 ppiwrite(dev, uio) 199 dev_t dev; 200 struct uio *uio; 201 { 202 203 #ifdef DEBUG 204 if (ppidebug & PDB_FOLLOW) 205 printf("ppiwrite(%x, %x)\n", dev, uio); 206 #endif 207 return (ppirw(dev, uio)); 208 } 209 210 ppirw(dev, uio) 211 dev_t dev; 212 register struct uio *uio; 213 { 214 int unit = UNIT(dev); 215 register struct ppi_softc *sc = &ppi_softc[unit]; 216 register int s, len, cnt; 217 register char *cp; 218 int error = 0, gotdata = 0; 219 int buflen; 220 char *buf; 221 222 if (uio->uio_resid == 0) 223 return(0); 224 225 #ifdef DEBUG 226 if (ppidebug & (PDB_FOLLOW|PDB_IO)) 227 printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n", 228 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 229 sc->sc_burst, sc->sc_timo, uio->uio_resid); 230 #endif 231 buflen = min(sc->sc_burst, uio->uio_resid); 232 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 233 sc->sc_flags |= PPIF_UIO; 234 if (sc->sc_timo > 0) { 235 sc->sc_flags |= PPIF_TIMO; 236 timeout(ppitimo, (void *)unit, sc->sc_timo); 237 } 238 while (uio->uio_resid > 0) { 239 len = min(buflen, uio->uio_resid); 240 cp = buf; 241 if (uio->uio_rw == UIO_WRITE) { 242 error = uiomove(cp, len, uio); 243 if (error) 244 break; 245 } 246 again: 247 s = splbio(); 248 if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0) 249 sleep(sc, PRIBIO+1); 250 /* 251 * Check if we timed out during sleep or uiomove 252 */ 253 (void) splsoftclock(); 254 if ((sc->sc_flags & PPIF_UIO) == 0) { 255 #ifdef DEBUG 256 if (ppidebug & PDB_IO) 257 printf("ppirw: uiomove/sleep timo, flags %x\n", 258 sc->sc_flags); 259 #endif 260 if (sc->sc_flags & PPIF_TIMO) { 261 untimeout(ppitimo, (void *)unit); 262 sc->sc_flags &= ~PPIF_TIMO; 263 } 264 splx(s); 265 break; 266 } 267 splx(s); 268 /* 269 * Perform the operation 270 */ 271 if (uio->uio_rw == UIO_WRITE) 272 cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 273 sc->sc_sec, cp, len); 274 else 275 cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 276 sc->sc_sec, cp, len); 277 s = splbio(); 278 hpibfree(&sc->sc_dq); 279 #ifdef DEBUG 280 if (ppidebug & PDB_IO) 281 printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n", 282 uio->uio_rw == UIO_READ ? "recv" : "send", 283 sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 284 sc->sc_sec, cp, len, cnt); 285 #endif 286 splx(s); 287 if (uio->uio_rw == UIO_READ) { 288 if (cnt) { 289 error = uiomove(cp, cnt, uio); 290 if (error) 291 break; 292 gotdata++; 293 } 294 /* 295 * Didn't get anything this time, but did in the past. 296 * Consider us done. 297 */ 298 else if (gotdata) 299 break; 300 } 301 s = splsoftclock(); 302 /* 303 * Operation timeout (or non-blocking), quit now. 304 */ 305 if ((sc->sc_flags & PPIF_UIO) == 0) { 306 #ifdef DEBUG 307 if (ppidebug & PDB_IO) 308 printf("ppirw: timeout/done\n"); 309 #endif 310 splx(s); 311 break; 312 } 313 /* 314 * Implement inter-read delay 315 */ 316 if (sc->sc_delay > 0) { 317 sc->sc_flags |= PPIF_DELAY; 318 timeout((void (*)__P((void *)))ppistart, (void *)unit, 319 sc->sc_delay); 320 error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0); 321 if (error) { 322 splx(s); 323 break; 324 } 325 } 326 splx(s); 327 /* 328 * Must not call uiomove again til we've used all data 329 * that we already grabbed. 330 */ 331 if (uio->uio_rw == UIO_WRITE && cnt != len) { 332 cp += cnt; 333 len -= cnt; 334 cnt = 0; 335 goto again; 336 } 337 } 338 s = splsoftclock(); 339 if (sc->sc_flags & PPIF_TIMO) { 340 untimeout(ppitimo, (void *)unit); 341 sc->sc_flags &= ~PPIF_TIMO; 342 } 343 if (sc->sc_flags & PPIF_DELAY) { 344 untimeout((void (*)__P((void *)))ppistart, (void *)unit); 345 sc->sc_flags &= ~PPIF_DELAY; 346 } 347 splx(s); 348 /* 349 * Adjust for those chars that we uiomove'ed but never wrote 350 */ 351 if (uio->uio_rw == UIO_WRITE && cnt != len) { 352 uio->uio_resid += (len - cnt); 353 #ifdef DEBUG 354 if (ppidebug & PDB_IO) 355 printf("ppirw: short write, adjust by %d\n", 356 len-cnt); 357 #endif 358 } 359 free(buf, M_DEVBUF); 360 #ifdef DEBUG 361 if (ppidebug & (PDB_FOLLOW|PDB_IO)) 362 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid); 363 #endif 364 return (error); 365 } 366 367 ppiioctl(dev, cmd, data, flag, p) 368 dev_t dev; 369 int cmd; 370 caddr_t data; 371 int flag; 372 struct proc *p; 373 { 374 struct ppi_softc *sc = &ppi_softc[UNIT(dev)]; 375 struct ppiparam *pp, *upp; 376 int error = 0; 377 378 switch (cmd) { 379 case PPIIOCGPARAM: 380 pp = &sc->sc_param; 381 upp = (struct ppiparam *)data; 382 upp->burst = pp->burst; 383 upp->timo = ppihztoms(pp->timo); 384 upp->delay = ppihztoms(pp->delay); 385 break; 386 case PPIIOCSPARAM: 387 pp = &sc->sc_param; 388 upp = (struct ppiparam *)data; 389 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || 390 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) 391 return(EINVAL); 392 pp->burst = upp->burst; 393 pp->timo = ppimstohz(upp->timo); 394 pp->delay = ppimstohz(upp->delay); 395 break; 396 case PPIIOCSSEC: 397 sc->sc_sec = *(int *)data; 398 break; 399 default: 400 return(EINVAL); 401 } 402 return (error); 403 } 404 405 ppihztoms(h) 406 int h; 407 { 408 extern int hz; 409 register int m = h; 410 411 if (m > 0) 412 m = m * 1000 / hz; 413 return(m); 414 } 415 416 ppimstohz(m) 417 int m; 418 { 419 extern int hz; 420 register int h = m; 421 422 if (h > 0) { 423 h = h * hz / 1000; 424 if (h == 0) 425 h = 1000 / hz; 426 } 427 return(h); 428 } 429 #endif 430