I am trying to find out a high-level overview of how the USB storage driver works in Linux. I'm looking for a simple article or even a picture/flowchart describing how it works.
Basically, I'm looking to get these questions answered:
When you plug the device into your computer, what happens? Is there a daemon that picks up on it, or does the event trigger an interrupt somewhere? Does the core USB driver read information about the device before passing control over to the USB storage driver? How does it decide what type of device it is? How does the device get mounted, and what allows it to communicate with the computer's filesystem? When I copy a file, what does the data flow look like in the kernel?
I hope the question isn't too vague - I tried Google to no avail, so I'm wondering if anyone knows any articles or diagrams that can explain this, or perhaps if they can explain it themselves without too much effort. Thanks.
No, it is a very good question.
The block writing is going in linux with the block device layer. The filesystems are working with this block dev layer.
If this layer wants to write something out, says it to the driver of the usb master device. This driver is talking with the usb controller chip of the motherboard.
This chip is very simple: the usb is practically a serial port, with a lot of extensions, mainly targeting the autoconfiguration and the power management. But basically, you can write out bytes, and read in bytes.
Your questions:
When you plug the device into your computer, what happens? Is there a daemon that picks up on it, or does the event trigger an interrupt somewhere?
The device (usb slave) says the master (in the motherboard): "I am here". The usb controller chip gets the message and says it to the kernel (normally) with an interrupt. The kernel reinitializes and rescans the usb bus, and says the udev: "here is a new 1234:5678 usb device on the usb tree 1.3.5"
"How does it decide what type of device it is?"
Usb devices have a vendor and model id, and they can say this on ask. Google for "usb ids".
"How does the device get mounted, and what allows it to communicate with the computer's filesystem?"
The kernel only loads the driver and says the udev (which is in userspace): "Here is a new block device on device number 22:16". From this, udev tries to mount this with some userspace daemon, it is already distribution-dependant.
Related
I want to learn how Linux OS understands the underlying hardware.Can anyone suggest me where to start for getting this understanding,As of now i just know the '/dev' sub-directory plays a vital role in that.
It has the device special files which are like a portal to the device driver which then takes it to the physical device.
I read somewhere that Udev daemon listens to the netlink socket to collect this information and Udev device manager detects addition and removal of devices as they occur.
But with these i am just not satisfied with the thought of how Linux reads the hardware.
Please let me know where to start to understand this, i am so thankful to anyone trying to help.
I think at first you need to find out how the memory mapping works. What is the address space and how it relates to physical memory. Then you could read about how the hardware is mapped in address space and how to access it. It is a big amount of docs to read.
Some of those information are in Linux Documentation Project.
Additionally some knowledge about electronic would be helpful.
In general - Linux for communication with devices needs some "channel" of communication. This channel may be for example ISA, PCI, USB, etc bus. For example PCI devices are memory mapped devices and Linux kernel communicates with them via memory accesses. So first Linux needs to see given device in some memory area and then it is able to configure this device and do some communication with it.
In case of USB devices it is a little bit complicated because USB devices are not memory mapped. You need to configure USB host first to be able to communicate with USB devices. Every communication with USB device is achieved via USB host.
There are also devices which are not connected via ISA, PCI or USB. They are connected directly to the processor and visible under some memory address. This solution is usually implemented in embedded devices. For example ARM processors use this approach.
Regarding udev - it is user-space application which listens for events from Linux kernel and helps other applications with recognizing device addition and configuration.
I need to detect when a USB serial device is plugged or unplugged on my embedded system and know what is the tty associated with it.
My system runs over a 2.6 Linux Kernel.
Since I don't have write access to udev rules, nowadays I'm trying to get this information from the file system, looking for modifications in /sys/bus/usb/devices directory. However, I'm facing some problems with this approach.
I know what is the Id BUS of the USB port connected (e.g 1-1.3). So, I search for the associated tty (looking for a directory in /sys/bus/usb/devices/<Id BUS>:1.0/tty/ - e.g. /sys/bus/usb/devices/1-1.3:1.0/tty/ttyACM0). This way I know that I should use /dev/ttyACM0 to communicate with my device.
But, sometimes, this device (/dev/ttyACM0) does not exist.
Is there any better way to get this information?
I even thought trying to get this information from the syslog, but I don't know whether this is a pretty good idea.
Edit:
Only to clarify, my system needs to be able to detect state changes in the USB bus, i.e. detecting when a new device is plugged (and getting the tty name linked to it) or an existing one is unplugged.
The system is monitoring up to N USB/serial devices, which are plugged to it using an USB HUB. During its normal execution new devices can be plugged, existing devices can be removed (or rebooted by a remote command - out of this scope). When a device is rebooted, it could receive a different tty from the previous one used before (e.g. ttyACM0 -> ttyACM3), since the kernel designates to it a tty which is free at the moment, and it is a big problem to me.
Netlink is the preferred mechanism for communication between kernel and userspace.
You would create a Netlink socket with family NETLINK_KOBJECT_UEVENT, listen on that socket and filter out messages that contain SUBSYSTEM=usb and ACTION=add for USB plug events or ACTION=remove for USB unplug events.
I wrote a USB abstraction library called libusbp. You should look at its port_name example, which shows how to use libusbp to get the serial port name (e.g. /dev/ttyACM0) for a USB serial device. Behind the scenes, libusbp gets this information using libudev.
Check if the virtual file is deleted using stat.
#include <sys/statvfs.h>
...
struct stat sb;
return (stat("/dev/ttyUSB0", &sb) == 0); // true if open, false otherwise
I have a embedded device that runs linux 2.6.37.
I want my application to know when the USB is connected.
Currently I can achieve this by pooling
/sys/devices/platform/musb/musb-hdrc.0/vbus.
However this approach does not distinguish between a USB charger or a USB host.
I found this udev approach but I don't think it's available in my version of the kernel. because I did not find any USB related nodes in my /dev. This discussing also shows that it might not be feasible, ether.
I also found linux hotplug and tried the netlink example, but I didn't see any output running the example when I connect/disconnect the USB cable.
What I want to do is to detect connection type on the device, when USB is connected, and prepare (unmount file system) and switch to g_file_storage if device is connected to a host, and do nothing if device is connect to a charger.
How shall I achieve this?
To achieve that, you can use the inotify(7) feature, available in all linux kernels to be awaken as soon as some device node gets created in /sys.
To know what type of device you have, you have to read the usb info from proper usb ioctl call (or if you are not a kernel interface expert, using the libusb interface) to get the device vendor, device id and device class fields coming from the device. Normally, the hotplug software gets informed on these clase of events (via a special socket). The most probably reason you don't get the device properly initialized is some misconfiguration in the config files for udev system, which normally has one entry for each possible device vendor/device id pair and allows it to load the appropiate device driver to control it. The process continues with the device driver module creating dynamically the actual devices, and they'll appear in the /dev/ filesystem as a consequence of some other kernel event to udevd.
Read apropiate documents in <linux_src>/Documentation (this directory directory belongs to the linux kernel source code, so you'll probably need to install it), and udevd(8) man pages to be able to add a new usb.
On 2.6.37 kernel, this could be done by polling
/sys/devices/platform/musb-omap2430.0/musb-hdrc.0/mode
If handshake with host is successful then it will read as "peripheral", if fail it'll be "idle".
I'm researching ways to communicate with a USB device in Linux and would prefer to not write a Linux Kernel driver. I understand that libusb exists and is a user-land library that would work, but our embedded device doesn't support usbfs ( and would be really a pain to change kernels to add the support ).
So my question is basically this: Is it possible / advisable to communicate with a USB device by directly reading and writing to the /dev/USB or the udev file corresponding to the USB device thus bypassing the need for a custom Linux Driver and usbfs?
I'm hoping it's possible to communicate using the USB devices protocol just by reading / writing protocol packets directly through file-type read/write commands once the /dev/USB or udev device file is open.
Thoughts and suggestions please.
FOLLOW UP:
Since the USB device I needed to talk to is a USB HID class device, I was able to use libudev and the standard Linux USB HID RAW driver by reading / writing directly to /dev/hidraw0 ( or the appropriate /dev/hidraw device ). It wasn't necessary to write a custom driver for a simple USB HID device.
Jim, I don't think you can escape the need to write a driver and just manage to read the USB file in /dev. Because who defines as to what should happen when you do a read() on the USB device file? And who defines what action should be initiated when you invoke sysioctl()? Your driver! In other words, the device files are themselves incapable of anything until they are supported by the underlying drivers. In fact, you can treat the device files to be an abstraction of the underlying driver! So, no driver, no use of device file :(
I suggest you go through the following articles about how to write a driver and also understand the USB internals-
http://www.linux-usb.org/USB-guide/c15.html
http://www.linuxjournal.com/article/4786 ( Slightly outdated )
I am wondering, do you need a specific device driver to read a usb device in Linux, or should it just be able to be read. If I connect my cell phone or iPod touch to my linux box, it is not found is /proc/partitions and thus is not a mountable device by fdisks standards, though gnomes nautilus does in fact mount the iPod but not the windows mobile touch pro cell phone.
So I am interested, If I just wanted to read a device(iPod touch) in linux, how can I do so. How can I get a hold of a descriptor of a set usb device so I can read it.
Thanks all.
You can access raw USB endpoints under /dev/usbdev. There is user-space libusb that makes it easier.
Unfortunately there is no simple concept of "just read it" for USB devices (I am assuming that you are not referring to reading and writing the data on the USB bus that make up the USB protocol). In short, you always need a device driver for accessing a USB device and it is up to the driver to implement "the abstraction" of the device used by the system (disk, serial device, etc).