Writing Device Drivers


The strategy(9E) routine originated in block drivers and is so called because it can implement a strategy for efficient queuing of I/O requests to a block device. A driver for a character-oriented device can also use a strategy(9E) routine. In the character I/O model presented here, strategy(9E) does not maintain a queue of requests, but rather services one request at a time.

In Example 9-8, the strategy(9E) routine for a character-oriented DMA device allocates DMA resources for synchronous data transfer and starts the command by programming the device register (see Chapter 7, DMA, for a detailed description).

Note -

strategy(9E) does not receive a device number (dev_t) as a parameter; instead, this is retrieved from the b_edev field of the buf(9S) structure passed to strategy(9E).

Example 9-8 strategy(9E) Routine

static int
xxstrategy(struct buf *bp)
 	minor_t	 				instance;
 	struct xxstate 					*xsp;
 	ddi_dma_cookie_t	 				cookie;
   instance = getminor(bp->b_edev);
 	xsp = ddi_get_soft_state(statep, instance);
 	if the device has power manageable components (see Chapter 8, Power Management     ),
 	mark the device busy with pm_busy_components(9F), 
     and then ensure that the device 
  	is powered up by calling ddi_dev_is_needed(9F).

 	set up DMA resources with ddi_dma_alloc_handle(9F) and
 	xsp->bp = bp; /* remember bp */
 	program DMA engine and start command
 	return (0);

Note -

Although strategy(9E) is declared to return an int, it must always return zero.

On completion of the DMA transfer, the device generates an interrupt, causing the interrupt routine to be called. In Example 9-9, xxintr()() receives a pointer to the state structure for the device that might have generated the interrupt.

Example 9-9 Interrupt Routine

static u_int
xxintr(caddr_t arg)
 	struct xxstate *xsp = (struct xxstate *)arg;
 	if (device did not interrupt) {
	    	return (DDI_INTR_UNCLAIMED);
 	if (error) {
	    	error handling
 	release any resources used in the transfer, such as DMA resources
	       ddi_dma_unbind_handle(9F) and ddi_dma_free_handle(9F(
 	/* notify threads that the transfer is complete */
 	return (DDI_INTR_CLAIMED);

The driver indicates an error by calling bioerror(9F). The driver must call biodone(9F) when the transfer is complete or after indicating an error with bioerror(9F).