Card Readers and USB keys using udev
Posted by chris on Sun 24 Apr 2005 at 21:08
I have three different memory card readers - each providing access to 8 or 9 different card formats. In addition I have a MobileDisk USB keyring. Debian supports these quite well out of the box but the device node changes with each time you plug and unplug the devices - is my CF reader /dev/sdd1 or /dev/sde1?
While you can look this up each time it makes it hard to set up fstab so that non-root users can mount the device.
Background
This article is written based on a debian unstable installation using a 2.6 kernel. It should work just fine on sarge - but you will need to be running 2.6. It is very much a "what-I-did" article :)
Under the 2.4 kernel this was to some extent changed by the implementation of devfs. However - the devfs design has some problems - so for 2.6 udev is available.
Two of the card readers I have are Lexar - the third is a Unomas omnicard reader. This article will concentrate on the Lexar readers - since the Unomas reader does not report the necessary information for sysfs (and so I couldn't distinguish between the card slots - if anyone gets this working please comment this article).
Getting udev
Simply run
apt-get install udevas root. It is strongly advised that you restart the machine after this (sadly)
Am I running udev?
Have you got a udevd process (ps aux | grep udevd)? Earlier versions of udev also created a /.dev directory - at least on the two sid boxen I have this is no longer present.
Using udev to generate a known device
Well - first we need to find out how the device identifies itself.
Run the following and then plug in the device
tail -f /var/log/messages
For the Lexar reader I see
Apr 22 13:52:18 localhost kernel: usb 1-2: new full speed USB device using uhci_hcd and address 6 Apr 22 13:52:18 localhost kernel: scsi3 : SCSI emulation for USB Mass Storage devices Apr 22 13:52:19 localhost usb.agent[25897]: usb-storage: already loaded Apr 22 13:52:23 localhost kernel: Vendor: Lexar Model: USB Storage-SMC Rev: I18A Apr 22 13:52:23 localhost kernel: Type: Direct-Access ANSI SCSI revision: 00 Apr 22 13:52:23 localhost kernel: Attached scsi removable disk sda at scsi3, channel 0, id 0, lun 0 Apr 22 13:52:23 localhost kernel: Vendor: Lexar Model: USB Storage-CFC Rev: I18A Apr 22 13:52:23 localhost kernel: Type: Direct-Access ANSI SCSI revision: 00 Apr 22 13:52:23 localhost kernel: Attached scsi removable disk sdb at scsi3, channel 0, id 0, lun 1 Apr 22 13:52:23 localhost kernel: Vendor: Lexar Model: USB Storage-SDC Rev: I18A Apr 22 13:52:23 localhost kernel: Type: Direct-Access ANSI SCSI revision: 00 Apr 22 13:52:23 localhost kernel: Attached scsi removable disk sdc at scsi3, channel 0, id 0, lun 2 Apr 22 13:52:23 localhost kernel: Vendor: Lexar Model: USB Storage-MSC Rev: I18A Apr 22 13:52:23 localhost kernel: Type: Direct-Access ANSI SCSI revision: 00 Apr 22 13:52:23 localhost kernel: Attached scsi removable disk sdd at scsi3, channel 0, id 0, lun 3 Apr 22 13:52:23 localhost scsi.agent[25951]: sd_mod: loaded sucessfully (for disk) Apr 22 13:52:23 localhost scsi.agent[25973]: sd_mod: loaded sucessfully (for disk) Apr 22 13:52:23 localhost scsi.agent[25975]: sd_mod: loaded sucessfully (for disk) Apr 22 13:52:23 localhost scsi.agent[25941]: sd_mod: loaded sucessfully (for disk)
This shows me that the device is located on the disks /sda, /sdb, /sdc and /sdd (it has 4 reader slots) - however - next time this could be /sde, /sdf etc). More importantly - it shows some information that sysfs (/sys) knows about - The Vendor and Model lines. This information will be repeated within the /sys sysfs file system in files called vendor and model ...
... and udev can use it to recognize the devices. Udev installs a set of config files under /etc/udev. Part of this is /etc/udev/rules.d/ - each file here will be processed to generate the ruleset that udev will use to determine device names for each device.
By adding a new file (local.rules) in this directory you can add new rules (it's a standard .d directory - the files will be read in alphanumeric order to create the rules that udev will use). The rules for the above card reader (one per card type) look like:
BUS="scsi", SYSFS{model}="USB Storage-SMC", NAME{all_partitions}="card_sm"
BUS="scsi", SYSFS{model}="USB Storage-CFC", NAME{all_partitions}="card_cf"
BUS="scsi", SYSFS{model}="USB Storage-SDC", NAME{all_partitions}="card_sd"
BUS="scsi", SYSFS{model}="USB Storage-MSC", NAME{all_partitions}="card_ms"
Things to note
- BUS="scsi" - the message log showed that this device was detected as scsi.
- SYSFS{model}="A string" - a file called "model" under /sys (any nesting level) contains the string "A string" (for this reader the messages output gives the strings)
- NAME{all_partitions}="device" - this will create /dev/device, /dev/device1 thru /dev/device15. If the line read NAME="device" - then for the Lexar readers I get only /dev/device and that's the equivalent of /dev/hda - a pointer to the device - not to a partition.
Restarting udev then plugging in the device should therefore result in the creation of (amongst several others) /dev/card_sm1, /dev/card_cd1, /dev/card/sd1 and /dev/card_ms1 - the first partition on each device. These names are the same whatever scsi host the reader has been allocated to. This means that in /etc/fstab you can add something like
/dev/card_sd1 /media/sd vfat rw,user,noauto 0 0 /dev/card_cf1 /media/cf vfat rw,user,noauto 0 0 /dev/card_sm1 /media/sm vfat rw,user,noauto 0 0 /dev/card_ms1 /media/ms vfat rw,user,noauto 0 0
And users can then "mount /media/cf" for themselves.
The MobileDisk USB key is slightly different. This has a model of "MOBILE Disk " (including spaces). However - when plugged in it generated /dev/sdx and /dev/sdx1 (where x is the letter for the scsi host that was allocated. This means that we have the partition mount point. We simply need to rename it.
BUS="scsi", SYSFS{model}="MOBILE Disk ", KERNEL="sd?1", NAME="%k", SYMLINK="mobiledisk"
Things to note
- BUS="scsi"
- SYSFS{model}="MOBILE Disk " - again taken from the messages log file
- KERNEL="sd?1" - the device (first partition on the USB key) will normally get a device name of the form /dev/sdx1 - where x can vary
- NAME="%k" - the /dev/sdx1 link will be created as default
- SYMLINK="mobiledisk" - a symlink /dev/mobiledisk will be created pointing to the /dev/sdx1 partition
Then you can have an /etc/fstab line that looks like
/dev/mobiledisk /media/mobiledisk vfat rw,user,noauto 0 0
Where next?
A following article will cover getting autofs to automount these devices - giving plugin/use/remove functionality to linux.
NAME{all_partitions}="card_ms"However - this comment is a good explanation of why you need to do this - and what is happening behind the scenes :)
[ Parent | Reply to this comment ]
Mike.
[ Parent | Reply to this comment ]
So - using the all_partitions option will create all partitions (in this example /dev/card_ms, /dev/card_ms1 up to /dev/card_ms15).
If you have only one partition then only /dev/card_ms1 will actually work - the others are just device nodes that do not work. If you have more partitions then the relevant device nodes will work.
So - all_partitions doesn't hurt multi-partition cards - it's just untidy in the /dev namespace.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
Can't see anything on BTS about it either.
[ Parent | Reply to this comment ]
well, you should say that there fileds you specify are in fact _files_ in the /sys (sysfs) metafilesystem. There is more info than the one provided in the logs there.
Lets say you have two pen drives, same model, manufacturer, size, everything...
You can distinguish between them by their serial numbers, if the info is provided by the device
[ Parent | Reply to this comment ]
This information will be repeated within the /sys sysfs file system in files called vendor and model
However - you're right that there are several other files present that can be used.
I hadn't intended this to be an explanation of the /sys system - though this is probably something that should be covered here.
[ Parent | Reply to this comment ]
When I started with 2.6 kernels and udev I set up the following:
BUS="scsi", SYSFS{model}="MOBILE Disk ", KERNEL="sd?1", NAME="%k", SYMLINK="mobiledisk"Note the spaces in the SYSFS{model} line - these spaces were present in the file called model in the /sys directory list relevant to this USB device and were required to make this line trigger.
Recently I've noticed that this line didn't work anymore (OK - so I don't use the MobileDisk USB key much since I got my dandy pretec 1GB model :)).
I found that to make it work I had to remove the spaces even though the model file looks identical (spaces and all).
So - it appears that trailing spaces are now removed before comparison (at least that's what appears to be happening).
Just thought I'd mention it.
[ Parent | Reply to this comment ]
$ cat /etc/udev/rules.d/local.rules
BUS="scsi", SYSFS{model}="USB Storage-CFC ", NAME{all_partitions}="card_cf"
udevinfo shows this:
follow the "device"-link to the physical device:
looking at the device chain at '/sys/devices/pci0000:00/0000:00:02.2/usb3/3-5/3-5:1.0/host12/tar get12:0:0/12:0:0:1':
BUS=="scsi"
ID=="12:0:0:1"
DRIVER=="sd"
SYSFS{device_blocked}=="0"
SYSFS{iocounterbits}=="32"
SYSFS{iodone_cnt}=="0x16"
SYSFS{ioerr_cnt}=="0x2"
SYSFS{iorequest_cnt}=="0x16"
SYSFS{max_sectors}=="240"
SYSFS{model}=="USB Storage-CFC "
SYSFS{queue_depth}=="1"
SYSFS{queue_type}=="none"
SYSFS{rev}=="010K"
SYSFS{scsi_level}=="3"
SYSFS{state}=="running"
SYSFS{timeout}=="30"
SYSFS{type}=="0"
SYSFS{vendor}=="GENERIC "
I don't see a /dev/card_cf entry after plugging in the card reader.
I wish udev would log a little bit more about its actions...
[ Parent | Reply to this comment ]
Something to try - in the rule - remove the trailing space in the model part (I sometimes seem to need trailing spaces - sometimes not - and I've never really investigated. I suspect differing versions of udev but I don't really know).
[ Parent | Reply to this comment ]
you need to add your user to the 'plugdev' group and/or 'cdrom' group
[ Parent | Reply to this comment ]
http://lists.debian.org/debian-user/2005/12/msg01018.html
Any idea if it's possible to get gkrellm to see udev-created device nodes?
Jason
[ Parent | Reply to this comment ]
The devices are real, or at least symlinks - depends on how you configure udev. For my configuration I get real devices for the card reader (/dev/card*), for the USB key a real link /dev/sd?1 where ? is whatever the kernel assigns with a symlink to that dev of /dev/mobiledisk
gkrellm doesn't know how these are created - it just looks in the /dev directory.
[ Parent | Reply to this comment ]
Great article! After following the instructions I still wasn't able to mount my device:
mount: /dev/iriver is not a block device
I set udev_log="info" in /etc/udev/udev.conf to get some more information. From what then appeared in /var/log/syslog (after removing/reinserting the device), it looked like the udev rule I added was matching both /dev/sd* as well as /dev/sg* (scsi generic), and that udev was renaming _both_ of these as /dev/iriver.
I added a KERNEL="sd*" clause to my rule, so that it will only match sd* devices, and not the sg (scsi generic) devices, so my rule ended up looking like:
BUS="scsi", KERNEL="sd*" SYSFS{model}="T30 Pure", NAME{all_partitions}="iriver"After this change it is now working.
[ Parent | Reply to this comment ]
When I plug in my USB keyring or multicard reader I only get sd* devices. For my mp3 player I also see sg* and - for that rule I have also got the KERNEL="sd*" stanza :)
However - I purchased that player long long after I wrote this article - so that's why it's not mentioned.
[ Parent | Reply to this comment ]
Many months after successfully using the instructions in this article (thanks, chris!), things "suddenly" stopped working for me: the new /dev/ symlink nodes were no longer being created (on Debian unstable) — somehow the rules in local.rules were no longer firing.
I spent some time looking at the udev logs and the documentation, and finally I saw the problem: the parts of the udev rule that do the matching (but of course not the ones that specify actions!) now have to use "==" instead of "=" (as used in the article) as the comparison operator.
So e.g.
SYSFS{product}="iRiver iHP-100 Series", KERNEL="sd?1", NAME="%k", SYMLINK="iriver"
became:
SYSFS{product}=="iRiver iHP-100 Series", KERNEL=="sd?1", NAME="%k", SYMLINK="iriver"
and after that everything worked again.
--
Leo Breebaart
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
tail -f /var/log/messagesproduced this model number:" PDU01_256 66A2.0 Rev: 0.00". However, that did not work, and neither did any combination of spaces.
I found a great utility to help solve this problem - udevinfo. The command
udevinfo -a -p /sys/block/sdalisted all the information that udev found for installed scsi devices. It was a simple matter of finding my device, and the model, which turned out to be "PDU01_256 66A2.0". Now it works!
Geat article, except for not mentioning this simple tool to keep this project simple and quick!
[ Parent | Reply to this comment ]
BUS=="scsi", SYSFS{model}=="USB SD Reader", NAME{all_partitions}="card_sd"
(Note the double equals signs on the first two things).
[ Parent | Reply to this comment ]
So, when you plug the card reader in, udev happily creates /dev/sd_reader, but when you subsequently plug a card into the reader, the kernel doesn't see it, and you can't mount /dev/sd_reader1 until the kernel has re-scanned the partition table.
You can solve this with a udev rule like this:-
BUS="usb", KERNEL="sd*", SYSFS{manufacturer}="SanDisk Corporation", SYSFS{product}="ImageMate CompactFlash USB", NAME="sandisk_cf%n", OPTIONS="all_partitions"
The "all_partitions" bit makes udev create device nodes for all possible partitions on the device, so when you plug a card in and try to mount /dev/sd_reader1, the kernel sees a read on a non-existent device and re-scans the partition table for you, making the mount work. This makes handling dumb card readers much nicer, though you do get a few extraneous device nodes.
[ Parent | Reply to this comment ]