| ------------- | |
| MDEV Primer | |
| ------------- | |
| For those of us who know how to use mdev, a primer might seem lame. For | |
| everyone else, mdev is a weird black box that they hear is awesome, but can't | |
| seem to get their head around how it works. Thus, a primer. | |
| ----------- | |
| Basic Use | |
| ----------- | |
| Mdev has two primary uses: initial population and dynamic updates. Both | |
| require sysfs support in the kernel and have it mounted at /sys. For dynamic | |
| updates, you also need to have hotplugging enabled in your kernel. | |
| Here's a typical code snippet from the init script: | |
| [0] mount -t proc proc /proc | |
| [1] mount -t sysfs sysfs /sys | |
| [2] echo /sbin/mdev > /proc/sys/kernel/hotplug | |
| [3] mdev -s | |
| Alternatively, without procfs the above becomes: | |
| [1] mount -t sysfs sysfs /sys | |
| [2] sysctl -w kernel.hotplug=/sbin/mdev | |
| [3] mdev -s | |
| Of course, a more "full" setup would entail executing this before the previous | |
| code snippet: | |
| [4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev | |
| [5] mkdir /dev/pts | |
| [6] mount -t devpts devpts /dev/pts | |
| The simple explanation here is that [1] you need to have /sys mounted before | |
| executing mdev. Then you [2] instruct the kernel to execute /sbin/mdev whenever | |
| a device is added or removed so that the device node can be created or | |
| destroyed. Then you [3] seed /dev with all the device nodes that were created | |
| while the system was booting. | |
| For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem | |
| (assuming you're running out of flash). Then you want to [5] create the | |
| /dev/pts mount point and finally [6] mount the devpts filesystem on it. | |
| ------------- | |
| MDEV Config (/etc/mdev.conf) | |
| ------------- | |
| Mdev has an optional config file for controlling ownership/permissions of | |
| device nodes if your system needs something more than the default root/root | |
| 660 permissions. | |
| The file has the format: | |
| [-][envmatch]<device regex> <uid>:<gid> <permissions> | |
| or | |
| [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions> | |
| or | |
| $envvar=<regex> <uid>:<gid> <permissions> | |
| For example: | |
| hd[a-z][0-9]* 0:3 660 | |
| The config file parsing stops at the first matching line unless this line | |
| starts with "-". If no line is matched, then the default of 0:0 660 is used. | |
| To set your own default, simply create your own total match like so: | |
| .* 1:1 777 | |
| You can rename/move device nodes by using the next optional field. | |
| <device regex> <uid>:<gid> <permissions> [=path] | |
| So if you want to place the device node into a subdirectory, make sure the path | |
| has a trailing /. If you want to rename the device node, just place the name. | |
| hda 0:3 660 =drives/ | |
| This will move "hda" into the drives/ subdirectory. | |
| hdb 0:3 660 =cdrom | |
| This will rename "hdb" to "cdrom". | |
| Similarly, ">path" renames/moves the device but it also creates | |
| a direct symlink /dev/DEVNAME to the renamed/moved device. | |
| You can also prevent creation of device nodes with the 4th field as "!": | |
| tty[a-z]. 0:0 660 ! | |
| pty[a-z]. 0:0 660 ! | |
| If you also enable support for executing your own commands, then the file has | |
| the format: | |
| <device regex> <uid>:<gid> <permissions> [=path] [@|$|*<command>] | |
| or | |
| <device regex> <uid>:<gid> <permissions> [>path] [@|$|*<command>] | |
| or | |
| <device regex> <uid>:<gid> <permissions> [!] [@|$|*<command>] | |
| For example: | |
| ---8<--- | |
| # block devices | |
| ([hs]d[a-z]) root:disk 660 >disk/%1/0 | |
| ([hs]d[a-z])([0-9]+) root:disk 660 >disk/%1/%2 | |
| mmcblk([0-9]+) root:disk 660 >disk/mmc/%1/0 | |
| mmcblk([0-9]+)p([0-9]+) root:disk 660 >disk/mmc/%1/%2 | |
| # network devices | |
| (tun|tap) root:network 660 >net/%1 | |
| ---8<--- | |
| The special characters have the meaning: | |
| @ Run after creating the device. | |
| $ Run before removing the device. | |
| * Run both after creating and before removing the device. | |
| The command is executed via the system() function (which means you're giving a | |
| command to the shell), so make sure you have a shell installed at /bin/sh. You | |
| should also keep in mind that the kernel executes hotplug helpers with stdin, | |
| stdout, and stderr connected to /dev/null. | |
| For your convenience, the shell env var $MDEV is set to the device name. So if | |
| the device "hdc" was matched, MDEV would be set to "hdc". | |
| ---------- | |
| FIRMWARE | |
| ---------- | |
| Some kernel device drivers need to request firmware at runtime in order to | |
| properly initialize a device. Place all such firmware files into the | |
| /lib/firmware/ directory. At runtime, the kernel will invoke mdev with the | |
| filename of the firmware which mdev will load out of /lib/firmware/ and into | |
| the kernel via the sysfs interface. The exact filename is hardcoded in the | |
| kernel, so look there if you need to know how to name the file in userspace. | |
| ------------ | |
| SEQUENCING | |
| ------------ | |
| Kernel does not serialize hotplug events. It increments SEQNUM environmental | |
| variable for each successive hotplug invocation. Normally, mdev doesn't care. | |
| This may reorder hotplug and hot-unplug events, with typical symptoms of | |
| device nodes sometimes not created as expected. | |
| However, if /dev/mdev.seq file is found, mdev will compare its | |
| contents with SEQNUM. It will retry up to two seconds, waiting for them | |
| to match. If they match exactly (not even trailing '\n' is allowed), | |
| or if two seconds pass, mdev runs as usual, then it rewrites /dev/mdev.seq | |
| with SEQNUM+1. | |
| IOW: this will serialize concurrent mdev invocations. | |
| If you want to activate this feature, execute "echo >/dev/mdev.seq" prior to | |
| setting mdev to be the hotplug handler. This writes single '\n' to the file. | |
| NB: mdev recognizes /dev/mdev.seq consisting of single '\n' character | |
| as a special case. IOW: this will not make your first hotplug event | |
| to stall for two seconds. |