Writing Device Drivers

Programmed I/O Transfers

Programmed I/O devices rely on the CPU to perform the data transfer. Programmed I/O data transfers are identical to other device register read and write operations. Various data access routines are used to read or store values to device memory. See "Data Access Functions" for more information.

uiomove( )

uiomove(9F) may be used to transfer data to some programmed I/O devices. uiomove(9F) transfers data between the user space (defined by the uio(9S) structure) and the kernel. uiomove(9F) can handle page faults, so the memory to which data is transferred need not be locked down. It also updates the uio_resid field in the uio(9S) structure. Example 9-3 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 */

Example 9-3 Ramdisk read(9E) Routine Using uiomove(9F)

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));

uwritec(9F) and ureadc(9F)

Another example of programmed I/O might be a driver writing data one byte at a time directly to the device's memory. Each byte is retrieved from the uio(9S) structure using uwritec(9F), 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.

Example 9-4 Programmed I/O write(9E) Routine Using uwritec(9F)

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)
		   ddi_dev_is_needed(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,
	   	ddi_put8(xsp->data_access_handle, &xsp->regp->csr,
	   	 * this device requires a ten microsecond delay
	   	 * between writes
	   pm_idle_component(xsp->dip, 0);
 	return (0);