Card Readers and USB keys using udev

Posted by chris on Sun 24 Apr 2005 at 21:08

Tags: ,

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 udev
as 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.

 

 


Posted by Anonymous (212.135.xx.xx) on Thu 5 May 2005 at 18:59
One problem with this is when you have a card reader that provides no notification to the kernel of media insertion events.

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 ]

Posted by chris (80.202.xx.xx) on Thu 5 May 2005 at 22:03
[ View Weblogs ]
This is correct - but note that you get the same effect with merging the name and options as in the original article:

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 ]

Posted by Anonymous (212.135.xx.xx) on Sat 7 May 2005 at 10:59
Ah - I hadn't spotted that, and the option is news to me. That's good to know about. I suppose it won't work properly if you have a card with multiple partitions on it, but that's fairly unlikely for most people.

Mike.

[ Parent | Reply to this comment ]

Posted by chris (80.202.xx.xx) on Sun 8 May 2005 at 08:15
[ View Weblogs ]
If you have a card with multiple partitions on it then this will still create all of them. The issue here is that some devices (most often the multi-card readers) only tell the system about the actual device (e.g. /dev/card_ms) and not the partitions.

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 ]

Posted by Anonymous (69.195.xx.xx) on Mon 23 May 2005 at 13:10
Actually, while the NAME{all_partitions} syntax has always worked for me in the past, it suddenly stopped working for me when I "upgraded" to udev-056 from 04something. Now only the OPTIONS="all_partitions" with %n after the name gives me back the old behaviour. I don't know whether it's just me or what's going on.

[ Parent | Reply to this comment ]

Posted by chris (217.8.xx.xx) on Mon 23 May 2005 at 13:32
[ View Weblogs ]
I've got udev 0.056-2 - and the NAME{all_partitions} is in active use. Wish I had an idea as to why it might be happening - but all I can say is "works4me" - which of course is a really irritating answer I know.

Can't see anything on BTS about it either.

[ Parent | Reply to this comment ]

Posted by Anonymous (194.138.xx.xx) on Fri 6 May 2005 at 16:49
SYSFS{model}="MOBILE Disk " - again taken from the messages log file

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 ]

Posted by chris (80.202.xx.xx) on Fri 6 May 2005 at 17:35
[ View Weblogs ]
I thought I had :)

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 ]

Posted by chris (80.202.xx.xx) on Fri 20 May 2005 at 21:34
[ View Weblogs ]
Now - here's something I've noticed.

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 ]

Posted by Anonymous (213.23.xx.xx) on Sun 23 Oct 2005 at 21:23
Is there anything I have to do with udev to make this work? I did /etc/init.d/udev stop and start but nothing happens with the rules, there is no device created.

$ 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 ]

Posted by chris (80.203.xx.xx) on Mon 24 Oct 2005 at 17:37
[ View Weblogs ]
Logging - what is set in /etc/udev/udev.conf under udev_log?

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 ]

Posted by Anonymous (84.51.xx.xx) on Fri 18 Nov 2005 at 23:04
This all works, except,

you need to add your user to the 'plugdev' group and/or 'cdrom' group

[ Parent | Reply to this comment ]

Posted by Anonymous (71.118.xx.xx) on Sun 11 Dec 2005 at 03:48
Thanks for the clearly written guide on udev. It seems like this should solve the problem with my usb hard drive:
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 ]

Posted by chris (80.203.xx.xx) on Sun 11 Dec 2005 at 09:44
[ View Weblogs ]
It should.

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 ]

Posted by Anonymous (205.200.xx.xx) on Tue 4 Apr 2006 at 15:07

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 ]

Posted by chris (217.8.xx.xx) on Tue 4 Apr 2006 at 15:16
[ View Weblogs ]
An interesting point :)

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 ]

Posted by LeoBreebaart (213.211.xx.xx) on Sat 8 Jul 2006 at 10:58

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 ]

Posted by chris (213.187.xx.xx) on Sat 8 Jul 2006 at 15:22
[ View Weblogs ]
Thats interesting. I've not updated udev or kernel in a while - but at least now I'll know why it all suddenly stopped working :)

[ Parent | Reply to this comment ]

Posted by Anonymous (68.3.xx.xx) on Wed 4 Oct 2006 at 21:03
I spent a lot of time messing aroud with spaces in the model name of my USB memory stick. The command
tail -f /var/log/messages
produced 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/sda
listed 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 ]

Posted by Anonymous (68.146.xx.xx) on Fri 14 Oct 2011 at 23:51
I had to use lines like the below on wheezy, which match what "man udev" says about rules files:

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 ]

Sign In

Username:

Password:

[Register|Advanced]

 

Flattr

 

Current Poll

What do you use for configuration management?








( 333 votes ~ 1 comments )