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