Programmed I/O devices rely on the CPU to perform the data transfer. Programmed I/O data transfers are identical to other read and write operations for device registers. Various data access routines are used to read or store values to device memory.
uiomove(9F) can be used to transfer data to some programmed I/O devices. uiomove(9F) transfers data between the user space, as defined by the uio(9S) structure, and the kernel. uiomove() can handle page faults, so the memory to which data is transferred need not be locked down. uiomove() also updates the uio_resid field in the uio(9S) structure. The following example shows one way to write a ramdisk read(9E) routine. It uses synchronous I/O and relies on the presence of the following fields in the ramdisk state structure:
caddr_t ram; /* base address of ramdisk */ int ramsize; /* size of the ramdisk */
static int rd_read(dev_t dev, struct uio *uiop, cred_t *credp) { rd_devstate_t *rsp; rsp = ddi_get_soft_state(rd_statep, getminor(dev)); if (rsp == NULL) return (ENXIO); if (uiop->uio_offset >= rsp->ramsize) return (EINVAL); /* * uiomove takes the offset into the kernel buffer, * the data transfer count (minimum of the requested and * the remaining data), the UIO_READ flag, and a pointer * to the uio structure. */ return (uiomove(rsp->ram + uiop->uio_offset, min(uiop->uio_resid, rsp->ramsize - uiop->uio_offset), UIO_READ, uiop)); }
Another example of programmed I/O would be a driver that writes data one byte at a time directly to the device's memory. Each byte is retrieved from the uio(9S) structure by using uwritec(9F). The byte is then sent to the device. read(9E) can use ureadc(9F) to transfer a byte from the device to the area described by the uio(9S) structure.
static int xxwrite(dev_t dev, struct uio *uiop, cred_t *credp) { int value; struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); /* if the device implements a power manageable component, do this: */ pm_busy_component(xsp->dip, 0); if (xsp->pm_suspended) pm_raise_power(xsp->dip, normal power); while (uiop->uio_resid > 0) { /* * do the programmed I/O access */ value = uwritec(uiop); if (value == -1) return (EFAULT); ddi_put8(xsp->data_access_handle, &xsp->regp->data, (uint8_t)value); ddi_put8(xsp->data_access_handle, &xsp->regp->csr, START_TRANSFER); /* * this device requires a ten microsecond delay * between writes */ drv_usecwait(10); } pm_idle_component(xsp->dip, 0); return (0); }