Writing Device Drivers

chpoll(9E)

int xxchpoll(dev_t dev, short events, int anyyet, short *reventsp,
 	struct pollhead **phpp); 

The system calls chpoll(9E) when a user process issues a poll(2) system call on a file descriptor associated with the device. The chpoll(9E) entry point routine is used by non-STREAMS character device drivers that need to support polling.

In chpoll(9E), the driver must follow these rules:

	if (events are satisfied now) {     
 		*reventsp = mask of satisfied events;
 } else {
 		*reventsp = 0;
 		if (!anyyet)
 			*phpp = &local pollhead structure;
 }
 return (0);

xxchpoll( ) should check to see if certain events have occurred; see chpoll(9E). It should then return the mask of satisfied events by setting the return events in *reventsp.

If no events have occurred, the return field for the events is cleared. If the anyyet field is not set, the driver must return an instance of the pollhead structure. It is usually allocated in a state structure and should be treated as opaque by the driver. None of its fields should be referenced.

Example 9-11 and Example 9-12 show how to implement the polling discipline and how to use pollwakeup(9F).


Example 9-11 chpoll(9E) Routine

static int
xxchpoll(dev_t dev, short events, int anyyet,
	    short *reventsp, struct pollhead **phpp)
{
 	uint8_t status;
 	short revent;
 	struct xxstate *xsp;

 	xsp = ddi_get_soft_state(statep, getminor(dev));
 	if (xsp == NULL)
		     return (ENXIO);
 	revent = 0;
 	/*
	    * Valid events are:
	    * POLLIN | POLLOUT | POLLPRI | POLLHUP | POLLERR
	    * This example checks only for POLLIN and POLLERR.
	    */
 	status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
 	if ((events & POLLIN) && data available to read) {
	    	revent |= POLLIN;
 	}
 	if ((events & POLLERR) && (status & DEVICE_ERROR)) {
	    	revent |= POLLERR;
	   }
 	/* if nothing has occurred */
 	if (revent == 0) {
	    	if (!anyyet) {
			    *phpp = &xsp->pollhead;
	    	}
 	}
	   *reventsp = revent;
 	return (0);
}

In Example 9-12, the driver can handle the POLLIN and POLLERR events (see chpoll(9E) for a detailed discussion of the available events). The driver first reads the status register to determine the current state of the device. The parameter events specifies which conditions the driver should check. If the appropriate conditions have occurred, the driver sets that bit in *reventsp. If none of the conditions have occurred and anyyet is not set, the address of the pollhead structure is returned in *phpp.


Example 9-12 Interrupt Routine Supporting chpoll(9E)

static u_int
xxintr(caddr_t arg)
{
	   struct xxstate *xsp = (struct xxstate *)arg;
 	uint8_t		status;
 	normal interrupt processing
 	...
 	status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
 	if (status & DEVICE_ERROR) {
	    	pollwakeup(&xsp->pollhead, POLLERR);
 	}
 	if (just completed a read) {
	    	pollwakeup(&xsp->pollhead, POLLIN);
 	}
 	...
 	return (DDI_INTR_CLAIMED);
}

pollwakeup(9F) is usually called in the interrupt routine when a supported condition has occurred. The interrupt routine reads the status from the status register and checks for the conditions. It then calls pollwakeup(9F) for each event to possibly notify polling threads that they should check again. Note that pollwakeup(9F) should not be called with any locks held, as it could cause the chpoll(9E) routine to be entered, resulting in deadlock if that routine tries to grab the same lock.