int mm_md_readwrite(dev_t dev, struct uio *uio) { switch (minor(dev)) { case DEV_EEPROM: return eeprom_uio(uio); case DEV_LEDS: return leds_uio(uio); default: return ENXIO; } }
/*ARGSUSED*/ int mmrw(dev_t dev, struct uio *uio, int flags) { vaddr_t va; paddr_t pa; int o, c; struct iovec *iov; int error = 0; static int physlock; vm_prot_t prot; extern void *vmmap; if (minor(dev) == DEV_MEM) { /* lock against other uses of shared vmmap */ while (physlock > 0) { physlock++; error = tsleep((void *)&physlock, PZERO | PCATCH, "mmrw", 0); if (error) return (error); } physlock = 1; } while (uio->uio_resid > 0 && error == 0) { int n; iov = uio->uio_iov; if (iov->iov_len == 0) { uio->uio_iov++; uio->uio_iovcnt--; if (uio->uio_iovcnt < 0) panic("mmrw"); continue; } /* Note how much is still to go */ n = uio->uio_resid; switch (minor(dev)) { case DEV_MEM: pa = (paddr_t)uio->uio_offset; if (!pmap_pa_exists(pa)) { error = EFAULT; goto unlock; } prot = uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE; pmap_enter(pmap_kernel(), (vaddr_t)vmmap, trunc_page(pa), prot, prot|PMAP_WIRED); pmap_update(pmap_kernel()); o = uio->uio_offset & PGOFSET; c = min(uio->uio_resid, (int)(PAGE_SIZE - o)); error = uiomove((char *)vmmap + o, c, uio); pmap_remove(pmap_kernel(), (vaddr_t)vmmap, (vaddr_t)vmmap + PAGE_SIZE); pmap_update(pmap_kernel()); break; case DEV_KMEM: va = (vaddr_t)uio->uio_offset; if (va >= MSGBUF_VA && va < MSGBUF_VA+PAGE_SIZE) { c = min(iov->iov_len, 4096); } else if (va >= prom_vstart && va < prom_vend && uio->uio_rw == UIO_READ) { /* Allow read-only access to the PROM */ c = min(iov->iov_len, prom_vend - prom_vstart); } else { c = min(iov->iov_len, MAXPHYS); if (!uvm_kernacc((void *)va, c, uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) return (EFAULT); } error = uiomove((void *)va, c, uio); break; case DEV_NULL: if (uio->uio_rw == UIO_WRITE) uio->uio_resid = 0; return (0); /* XXX should add sbus, etc */ #if defined(SUN4) case DEV_EEPROM: if (cputyp == CPU_SUN4) error = eeprom_uio(uio); else error = ENXIO; break; #endif /* SUN4 */ case DEV_ZERO: if (uio->uio_rw == UIO_WRITE) { uio->uio_resid = 0; return(0); } if (zeropage == NULL) { zeropage = (void *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK); bzero(zeropage, PAGE_SIZE); } c = min(iov->iov_len, PAGE_SIZE); error = uiomove(zeropage, c, uio); break; default: return (ENXIO); } /* If we didn't make any progress (i.e. EOF), we're done here */ if (n == uio->uio_resid) break; } if (minor(dev) == 0) { unlock: if (physlock > 1) wakeup((void *)&physlock); physlock = 0; } return (error); }