#include #include #include #include #include #include #include #include #include #include #include #include /* autoconfig stuff... */ #define BUFSZ (256<<10) #define DMASIZE (2*BUFSZ) struct pbus_softc { struct device sc_dev; /* REQUIRED first entry */ void *sc_ih; /* interrupt handle */ bus_space_tag_t iot; bus_space_handle_t ioh; bus_dma_tag_t dmat; unsigned long iobase; bus_dmamap_t sc_dmam; /* bus dma map */ unsigned char *sc_cpudma; /* dma memory space from cpu space*/ unsigned long sc_bonitodma; /* dma memory space from pci space*/ unsigned long sc_dmasize; /* dma buffer size */ struct proc *cproc; /* Control process */ int csignal; /* Control signal */ int in_dma; int buf_ok; int framesize; int buf_consumed; int pbusinten; }; static int pbusprobe(struct device *, struct cfdata *, void *); static void pbusattach(struct device *, struct device *, void *); struct cfattach pbus_ca = { sizeof(struct pbus_softc), pbusprobe, pbusattach }; #define BUFSYNC_PRE \ bus_dmamap_sync(sc->dmat,sc->sc_dmam,0,DMASIZE,BUS_DMASYNC_PREREAD) #define BUFSYNC_POST \ bus_dmamap_sync(sc->dmat,sc->sc_dmam,0,DMASIZE,BUS_DMASYNC_POSTREAD) #define PBUS_WRITE_4(reg, val) \ bus_space_write_4(sc->iot, sc->ioh, reg, val) #define PBUS_READ_4(reg) \ bus_space_read_4(sc->iot, sc->ioh, reg) static int pbusprobe(struct device *parent, struct cfdata *cf, void *aux) { struct bonito_io_attach *bia = aux; struct pbus_softc scp; struct pbus_softc *sc=&scp; sc->iobase=bia->base; return 1; } int pbus_intr(void *p); static void pbusattach(parent, self, aux) struct device *parent, *self; void *aux; { bus_dma_segment_t seg; int rseg; struct bonito_io_attach *bia = aux; struct pbus_softc *sc = (struct pbus_softc *)self; sc->iot=bia->iot; sc->dmat=bia->dmat; bus_space_map(sc->iot, bia->base, 12, 0, &(sc->ioh)); sc->iobase=(unsigned long)sc->ioh; printf("\n"); PBUS_WRITE_4(0x08,PBUS_RnW); PBUS_WRITE_4(0x0,0); sc->sc_dmasize=DMASIZE; sc->in_dma=0; sc->buf_ok=0; sc->framesize=BUFSZ; sc->csignal=SIGUSR1; sc->pbusinten=0; sc->buf_consumed=0; /* * Allocate a DMA area for the card. */ if (bus_dmamem_alloc(sc->dmat, sc->sc_dmasize, NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT|BUS_DMA_DIRECT)) { printf("%s: couldn't allocate DMA\n", sc->sc_dev.dv_xname); return; } if (bus_dmamem_map(sc->dmat, &seg, rseg, sc->sc_dmasize, (caddr_t *)&sc->sc_cpudma, BUS_DMA_NOWAIT|BUS_DMA_DIRECT)) { printf("%s: couldn't map DMA\n", sc->sc_dev.dv_xname); return; } /* * Create and load the DMA map for the DMA area. */ if (bus_dmamap_create(sc->dmat, sc->sc_dmasize, 1, sc->sc_dmasize, 0, BUS_DMA_NOWAIT|BUS_DMA_DIRECT, &sc->sc_dmam)) { printf("%s: couldn't create DMA map\n", sc->sc_dev.dv_xname); bus_dmamem_free(sc->dmat, &seg, rseg); return; } if (bus_dmamap_load(sc->dmat, sc->sc_dmam, sc->sc_cpudma, sc->sc_dmasize, NULL, BUS_DMA_NOWAIT|BUS_DMA_DIRECT)) { printf("%s: coundn't load DMA map\n", sc->sc_dev.dv_xname); bus_dmamem_free(sc->dmat, &seg, rseg); return; } sc->sc_bonitodma = sc->sc_dmam->dm_segs[0].ds_addr; bzero(sc->sc_cpudma,DMASIZE); sc->sc_ih = bonito_intr_establish(bia->irq, IPL_NET, pbus_intr, sc); if (sc->sc_ih == NULL) { printf("%s: couldn't establish interrupt at %d\n", sc->sc_dev.dv_xname,bia->irq); return; } printf("%s: DMA map:0x%08lx (PHYS:0x%08lx)\n", sc->sc_dev.dv_xname, (unsigned long) sc->sc_cpudma, sc->sc_bonitodma); printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, bia->irq); } /* * operational routines: * open, close, read, write, * ioctl, mmap */ dev_type_open(pbusopen); dev_type_close(pbusclose); dev_type_read(pbusread); dev_type_write(pbuswrite); dev_type_ioctl(pbusioctl); dev_type_mmap(pbusmmap); int pbusopen(dev, flag, fmt, proc) dev_t dev; int flag, fmt; struct proc *proc; { struct pbus_softc *sc= pbus_cd.cd_devs[0]; if (minor(dev)==1) /* PBUS */ sc->cproc=proc; return 0; } int pbusclose(dev, flag, fmt, proc) dev_t dev; int flag, fmt; struct proc *proc; { struct pbus_softc *sc= pbus_cd.cd_devs[0]; if (minor(dev)==1) /* PBUS */ sc->cproc=NULL; return 0; } int pbusread(dev, uio, flags) dev_t dev; struct uio *uio; int flags; { int bufok,remain; int resid=uio->uio_resid; int s; struct pbus_softc *sc= pbus_cd.cd_devs[0]; s=splhigh(); bufok=*((volatile int *)(&sc->buf_ok)); if ((!bufok)&&(!sc->in_dma)) { BUFSYNC_PRE; PBUS_WRITE_4(0x4,sc->sc_bonitodma); sc->in_dma=1; } splx(s); if (!bufok) return 0; remain=sc->framesize-sc->buf_consumed; if (resid>remain) resid=remain; uiomove(sc->sc_cpudma+sc->buf_consumed,resid,uio); sc->buf_consumed+=resid; remain-=resid; if (!remain) { sc->buf_consumed=0; sc->buf_ok=0; } return 0; } int pbuswrite(dev, uio, flags) dev_t dev; struct uio *uio; int flags; { return ENODEV; } int pbus_intr(void *p) { struct pbus_softc *sc = (struct pbus_softc *)p; unsigned long status=PBUS_READ_4(0); if (status&0x20000000) { /* Désactive les interuptions. */ PBUS_WRITE_4(8,PBUS_READ_4(8)&0x3FFF); sc->pbusinten=0; /* Envoie le signal à l'application. */ if (sc->cproc!=NULL) psignal(sc->cproc,sc->csignal); } else { if (status&0x40000000) { /* Frame Ok */ BUFSYNC_POST; sc->buf_ok=1; sc->in_dma=0; } else { /* Pointer slot avail */ } } return 0; } #define PBUS_WAIT \ tsleep(sc,PUSER | PCATCH,"pbusio",(HZ/10000)?(HZ/10000):1) int pbusioctl(dev, cmd, addr, flag, proc) dev_t dev; u_long cmd; int flag; caddr_t addr; struct proc *proc; { struct pbus_softc *sc= pbus_cd.cd_devs[0]; struct pbus_io *parm=(struct pbus_io *)addr; unsigned long *fsize=(unsigned long *)addr; /* PBUS IOctl */ if (minor(dev)==1) /* PBUS */ { switch (cmd) { case PBUS_READ: PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten); PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_CLK|PBUS_RnW|sc->pbusinten); PBUS_WAIT; parm->data=PBUS_READ_4(8)&0xFF; PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten); PBUS_WAIT; break; case PBUS_WRITE: PBUS_WRITE_4(8,(parm->addr<<8)|(parm->data)|sc->pbusinten); PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_CLK|(parm->data)|sc->pbusinten); PBUS_WAIT; PBUS_WRITE_4(8,(parm->addr<<8)|(parm->data)|sc->pbusinten); PBUS_WAIT; PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten); break; case PBUS_INTDISABLE: sc->pbusinten=0; PBUS_WRITE_4(8,0|PBUS_RnW|sc->pbusinten); break; case PBUS_INTENABLE: sc->pbusinten=PBUS_INTEN; PBUS_WRITE_4(8,0|PBUS_RnW|sc->pbusinten); break; case PBUS_INTREAD: parm->ints=(PBUS_READ_4(8)>>16)&0x1F; break; } } if (minor(dev)==0) /* CAM */ { switch (cmd) { case CAM_SETFRAMESIZE: PBUS_WRITE_4(0x0,1); sc->framesize=*fsize; break; } } return 0; } paddr_t pbusmmap(dev_t dev, off_t offset, int nprot) { return ENXIO; }