1 /* 2 * Copyright (c) 1982, 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)ppi.c 7.3 (Berkeley) 12/16/90 34 * $Id: ppi.c,v 1.4 1994/05/05 10:10:34 mycroft Exp $ 35 */ 36 37 /* 38 * Printer/Plotter HPIB interface 39 */ 40 41 #include "ppi.h" 42 #if NPPI > 0 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/errno.h> 47 #include <sys/uio.h> 48 #include <sys/malloc.h> 49 50 #include <hp300/dev/device.h> 51 #include <hp300/dev/ppiioctl.h> 52 53 int ppiattach(), ppistart(), ppitimo(); 54 struct driver ppidriver = { 55 ppiattach, "ppi", ppistart, 56 }; 57 58 struct ppi_softc { 59 int sc_flags; 60 struct devqueue sc_dq; 61 struct hp_device *sc_hd; 62 struct ppiparam sc_param; 63 #define sc_burst sc_param.burst 64 #define sc_timo sc_param.timo 65 #define sc_delay sc_param.delay 66 int sc_sec; 67 } ppi_softc[NPPI]; 68 69 /* sc_flags values */ 70 #define PPIF_ALIVE 0x01 71 #define PPIF_OPEN 0x02 72 #define PPIF_UIO 0x04 73 #define PPIF_TIMO 0x08 74 #define PPIF_DELAY 0x10 75 76 #define UNIT(x) minor(x) 77 78 #ifdef DEBUG 79 int ppidebug = 0x80; 80 #define PDB_FOLLOW 0x01 81 #define PDB_IO 0x02 82 #define PDB_NOCHECK 0x80 83 #endif 84 85 ppiattach(hd) 86 register struct hp_device *hd; 87 { 88 register struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; 89 90 #ifdef DEBUG 91 if ((ppidebug & PDB_NOCHECK) == 0) 92 #endif 93 /* 94 * XXX: the printer/plotter doesn't seem to really return 95 * an ID but this will at least prevent us from mistaking 96 * a cs80 disk or tape for a ppi device. 97 */ 98 if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200) 99 return(0); 100 sc->sc_flags = PPIF_ALIVE; 101 sc->sc_dq.dq_ctlr = hd->hp_ctlr; 102 sc->sc_dq.dq_unit = hd->hp_unit; 103 sc->sc_dq.dq_slave = hd->hp_slave; 104 sc->sc_dq.dq_driver = &ppidriver; 105 sc->sc_hd = hd; 106 return(1); 107 } 108 109 ppiopen(dev, flags) 110 dev_t dev; 111 { 112 register int unit = UNIT(dev); 113 register struct ppi_softc *sc = &ppi_softc[unit]; 114 115 if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0) 116 return(ENXIO); 117 #ifdef DEBUG 118 if (ppidebug & PDB_FOLLOW) 119 printf("ppiopen(%x, %x): flags %x\n", 120 dev, flags, sc->sc_flags); 121 #endif 122 if (sc->sc_flags & PPIF_OPEN) 123 return(EBUSY); 124 sc->sc_flags |= PPIF_OPEN; 125 sc->sc_burst = PPI_BURST; 126 sc->sc_timo = ppimstohz(PPI_TIMO); 127 sc->sc_delay = ppimstohz(PPI_DELAY); 128 sc->sc_sec = -1; 129 return(0); 130 } 131 132 ppiclose(dev, flags) 133 dev_t dev; 134 { 135 register int unit = UNIT(dev); 136 register struct ppi_softc *sc = &ppi_softc[unit]; 137 138 #ifdef DEBUG 139 if (ppidebug & PDB_FOLLOW) 140 printf("ppiclose(%x, %x): flags %x\n", 141 dev, flags, sc->sc_flags); 142 #endif 143 sc->sc_flags &= ~PPIF_OPEN; 144 return(0); 145 } 146 147 ppistart(arg) 148 void *arg; 149 { 150 int unit = (int)arg; 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 } 159 160 ppitimo(arg) 161 void *arg; 162 { 163 int unit = (int)arg; 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(ppistart, (void *)unit, sc->sc_delay); 306 error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0); 307 if (error) { 308 splx(s); 309 break; 310 } 311 } 312 splx(s); 313 /* 314 * Must not call uiomove again til we've used all data 315 * that we already grabbed. 316 */ 317 if (uio->uio_rw == UIO_WRITE && cnt != len) { 318 cp += cnt; 319 len -= cnt; 320 cnt = 0; 321 goto again; 322 } 323 } 324 s = splsoftclock(); 325 if (sc->sc_flags & PPIF_TIMO) { 326 untimeout(ppitimo, (void *)unit); 327 sc->sc_flags &= ~PPIF_TIMO; 328 } 329 if (sc->sc_flags & PPIF_DELAY) { 330 untimeout(ppistart, (void *)unit); 331 sc->sc_flags &= ~PPIF_DELAY; 332 } 333 splx(s); 334 /* 335 * Adjust for those chars that we uiomove'ed but never wrote 336 */ 337 if (uio->uio_rw == UIO_WRITE && cnt != len) { 338 uio->uio_resid += (len - cnt); 339 #ifdef DEBUG 340 if (ppidebug & PDB_IO) 341 printf("ppirw: short write, adjust by %d\n", 342 len-cnt); 343 #endif 344 } 345 free(buf, M_DEVBUF); 346 #ifdef DEBUG 347 if (ppidebug & (PDB_FOLLOW|PDB_IO)) 348 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid); 349 #endif 350 return (error); 351 } 352 353 ppiioctl(dev, cmd, data, flag, p) 354 dev_t dev; 355 int cmd; 356 caddr_t data; 357 int flag; 358 struct proc *p; 359 { 360 struct ppi_softc *sc = &ppi_softc[UNIT(dev)]; 361 struct ppiparam *pp, *upp; 362 int error = 0; 363 364 switch (cmd) { 365 case PPIIOCGPARAM: 366 pp = &sc->sc_param; 367 upp = (struct ppiparam *)data; 368 upp->burst = pp->burst; 369 upp->timo = ppihztoms(pp->timo); 370 upp->delay = ppihztoms(pp->delay); 371 break; 372 case PPIIOCSPARAM: 373 pp = &sc->sc_param; 374 upp = (struct ppiparam *)data; 375 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || 376 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) 377 return(EINVAL); 378 pp->burst = upp->burst; 379 pp->timo = ppimstohz(upp->timo); 380 pp->delay = ppimstohz(upp->delay); 381 break; 382 case PPIIOCSSEC: 383 sc->sc_sec = *(int *)data; 384 break; 385 default: 386 return(EINVAL); 387 } 388 return (error); 389 } 390 391 ppihztoms(h) 392 int h; 393 { 394 extern int hz; 395 register int m = h; 396 397 if (m > 0) 398 m = m * 1000 / hz; 399 return(m); 400 } 401 402 ppimstohz(m) 403 int m; 404 { 405 extern int hz; 406 register int h = m; 407 408 if (h > 0) { 409 h = h * hz / 1000; 410 if (h == 0) 411 h = 1000 / hz; 412 } 413 return(h); 414 } 415 #endif 416