1 /* $NetBSD: ppi.c,v 1.6 1994/10/26 07:24:46 cgd 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 ppiattach(), ppistart(); 55 void ppitimo(); 56 struct driver ppidriver = { 57 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 ppiattach(hd) 88 register struct hp_device *hd; 89 { 90 register struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; 91 92 #ifdef DEBUG 93 if ((ppidebug & PDB_NOCHECK) == 0) 94 #endif 95 /* 96 * XXX: the printer/plotter doesn't seem to really return 97 * an ID but this will at least prevent us from mistaking 98 * a cs80 disk or tape for a ppi device. 99 */ 100 if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200) 101 return(0); 102 sc->sc_flags = PPIF_ALIVE; 103 sc->sc_dq.dq_ctlr = hd->hp_ctlr; 104 sc->sc_dq.dq_unit = hd->hp_unit; 105 sc->sc_dq.dq_slave = hd->hp_slave; 106 sc->sc_dq.dq_driver = &ppidriver; 107 sc->sc_hd = hd; 108 return(1); 109 } 110 111 ppiopen(dev, flags) 112 dev_t dev; 113 { 114 register int unit = UNIT(dev); 115 register struct ppi_softc *sc = &ppi_softc[unit]; 116 117 if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0) 118 return(ENXIO); 119 #ifdef DEBUG 120 if (ppidebug & PDB_FOLLOW) 121 printf("ppiopen(%x, %x): flags %x\n", 122 dev, flags, sc->sc_flags); 123 #endif 124 if (sc->sc_flags & PPIF_OPEN) 125 return(EBUSY); 126 sc->sc_flags |= PPIF_OPEN; 127 sc->sc_burst = PPI_BURST; 128 sc->sc_timo = ppimstohz(PPI_TIMO); 129 sc->sc_delay = ppimstohz(PPI_DELAY); 130 sc->sc_sec = -1; 131 return(0); 132 } 133 134 ppiclose(dev, flags) 135 dev_t dev; 136 { 137 register int unit = UNIT(dev); 138 register struct ppi_softc *sc = &ppi_softc[unit]; 139 140 #ifdef DEBUG 141 if (ppidebug & PDB_FOLLOW) 142 printf("ppiclose(%x, %x): flags %x\n", 143 dev, flags, sc->sc_flags); 144 #endif 145 sc->sc_flags &= ~PPIF_OPEN; 146 return(0); 147 } 148 149 ppistart(unit) 150 int unit; 151 { 152 #ifdef DEBUG 153 if (ppidebug & PDB_FOLLOW) 154 printf("ppistart(%x)\n", unit); 155 #endif 156 ppi_softc[unit].sc_flags &= ~PPIF_DELAY; 157 wakeup(&ppi_softc[unit]); 158 return (0); 159 } 160 161 void 162 ppitimo(unit) 163 int unit; 164 { 165 #ifdef DEBUG 166 if (ppidebug & PDB_FOLLOW) 167 printf("ppitimo(%x)\n", unit); 168 #endif 169 ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO); 170 wakeup(&ppi_softc[unit]); 171 } 172 173 ppiread(dev, uio) 174 dev_t dev; 175 struct uio *uio; 176 { 177 178 #ifdef DEBUG 179 if (ppidebug & PDB_FOLLOW) 180 printf("ppiread(%x, %x)\n", dev, uio); 181 #endif 182 return (ppirw(dev, uio)); 183 } 184 185 ppiwrite(dev, uio) 186 dev_t dev; 187 struct uio *uio; 188 { 189 190 #ifdef DEBUG 191 if (ppidebug & PDB_FOLLOW) 192 printf("ppiwrite(%x, %x)\n", dev, uio); 193 #endif 194 return (ppirw(dev, uio)); 195 } 196 197 ppirw(dev, uio) 198 dev_t dev; 199 register struct uio *uio; 200 { 201 int unit = UNIT(dev); 202 register struct ppi_softc *sc = &ppi_softc[unit]; 203 register int s, len, cnt; 204 register char *cp; 205 int error = 0, gotdata = 0; 206 int buflen; 207 char *buf; 208 209 if (uio->uio_resid == 0) 210 return(0); 211 212 #ifdef DEBUG 213 if (ppidebug & (PDB_FOLLOW|PDB_IO)) 214 printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n", 215 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 216 sc->sc_burst, sc->sc_timo, uio->uio_resid); 217 #endif 218 buflen = min(sc->sc_burst, uio->uio_resid); 219 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 220 sc->sc_flags |= PPIF_UIO; 221 if (sc->sc_timo > 0) { 222 sc->sc_flags |= PPIF_TIMO; 223 timeout(ppitimo, (void *)unit, sc->sc_timo); 224 } 225 while (uio->uio_resid > 0) { 226 len = min(buflen, uio->uio_resid); 227 cp = buf; 228 if (uio->uio_rw == UIO_WRITE) { 229 error = uiomove(cp, len, uio); 230 if (error) 231 break; 232 } 233 again: 234 s = splbio(); 235 if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0) 236 sleep(sc, PRIBIO+1); 237 /* 238 * Check if we timed out during sleep or uiomove 239 */ 240 (void) splsoftclock(); 241 if ((sc->sc_flags & PPIF_UIO) == 0) { 242 #ifdef DEBUG 243 if (ppidebug & PDB_IO) 244 printf("ppirw: uiomove/sleep timo, flags %x\n", 245 sc->sc_flags); 246 #endif 247 if (sc->sc_flags & PPIF_TIMO) { 248 untimeout(ppitimo, (void *)unit); 249 sc->sc_flags &= ~PPIF_TIMO; 250 } 251 splx(s); 252 break; 253 } 254 splx(s); 255 /* 256 * Perform the operation 257 */ 258 if (uio->uio_rw == UIO_WRITE) 259 cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 260 sc->sc_sec, cp, len); 261 else 262 cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 263 sc->sc_sec, cp, len); 264 s = splbio(); 265 hpibfree(&sc->sc_dq); 266 #ifdef DEBUG 267 if (ppidebug & PDB_IO) 268 printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n", 269 uio->uio_rw == UIO_READ ? "recv" : "send", 270 sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 271 sc->sc_sec, cp, len, cnt); 272 #endif 273 splx(s); 274 if (uio->uio_rw == UIO_READ) { 275 if (cnt) { 276 error = uiomove(cp, cnt, uio); 277 if (error) 278 break; 279 gotdata++; 280 } 281 /* 282 * Didn't get anything this time, but did in the past. 283 * Consider us done. 284 */ 285 else if (gotdata) 286 break; 287 } 288 s = splsoftclock(); 289 /* 290 * Operation timeout (or non-blocking), quit now. 291 */ 292 if ((sc->sc_flags & PPIF_UIO) == 0) { 293 #ifdef DEBUG 294 if (ppidebug & PDB_IO) 295 printf("ppirw: timeout/done\n"); 296 #endif 297 splx(s); 298 break; 299 } 300 /* 301 * Implement inter-read delay 302 */ 303 if (sc->sc_delay > 0) { 304 sc->sc_flags |= PPIF_DELAY; 305 timeout((void (*)__P((void *)))ppistart, (void *)unit, 306 sc->sc_delay); 307 error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0); 308 if (error) { 309 splx(s); 310 break; 311 } 312 } 313 splx(s); 314 /* 315 * Must not call uiomove again til we've used all data 316 * that we already grabbed. 317 */ 318 if (uio->uio_rw == UIO_WRITE && cnt != len) { 319 cp += cnt; 320 len -= cnt; 321 cnt = 0; 322 goto again; 323 } 324 } 325 s = splsoftclock(); 326 if (sc->sc_flags & PPIF_TIMO) { 327 untimeout(ppitimo, (void *)unit); 328 sc->sc_flags &= ~PPIF_TIMO; 329 } 330 if (sc->sc_flags & PPIF_DELAY) { 331 untimeout((void (*)__P((void *)))ppistart, (void *)unit); 332 sc->sc_flags &= ~PPIF_DELAY; 333 } 334 splx(s); 335 /* 336 * Adjust for those chars that we uiomove'ed but never wrote 337 */ 338 if (uio->uio_rw == UIO_WRITE && cnt != len) { 339 uio->uio_resid += (len - cnt); 340 #ifdef DEBUG 341 if (ppidebug & PDB_IO) 342 printf("ppirw: short write, adjust by %d\n", 343 len-cnt); 344 #endif 345 } 346 free(buf, M_DEVBUF); 347 #ifdef DEBUG 348 if (ppidebug & (PDB_FOLLOW|PDB_IO)) 349 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid); 350 #endif 351 return (error); 352 } 353 354 ppiioctl(dev, cmd, data, flag, p) 355 dev_t dev; 356 int cmd; 357 caddr_t data; 358 int flag; 359 struct proc *p; 360 { 361 struct ppi_softc *sc = &ppi_softc[UNIT(dev)]; 362 struct ppiparam *pp, *upp; 363 int error = 0; 364 365 switch (cmd) { 366 case PPIIOCGPARAM: 367 pp = &sc->sc_param; 368 upp = (struct ppiparam *)data; 369 upp->burst = pp->burst; 370 upp->timo = ppihztoms(pp->timo); 371 upp->delay = ppihztoms(pp->delay); 372 break; 373 case PPIIOCSPARAM: 374 pp = &sc->sc_param; 375 upp = (struct ppiparam *)data; 376 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || 377 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) 378 return(EINVAL); 379 pp->burst = upp->burst; 380 pp->timo = ppimstohz(upp->timo); 381 pp->delay = ppimstohz(upp->delay); 382 break; 383 case PPIIOCSSEC: 384 sc->sc_sec = *(int *)data; 385 break; 386 default: 387 return(EINVAL); 388 } 389 return (error); 390 } 391 392 ppihztoms(h) 393 int h; 394 { 395 extern int hz; 396 register int m = h; 397 398 if (m > 0) 399 m = m * 1000 / hz; 400 return(m); 401 } 402 403 ppimstohz(m) 404 int m; 405 { 406 extern int hz; 407 register int h = m; 408 409 if (h > 0) { 410 h = h * hz / 1000; 411 if (h == 0) 412 h = 1000 / hz; 413 } 414 return(h); 415 } 416 #endif 417