123332Smckusick /* 223332Smckusick * Copyright (c) 1982 Regents of the University of California. 323332Smckusick * All rights reserved. The Berkeley software License Agreement 423332Smckusick * specifies the terms and conditions for redistribution. 523332Smckusick * 6*26367Skarels * @(#)lpa.c 6.4 (Berkeley) 02/23/86 723332Smckusick */ 88476Sroot 96968Ssam #include "lpa.h" 106968Ssam #if NLPA > 0 116968Ssam 1217074Sbloom #include "param.h" 1317074Sbloom #include "dir.h" 1417074Sbloom #include "user.h" 1517074Sbloom #include "buf.h" 1617074Sbloom #include "proc.h" 1717074Sbloom #include "ioctl.h" 1817074Sbloom #include "uio.h" 196968Ssam 2017074Sbloom #include "ubavar.h" 218476Sroot 226968Ssam /* 238492Sroot * LPA driver for -- Asa Romberger 248492Sroot * 256968Ssam * open 266968Ssam * write microcode 276968Ssam * write dedicated mode dispatch table 286968Ssam * ioctl TIOCSETP to set parameters 296968Ssam * struct iocb { 306968Ssam * short *baddr; buffer address 316968Ssam * short rate; - 1,000,000 / frequency in Hz 326968Ssam * short wc; 15-13 = number of buffers - 1 336968Ssam * 12-0 = buffer size in words 346968Ssam * } iocb; 356968Ssam * read - 1 character indicating buffer index 366968Ssam * fill or empty buffer 376968Ssam * minor device number = DDCCCCCC where: 386968Ssam * DD = 00 for analog input 396968Ssam * = 01 for analog output 406968Ssam * CCCCCC = channel number 416968Ssam */ 426968Ssam * define NOMCODE to eliminate the microcode download check 436968Ssam */ 448492Sroot /* #define TRACELPA */ 458492Sroot /* #define NOMCODE */ 466968Ssam 476968Ssam #ifdef TRACELPA 486968Ssam # define TRACER(x) printf(x) 496968Ssam # define TRACERN(x, d) printf(x, d) 506968Ssam #else 516968Ssam # define TRACER(x) 526968Ssam # define TRACERN(x, d) 536968Ssam #endif 546968Ssam 556968Ssam /* PRIORITY AT WHICH PROGRAM SHOULD RUN */ 566968Ssam /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */ 576968Ssam 586968Ssam #define NICE 0 596968Ssam 608492Sroot #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf)) 616968Ssam 628492Sroot #define LPAPRI (PZERO + 0) 636968Ssam #define LPAUNIT(dev) 0 646968Ssam #define LPADEVICE(dev) (((dev) >> 6) & 03) 656968Ssam #define LPACHANNEL(dev) ((dev) & 077) 666968Ssam 678492Sroot int lpaprobe(), lpaattach(), lpaiintr(), lpaointr(); 688492Sroot u_short lpastd[] = {0170460, 0}; 698492Sroot struct uba_device *lpadinfo[NLPA]; 706968Ssam struct uba_driver lpadriver = 718492Sroot {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 }; 726968Ssam 736968Ssam struct lpa_softc { 746968Ssam int sc_flag; /* flags, as defined below */ 756968Ssam int sc_device; /* device: 0 = analog in, 1 = analog out */ 766968Ssam int sc_channel; /* device channel number */ 776968Ssam struct buf sc_ubuffer; /* user buffer header */ 786968Ssam int sc_ubabuf; /* uba allocation pointer for buffer */ 796968Ssam int sc_ubufn; /* present buffer that user is accessing */ 806968Ssam int sc_lbufn; /* present buffer that lpa is accessing */ 816968Ssam int sc_lbufnx; /* next buffer for lpa (value in ustat) */ 826968Ssam int sc_nbuf; /* number of buffers */ 836968Ssam int sc_count; /* buffer size in words */ 846968Ssam short sc_ustat; /* user status word */ 856968Ssam struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */ 866968Ssam int sc_ubaustat; /* uba allocation pointer for ustat */ 876968Ssam struct buf *sc_buffer; /* scratch buffer header */ 886968Ssam int sc_start; /* 0 if lpa operation has been started */ 896968Ssam } lpa_softc[NLPA]; 908492Sroot 918492Sroot /* flags for sc_flag */ 926968Ssam #define OPEN 01 /* device is open */ 936968Ssam #define MCODE 02 /* microcode has been loaded */ 946968Ssam #define DMDT 04 /* dedicated mode dispatch table loaded */ 956968Ssam #define STTY 010 /* stty call and device initialized */ 966968Ssam #define SLEEP 020 /* sleeping */ 978492Sroot 988492Sroot /* bits for ustat */ 996968Ssam #define DONE 0100000 /* done */ 1006968Ssam #define STOP 0040000 /* stop data transfer */ 1016968Ssam #define NBI 0003400 /* next buffer index */ 1026968Ssam #define LBI 0000003 /* last buffer index */ 1036968Ssam 1046968Ssam struct lpadevice { 1056968Ssam short lcim; /* control in and maintenance */ 1066968Ssam short lcos; /* control and status out */ 1076968Ssam short lrda; /* request description array address word */ 1086968Ssam short lms; /* maintenance status */ 1096968Ssam }; 1108492Sroot 1118492Sroot /* control in and maintenance register bits */ 1126968Ssam #define READYI 0000200 /* ready in */ 1136968Ssam #define IIE 0000100 /* in interrupt enable */ 1146968Ssam #define RDAEXT 0000014 /* rda address extension */ 1156968Ssam #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */ 1166968Ssam #define GO 0000001 /* go */ 1176968Ssam #define RUN 0100000 /* run */ 1186968Ssam #define RESET 0040000 /* reset */ 1196968Ssam #define CWRITE 0020000 /* cram write */ 1206968Ssam #define EA 0004000 /* enable arbitration */ 1216968Ssam #define ROMO 0002000 /* rom O */ 1226968Ssam #define ROMI 0001000 /* rom I */ 1236968Ssam #define SMICRO 0000400 /* step microprocessor */ 1248492Sroot 1258492Sroot /* control and status out register bits */ 1266968Ssam #define READYO 0200 /* ready out */ 1276968Ssam #define OIE 0100 /* out interrupt enable */ 1286968Ssam #define UINDEX 0007 /* user index */ 1296968Ssam #define ERROR 0100000 /* error */ 1306968Ssam #define ESTAT 0060000 /* error status */ 1316968Ssam #define ESCODE 0017400 /* error sub code */ 1326968Ssam #define ECODE 0077400 /* error status + error sub code */ 1336968Ssam #define OVERRUN 0243 /* overrun error */ 1346968Ssam 1358492Sroot /* LPA COMMAND DESCRIPTION AREA */ 1366968Ssam 1378492Sroot /* INIT COMMAND */ 1386968Ssam #define INIT 0 /* mode */ 1396968Ssam #define MCVERS 4 /* microcode version */ 1406968Ssam #define ACLOCKA 0170404 /* LPA bus addresses */ 1416968Ssam #define ACLOCKB 0170432 1426968Ssam #define AAD1 0170400 1436968Ssam #define AAD2 1 /* 0170440 - DOES NOT EXIST */ 1446968Ssam #define ADA 0170420 1456968Ssam #define ADIO1 1 /* 0167770 - DOES NOT EXIST */ 1466968Ssam #define ADIO2 1 /* 0167760 - DOES NOT EXIST */ 1476968Ssam #define ADIO3 1 /* 0167750 - DOES NOT EXIST */ 1486968Ssam #define ADIO4 1 /* 0167740 - DOES NOT EXIST */ 1496968Ssam #define ADIO5 1 /* 0167730 - DOES NOT EXIST */ 1508492Sroot 1518492Sroot /* CLOCK START COMMAND */ 1526968Ssam #define CLOCK 1 /* mode */ 1536968Ssam #define CLOCKA 0<<4 /* clock A */ 1548492Sroot /* clock status word */ 1556968Ssam #define ENACTR 1 /* enable counter */ 1566968Ssam #define R1M 1<<1 /* 1 MHz rate */ 1576968Ssam #define R100K 2<<1 /* 100 KHz rate */ 1586968Ssam #define R10K 3<<1 /* 10 KHz rate */ 1596968Ssam #define R1K 4<<1 /* 1 KHz rate */ 1606968Ssam #define R100 5<<1 /* 100 Hz rate */ 1616968Ssam #define REXT 6<<1 /* external rate (from st1 input) */ 1626968Ssam #define R60 7<<1 /* line frequency rate */ 1636968Ssam #define MFIE 0100 /* mode flag interrupt enable */ 1646968Ssam #define MSI 0<<8 /* single interval mode */ 1656968Ssam #define MRI 1<<8 /* repeat interval mode */ 1666968Ssam #define MEET 2<<8 /* external event time mode */ 1676968Ssam #define MEETZ 3<<8 /* external event time mode from zero base */ 1686968Ssam #define ST1EC 020000 /* st1 enable counter */ 1696968Ssam #define ST1IE 040000 /* st1 interrupt enable */ 1708492Sroot 1718492Sroot /* DATA TRANSFER START COMMAND */ 1726968Ssam #define DTS 2 /* mode */ 1736968Ssam #define SCHAN 1<<8 /* single channel */ 1746968Ssam 1756968Ssam lpaprobe(reg) 1768492Sroot caddr_t reg; 1776968Ssam { 1788492Sroot register int br, cvec; /* value result */ 1798492Sroot register struct lpadevice *lpaaddr = (struct lpadevice *)reg; 1806968Ssam 1816968Ssam #ifdef lint 1826968Ssam br = 0; cvec = br; br = cvec; 1836968Ssam #endif 1846968Ssam /* this should force an interrupt, stall, clear the lpa */ 1856968Ssam br = 0x15; 1866968Ssam cvec = 0330; 1876968Ssam TRACER("PROBE\n"); 1887413Skre return (sizeof (struct lpadevice)); 1896968Ssam } 1906968Ssam 1916968Ssam lpaattach(ui) 1928492Sroot register struct upa_device *ui; 1936968Ssam { 1948492Sroot 1956968Ssam } 1966968Ssam 1976968Ssam lpaopen(dev, flag) 1988492Sroot dev_t dev; 1998492Sroot int flag; 2006968Ssam { 2016968Ssam register int unit = LPAUNIT(dev); 2026968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 2036968Ssam register struct uba_device *ui = lpadinfo[unit]; 2046968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 2056968Ssam 2066968Ssam TRACER("OPEN\n"); 2076968Ssam if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 || 2088571Sroot ui->ui_alive == 0) 2098571Sroot return (ENXIO); 210*26367Skarels (void) splhigh(); 2116968Ssam lpaaddr->lcim = RESET; 2126968Ssam lpaaddr->lcim = 0; 2136968Ssam (void) spl0(); 2146968Ssam lpaaddr->lcos = 0; /* clear the registers as a precaution */ 2156968Ssam lpaaddr->lrda = 0; 2166968Ssam lpaaddr->lms = 0; 2176968Ssam sc->sc_flag = OPEN; 2186968Ssam sc->sc_device = LPADEVICE(dev); 2196968Ssam sc->sc_channel = LPACHANNEL(dev); 2206968Ssam sc->sc_buffer = geteblk(); 2216968Ssam sc->sc_buffer->b_error = 0; 2226968Ssam sc->sc_buffer->b_proc = u.u_procp; 2236968Ssam sc->sc_ubufn = -1; 2246968Ssam /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */ 2256968Ssam u.u_procp->p_nice = NICE; 2268571Sroot return (0); 2276968Ssam } 2286968Ssam 2296968Ssam lpaclose(dev, flag) 2308492Sroot dev_t dev; 2318492Sroot int flag; 2326968Ssam { 2336968Ssam register int unit = LPAUNIT(dev); 2346968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 2356968Ssam register struct uba_device *ui = lpadinfo[unit]; 2366968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 2376968Ssam 2386968Ssam if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) { 2396968Ssam if (sc->sc_start) 2406968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 2416968Ssam sc->sc_flag |= STOP; 2426968Ssam (void) spl5(); 2436968Ssam while (sc->sc_flag & STOP) { 2446968Ssam TRACER("SLEEP\n"); 2456968Ssam sc->sc_flag |= SLEEP; 2466968Ssam sleep((caddr_t)sc, LPAPRI); 2476968Ssam } 2486968Ssam } 249*26367Skarels (void) splhigh(); 2506968Ssam lpaaddr->lcim = RESET; 2516968Ssam lpaaddr->lcim = 0; 2526968Ssam (void) spl0(); 2536968Ssam if (sc->sc_ubabuf) { 2546968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubabuf); 2556968Ssam sc->sc_ubabuf = 0; 256*26367Skarels (void) splclock(); 2576968Ssam vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount, 2586968Ssam (sc->sc_device)? B_READ : B_WRITE); 2596968Ssam u.u_procp->p_flag &= ~SPHYSIO; 2606968Ssam (void) spl0(); 2616968Ssam } 2626968Ssam if (sc->sc_ubaustat) { 2636968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubaustat); 2646968Ssam sc->sc_ubaustat = 0; 2656968Ssam } 2666968Ssam if (sc->sc_buffer) { 2676968Ssam brelse(sc->sc_buffer); 2686968Ssam sc->sc_buffer = 0; 2696968Ssam } 2706968Ssam sc->sc_flag = 0; 2716968Ssam TRACER("CLOSE\n"); 2726968Ssam } 2736968Ssam 2747835Sroot lpawrite(dev, uio) 2757835Sroot dev_t dev; 2767835Sroot struct uio *uio; 2776968Ssam { 2786968Ssam register int unit = LPAUNIT(dev); 2796968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 2806968Ssam register struct uba_device *ui = lpadinfo[unit]; 2816968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 2826968Ssam register int f; 2836968Ssam 2846968Ssam TRACER("WRITE\n"); 2856968Ssam f = sc->sc_flag; 2868492Sroot if ((f & OPEN) == 0) 2878492Sroot return (ENXIO); 2888492Sroot if ((f & MCODE) == 0) /* first write is the microcode */ 2898492Sroot return (lpamcode(lpaaddr, sc, uio)); 2908492Sroot if ((f & DMDT) == 0) /* second write is the dispatch table */ 2918492Sroot return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio)); 2928492Sroot return (ENXIO); 2936968Ssam } 2946968Ssam 2957835Sroot lpamcode(lpaaddr, sc, uio) 2967835Sroot register struct lpadevice *lpaaddr; 2977835Sroot register struct lpa_softc *sc; 2987835Sroot struct uio *uio; 2996968Ssam { 3006968Ssam short v, r; 3016968Ssam register int mcaddr; 3028709Sroot int error; 3036968Ssam 3046968Ssam mcaddr = 0; 3057835Sroot while (uio->uio_resid) { 3068709Sroot error = uiomove(&v, 2, UIO_WRITE, uio); 3078709Sroot if (error) 3088709Sroot break; 3096968Ssam lpaaddr->lcim = 0; /* load microcode word */ 3106968Ssam lpaaddr->lrda = mcaddr; 3116968Ssam lpaaddr->lms = v; 3126968Ssam lpaaddr->lcim = ROMO; 3136968Ssam lpaaddr->lcim |= CWRITE; 3146968Ssam lpaaddr->lcim = 0; /* verify microcode word */ 3156968Ssam lpaaddr->lrda = mcaddr; 3166968Ssam lpaaddr->lcim = ROMO; 3176968Ssam if ((r = lpaaddr->lms) != v) { 3186968Ssam /* download failure */ 3196968Ssam printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r); 3208492Sroot return (ENXIO); 3216968Ssam } 3226968Ssam mcaddr++; 3236968Ssam } 3246968Ssam lpaaddr->lcim = RUN | EA; /* turn it on */ 3256968Ssam sc->sc_flag |= MCODE; 3266968Ssam lpaaddr->lcim |= IIE; 3276968Ssam lpaaddr->lcos |= OIE; 3288709Sroot return (error); 3296968Ssam TRACER("MCODE\n"); 3306968Ssam } 3316968Ssam 3327835Sroot lpadmdt(lpaaddr, sc, ubanum, uio) 3337835Sroot register struct lpadevice *lpaaddr; 3347835Sroot register struct lpa_softc *sc; 3357835Sroot register short ubanum; 3367835Sroot struct uio *uio; 3376968Ssam { 3386968Ssam register short *p; 3396968Ssam register int n; 3408492Sroot int error; 3416968Ssam 3426968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* INIT */ 3436968Ssam *p++ = (MCVERS << 8) | INIT; /* mode */ 3446968Ssam *p++ = ACLOCKA; /* LPA bus device addresses */ 3456968Ssam *p++ = ACLOCKB; 3466968Ssam *p++ = AAD1; 3476968Ssam *p++ = AAD2; 3486968Ssam *p++ = ADA; 3496968Ssam *p++ = ADIO1; 3506968Ssam *p++ = ADIO2; 3516968Ssam *p++ = ADIO3; 3526968Ssam *p++ = ADIO4; 3536968Ssam *p++ = ADIO5; 354*26367Skarels n = MIN(uio->uio_resid, 256); /* dedicated mode dispatch table */ 3558492Sroot error = uiomove((char *)p, n, UIO_WRITE, uio); 3568492Sroot if (error) 3578492Sroot return (error); 3586968Ssam n >>= 1; 3596968Ssam p += n; 3606968Ssam while (n++ < 128) 3616968Ssam *p++ = 0; 3626968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum); 3636968Ssam sc->sc_flag |= DMDT; 3648492Sroot return (0); 3656968Ssam TRACER("DMDT\n"); 3666968Ssam } 3676968Ssam 3687632Ssam lpaioctl(dev, cmd, data, flag) 3697632Ssam dev_t dev; 3707632Ssam caddr_t data; 3716968Ssam { 3726968Ssam register int unit = LPAUNIT(dev); 3736968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 3746968Ssam register struct uba_device *ui = lpadinfo[unit]; 3756968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 3766968Ssam register short *p; 3776968Ssam register int i; 3786968Ssam register int v; 3796968Ssam struct iocb { 3806968Ssam short *baddr; 3816968Ssam short rate; 3826968Ssam short wc; 3837632Ssam } *iocb; 3846968Ssam 3856968Ssam TRACER("IOCTL IN\n"); 3868571Sroot if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0) 3878571Sroot return (ENXIO); 3887632Ssam iocb = (struct iocb *)data; 3896968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* CLOCK START */ 3906968Ssam *p++ = CLOCK | CLOCKA; /* mode */ 3916968Ssam *p++ = ENACTR | R1M | MFIE | MRI; /* clock status */ 3927632Ssam *p = iocb->rate; /* clock preset */ 3936968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 3946968Ssam TRACER("CLOCK STARTED\n"); 3956968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* DATA TRANSFER START*/ 3966968Ssam *p++ = (sc->sc_device << 7) | DTS | SCHAN; /* mode */ 3977632Ssam sc->sc_count = iocb->wc & 017777; /* word count per buffer */ 3986968Ssam *p++ = sc->sc_count; 3996968Ssam /* user status word */ 4006968Ssam sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat; 4016968Ssam sc->sc_ustatbuf.b_flags = 0; 4026968Ssam sc->sc_ustatbuf.b_bcount = 2; 4036968Ssam sc->sc_ustatbuf.b_proc = u.u_procp; 4046968Ssam sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0); 4056968Ssam v = sc->sc_ubaustat; 4066968Ssam *p++ = v; 4076968Ssam *p = (v >> 16) & 03; /* into low portion of word */ 4087632Ssam sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */ 4096968Ssam *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */ 4106968Ssam /* buffer addresses */ 4117632Ssam if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr, 4128571Sroot sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2, 4138571Sroot (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) { 4146968Ssam TRACER("USER BUFFER FAULT\n"); 4158571Sroot return (EFAULT); 4166968Ssam } 4176968Ssam sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i; 4186968Ssam sc->sc_ubuffer.b_proc = u.u_procp; 4196968Ssam u.u_procp->p_flag |= SPHYSIO; 4206968Ssam vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount); 4216968Ssam sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0); 4226968Ssam v = sc->sc_ubabuf; 4236968Ssam for (i = 0; i < sc->sc_nbuf; i++) { 4246968Ssam *p++ = v; 4256968Ssam *p++ = (v >> 16) & 03; 4266968Ssam v += sc->sc_count * 2; 4276968Ssam } 4286968Ssam for ( ; i <= 7; i++) { 4296968Ssam *p++ = 0; 4306968Ssam *p++ = 0; 4316968Ssam } 4326968Ssam *p++ = 0; *p++ = 0; /* random channel list address */ 4336968Ssam *p++ = 0; /* delay */ 4346968Ssam *p++ = sc->sc_channel; /* start channel, channel inc */ 4356968Ssam *p++ = 1; /* number of samples in a sequence */ 4366968Ssam *p++ = 0; /* dwell */ 4376968Ssam *p++ = 0; /* start word no., event mark word */ 4386968Ssam *p++ = 0; /* start word mask */ 4396968Ssam *p = 0; /* event mark mask */ 4406968Ssam sc->sc_ustat = 0; 4416968Ssam sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1; 4426968Ssam sc->sc_lbufn = 0; 4436968Ssam sc->sc_lbufnx = 0; 4446968Ssam sc->sc_flag |= STTY; 4456968Ssam TRACER("IOCTL OUT\n"); 4468571Sroot return (0); 4476968Ssam } 4486968Ssam 4497729Sroot lparead(dev, uio) 4507835Sroot dev_t dev; 4517835Sroot struct uio *uio; 4526968Ssam { 4536968Ssam register int unit = LPAUNIT(dev); 4546968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 4556968Ssam register struct uba_device *ui = lpadinfo[unit]; 4566968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 4576968Ssam 4586968Ssam TRACER("READ\n"); 4598492Sroot if ((sc->sc_flag & STTY) == 0) 4608492Sroot return (ENXIO); 4618492Sroot if (sc->sc_flag & ERROR) 4628492Sroot return (ENXIO); 4636968Ssam if (sc->sc_start) 4646968Ssam if (--sc->sc_start == 0) { 4656968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 4666968Ssam TRACER("START\n"); 4676968Ssam } 4686968Ssam inc(sc_ubufn); 4696968Ssam if (sc->sc_start == 0) { 4706968Ssam (void) spl5(); 4716968Ssam while (sc->sc_ubufn == sc->sc_lbufn) { 4728492Sroot if (sc->sc_flag & ERROR) 4738492Sroot return (ENXIO); 4746968Ssam TRACER("SLEEP\n"); 4756968Ssam sc->sc_flag |= SLEEP; 4766968Ssam sleep(sc, LPAPRI); 4776968Ssam } 4786968Ssam (void) spl0(); 4796968Ssam } 4806968Ssam TRACERN("READ %d\n", sc->sc_ubufn); 4818492Sroot return (uiomove(&sc->sc_ubufn, 1, UIO_READ, uio)); 4826968Ssam } 4836968Ssam 4846968Ssam lpacmd(bp, lpaaddr, sc, ubanum) 4857835Sroot register struct buf *bp; 4867835Sroot register struct lpadevice *lpaaddr; 4877835Sroot register struct lpa_softc *sc; 4887835Sroot register short ubanum; 4896968Ssam { 4906968Ssam int ubareg; 4916968Ssam 4926968Ssam TRACER("CMD\n"); 4936968Ssam ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP); 4946968Ssam lpawait(lpaaddr, sc); 4956968Ssam lpaaddr->lrda = ubareg; 4966968Ssam lpaaddr->lcim &= ~RDAEXT; 4976968Ssam lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO; 4986968Ssam lpawait(lpaaddr, sc); 4996968Ssam ubarelse(ubanum, &ubareg); 5006968Ssam } 5016968Ssam 5026968Ssam lpawait(lpaaddr, sc) 5038492Sroot register struct lpadevice *lpaaddr; 5048492Sroot register struct lpa_softc *sc; 5056968Ssam { 5068492Sroot 5076968Ssam (void) spl5(); 5086968Ssam while ((lpaaddr->lcim & READYI) == 0) { 5096968Ssam TRACER("SLEEP\n"); 5106968Ssam sc->sc_flag |= SLEEP; 5116968Ssam sleep((caddr_t)sc, LPAPRI); 5126968Ssam } 5136968Ssam (void) spl0(); 5146968Ssam } 5156968Ssam 5166968Ssam lpaiintr(unit) 5178492Sroot int unit; 5186968Ssam { 5196968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 5206968Ssam 5216968Ssam TRACER("{I"); 5226968Ssam if (sc->sc_flag & SLEEP) { 5236968Ssam TRACER("<WAKEUP>"); 5246968Ssam wakeup((caddr_t)sc); 5256968Ssam sc->sc_flag &= ~SLEEP; 5266968Ssam } 5276968Ssam TRACER("}"); 5286968Ssam } 5296968Ssam 5306968Ssam lpaointr(unit) 5318492Sroot int unit; 5326968Ssam { 5336968Ssam register int c, m; 5346968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 5356968Ssam register struct uba_device *ui = lpadinfo[unit]; 5366968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 5376968Ssam int spx; 5386968Ssam 5396968Ssam TRACER("{O"); 5406968Ssam if (sc->sc_flag & SLEEP) { 5416968Ssam TRACER("<WAKEUP>"); 5426968Ssam wakeup(sc); 5436968Ssam sc->sc_flag &= ~SLEEP; 5446968Ssam } 5456968Ssam c = lpaaddr->lcos; 5466968Ssam m = lpaaddr->lms; 5476968Ssam lpaaddr->lcos &= ~READYO; 5486968Ssam if (c & ERROR) { 5496968Ssam TRACER("<ERROR>"); 5506968Ssam c = (c >> 8) & 0377; 5516968Ssam if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) { 5526968Ssam printf("LPA ERROR %o %o\n", c, m&0177777); 5536968Ssam sc->sc_flag |= ERROR; 5546968Ssam } 5556968Ssam sc->sc_flag &= ~STOP; 5566968Ssam TRACER("}\n"); 5576968Ssam return; 5586968Ssam } 5596968Ssam TRACERN("<LPA %d>", sc->sc_lbufnx); 5606968Ssam sc->sc_lbufn = sc->sc_lbufnx; 5616968Ssam if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) { 5626968Ssam TRACER("<STOP?>"); 5636968Ssam if (sc->sc_flag & STOP) 5646968Ssam return; 5656968Ssam printf("LPA OVERRUN\n"); 5666968Ssam sc->sc_flag |= ERROR; 5676968Ssam } 5686968Ssam inc(sc_lbufnx); 5696968Ssam TRACERN("<USTAT %o>", sc->sc_ustat); 570*26367Skarels spx = splhigh(); 5716968Ssam sc->sc_ustat &= ~NBI; 5726968Ssam sc->sc_ustat |= sc->sc_lbufnx << 8; 5736968Ssam sc->sc_ustat &= ~DONE; 574*26367Skarels splx(spx); 5756968Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx); 5766968Ssam } 5776968Ssam 5786968Ssam lpareset(uban) 5798492Sroot int uban; 5806968Ssam { 5816968Ssam register struct uba_device *ui; 5826968Ssam register struct lpadevice *lpaaddr; 5836968Ssam register struct lpa_softc *sc; 5846968Ssam register int unit; 5856968Ssam 5866968Ssam TRACER("LPA RESET\n"); 5876968Ssam for (unit = 0; unit < NLPA; unit++) { 5888492Sroot if ((ui = lpadinfo[unit]) == 0 || 5898492Sroot ui->ui_ubanum != uban || ui->ui_alive == 0) 5908492Sroot continue; 5916968Ssam printf(" lpa%d", unit); 5926968Ssam lpaaddr = (struct lpadevice *)ui->ui_addr; 5936968Ssam sc = &lpa_softc[unit]; 5946968Ssam sc->sc_flag |= ERROR; 595*26367Skarels (void) splhigh(); 5966968Ssam lpaaddr->lcim = RESET; 5976968Ssam lpaaddr->lcim = 0; 5986968Ssam (void) spl0(); 5996968Ssam if (sc->sc_flag & SLEEP) { 6006968Ssam wakeup((caddr_t)sc); 6016968Ssam sc->sc_flag &= ~SLEEP; 6026968Ssam } 6036968Ssam } 6046968Ssam } 6056968Ssam #endif NLPA 606