Most driver writers are familiar with device minor numbers. But a notion of an instance number is specific to Solaris and it is often incorrectly assumed that minor == instance. Let's see if we can see clear that up.
Instance number
A driver handles devices of a certain type. There can be multiple instances of the same device type in the system. For example, there are two asynchronous serial devices (UARTs) on my system, handled by the asy(7D) driver and represented by two nodes in the device tree:
$ prtconf -D | grep asy
asy, instance #0 (driver name: asy)
asy, instance #1 (driver name: asy)
These are the two instances of the same driver: sharing binary code in the kernel address space, but maintaining separate data 1. Instances are numbered, in this case 0 and 1. Instance numbers are assigned permanently to physical devices in the system; the mapping is maintained in the /etc/path_to_inst file:
$ grep asy /etc/path_to_inst
"/isa/asy@1,3f8" 0 "asy"
"/isa/asy@1,2f8" 1 "asy"
There are also drivers without respective hardware, called pseudo drivers. An example of a pseudo driver is random(7D), the random number generator driver. Pseudo drivers have no physical device nodes to attach to. We have to synthesize artificial instances via driver.conf file:
$ cat /kernel/drv/random.conf | egrep -v '^#|^
The system obeys and creates a node for instance 0:
$ prtconf -DP | grep random
random, instance #0 (driver name: random)
Drivers can retrieve their instance number with ddi_get_instance().
Minor number
Outside the kernel, devices are identified by their {major, minor} pairs, also know as dev_t. The major number range is owned by the system. It assigns major numbers when drivers are installed and keeps the list in /etc/name_to_major:
$ grep asy /etc/name_to_major
asy 106
The minor number range is owned by the driver. A minor number becomes visible to the userland when the driver creates a minor node using ddi_create_minor_node() 2, which takes minor number as one of its arguments:
int ddi_create_minor_node(dev_info_t *dip, char *name, int
spec_type, minor_t minor_num, char *node_type, int flag);
Problem is, the minor number range is shared among all driver instances, so each instance can only use a subrange. If each instance needs exactly one minor node, then the node's minor number can equal instance number, i.e. the 4th argument in ddi_create_minor_node() is set to instance number.
Things get a bit fancier in case of multiple minor nodes per instance. Serial drivers typically create two nodes per node: one in /dev/term and one in /dev/cua:
$ ls -lL /dev/{term,cua}/[ab]
crw------- 1 uucp uucp 106, 131072 Jun 29 19:04 /dev/cua/a
crw------- 1 uucp uucp 106, 131073 Jun 29 19:04 /dev/cua/b
crw-rw-rw- 1 root sys 106, 0 Jun 29 19:04 /dev/term/a
crw-rw-rw- 1 root sys 106, 1 Jun 29 19:04 /dev/term/b
106, as we saw earlier, is asy major number. Minor numbers 0 and 131072 (0x20000) belong to instance 0, and 1 and 131073 (0x20001) to instance 1. The instance/minor mapping is not 1:1 here.
Conversion
The driver holds the algorithm for mapping instances into minors and vice versa. When the kernel needs to find out instance number from a minor number, it has to ask the driver by calling getinfo(9E) entry point with the DDI_INFO_DEVT2INSTANCE command. One example could be found in spec_open() which calls e_ddi_hold_devi_by_dev().
1 Per-instance data is called soft state and explicitly supported in DDI, see ddi_soft_state(9F) man page.
2 A whole lot of action can be triggered by ddi_create_minor_node(). See dacfc_match_create_minor() and /etc/dacf.conf file on your nearest Solaris system.
name="random" parent="pseudo" instance=0;
The system obeys and creates a node for instance 0:
___FCKpd___3
Drivers can retrieve their instance number with ddi_get_instance().
Minor number
Outside the kernel, devices are identified by their {major, minor} pairs, also know as dev_t. The major number range is owned by the system. It assigns major numbers when drivers are installed and keeps the list in /etc/name_to_major:
___FCKpd___4
The minor number range is owned by the driver. A minor number becomes visible to the userland when the driver creates a minor node using ddi_create_minor_node() 2, which takes minor number as one of its arguments:
___FCKpd___5
Problem is, the minor number range is shared among all driver instances, so each instance can only use a subrange. If each instance needs exactly one minor node, then the node's minor number can equal instance number, i.e. the 4th argument in ddi_create_minor_node() is set to instance number.
Things get a bit fancier in case of multiple minor nodes per instance. Serial drivers typically create two nodes per node: one in /dev/term and one in /dev/cua:
___FCKpd___6
106, as we saw earlier, is asy major number. Minor numbers 0 and 131072 (0x20000) belong to instance 0, and 1 and 131073 (0x20001) to instance 1. The instance/minor mapping is not 1:1 here.
Conversion
The driver holds the algorithm for mapping instances into minors and vice versa. When the kernel needs to find out instance number from a minor number, it has to ask the driver by calling getinfo(9E) entry point with the DDI_INFO_DEVT2INSTANCE command. One example could be found in spec_open() which calls e_ddi_hold_devi_by_dev().
1 Per-instance data is called soft state and explicitly supported in DDI, see ddi_soft_state(9F) man page.
2 A whole lot of action can be triggered by ddi_create_minor_node(). See dacfc_match_create_minor() and /etc/dacf.conf file on your nearest Solaris system.