Writing Device Drivers

probe()

This entry point is not required for self-identifying devices such as SBus or PCI devices. nulldev(9F) may be used instead.

For non-self-identifying devices (see "Device Identification") this entry point should determine whether the hardware device is present on the system and return:

DDI_PROBE_SUCCESS if the probe was successful

DDI_PROBE_FAILURE if the probe failed

DDI_PROBE_DONTCARE if the probe was unsuccessful, yet attach(9E) should still be called

DDI_PROBE_PARTIAL if the instance is not present now, but may be present in the future

For a given device instance, attach(9E) will not be called before probe(9E) has succeeded at least once on that device.

It is important that probe(9E) free all the resources it allocates, because it may be called multiple times; however, attach(9E) will not necessarily be called even if probe(9E) succeeds.

For probe to determine whether the instance of the device is present, probe(9E) may need to do many of the things also commonly done by attach(9E). In particular, it may need to map the device registers.

Probing the device registers is device specific. The driver probably has to perform a series of tests of the hardware to assure that the hardware is really there. The test criteria must be rigorous enough to avoid misidentifying devices. It may, for example, appear that the device is present when in fact it is not, because a different device appears to behave like the expected device.

When the driver's probe(9E) routine is called, it does not know whether the device being probed exists on the bus. Therefore, it is possible that the driver may attempt to access device registers for a nonexistent device. A bus fault may be generated on some buses as a result.

Buses such as ISA, EISA, and MCA do not generate bus faults as a result of such accesses. Example 5-2 is a sample probe(9E) routine for devices on these buses.


Example 5-2 probe(9E) Routine

static int
xxprobe(dev_info_t *dip)
{
	int			instance;
	caddr_t 			reg_addr;
	ddi_acc_handle_t 	data_access_handle;

	/* define device access attributes */
	ddi_device_acc_attr_t access_attr = {
		  DDI_DEVICE_ATTR_V0,
	  	DDI_STRUCTURE_BE_ACC,
	  	DDI_STRICTORDER_ACC
	};
	if (ddi_dev_is_sid(dip) == DDI_SUCCESS) /* no need to probe */
	  	return (DDI_PROBE_DONTCARE);
	instance = ddi_get_instance(dip);										/* assigned instance */
	if (ddi_intr_hilevel(dip, inumber)) {
	  	cmn_err(CE_CONT,
			"?xx driver does not support high level interrupts."
			" Probe failed.");
	  	return (DDI_PROBE_FAILURE);
	}

	/* Map device registers and try to contact device.*/
	if (ddi_regs_map_setup(dip, rnumber, &reg_addr, offset, len,
			&access_attr, &data_access_handle) != DDI_SUCCESS)
	  	return (DDI_PROBE_FAILURE);
	if (ddi_get8(data_access_handle, (uint8_t *)reg_addr) !=
 			some_value)
	  	goto failed;
	free allocated resources
	ddi_regs_map_free(&data_access_handle);
	if (device is present and ready for attach)
	    	return (DDI_PROBE_SUCCESS);
	else if (device is present but not ready for attach)
	    	return (DDI_PROBE_PARTIAL);
	else		/* device is not present */
	    	return (DDI_PROBE_FAILURE);
failed:
	free allocated resources
	ddi_regs_map_free(&data_access_handle);
	return (DDI_PROBE_FAILURE);
}	

The string printed in the high-level interrupt case begins with a `?' character. This causes the message to be printed only if the kernel was booted with the verbose (-v) flag. (See kernel(1M)). Otherwise the message only goes into the message log, where it can be seen by running dmesg(1M).

ddi_dev_is_sid(9F) may be used in a driver's probe(9E) routine to determine if the device is self-identifying. This is useful in drivers written for self-identifying and non-self-identifying versions of the same device.

For VME device drivers, a fault may occur as a result of attempting to access device registers for a device that is not present. In this case, the ddi_peek(9F) and ddi_poke(9F) family of routines must be used to access the device registers. Example 5-3 shows a probe(9E) routine that uses ddi_peek(9F) and ddi_poke(9F) to check for the existence of the device.


Example 5-3 probe(9E) Routine Using ddi_peek(9F)

static int
xxprobe(dev_info_t *dip)
{
	int			instance;
	caddr_t 			reg_addr;
	if (ddi_dev_is_sid(dip) == DDI_SUCCESS) /* no need to probe */
	    	return (DDI_PROBE_DONTCARE);
	instance = ddi_get_instance(dip);										/* assigned instance */
	if (ddi_intr_hilevel(dip, inumber)) {
	   	cmn_err(CE_CONT,
			"?xx driver does not support high level interrupts."
			" Probe failed.");
	   	return (DDI_PROBE_FAILURE);
	}
	/*
	 * Map device registers and try to contact device.
	 */
	if (ddi_regs_map_setup(dip, rnumber, &reg_addr, offset, len,
			&access_attr, &data_access_handle) != DDI_SUCCESS)
	  	return (DDI_PROBE_FAILURE);
	if (ddi_peek8(dip, reg_addr, NULL) != DDI_SUCCESS)
	    	goto failed;
	free allocated resources
ddi_regs_map_free(&data_access_handle);
	if (device is present and ready for attach)
	    	return (DDI_PROBE_SUCCESS);
	else if (device is present but not ready for attach)
	    	return (DDI_PROBE_PARTIAL);
	else		/* device is not present */
	    	return (DDI_PROBE_FAILURE);
	failed:
	free allocated resources
	ddi_regs_map_free(&data_access_handle);
	return (DDI_PROBE_FAILURE);
}	

In this example, ddi_regs_map_setup(9F) is used to map the device registers. ddi_peek8(9F) reads a single character from the location reg_addr.