Hard Time in Understanding Module_Device_Table(Usb, Id_Table) Usage

Hard time in understanding MODULE_DEVICE_TABLE(usb, id_table) usage

It is usually used to support hot-plugging, by loading/inserting the driver for a device if not already loaded.

There is a similar question here: Detect the presence of a device when it's hot plugged in Linux

(From my ans)

It works as follows:

  1. Each driver in the code exposes its vendor/device id using:

      MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
  2. At compilation time the build process extracts this infomation from all the drivers and prepares a device table.

  3. When you insert the device, the device table is referred by the kernel and if an entry is found matching the device/vendor id of the added device, then its module is loaded and initialized.

Usb device id table understanding

You should have Linux kernel source at hand to really understand this.

  • Why pen_table is an array?

It wil be necessary in MODULE_DEVICE_TABLE (see Hard time in understanding MODULE_DEVICE_TABLE(usb, id_table) usage) and in defining instance of usb_driver struct, see http://opensourceforu.efytimes.com/2011/11/usb-drivers-in-linux-2/.

  • what type of array initialization is this?

USB_DEVICE is a macro defined in include/linux/usb.h:

#define USB_DEVICE(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
  • how this terminates?

C standard says:

The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject; all subobjects
that are not initialized explicitly shall be initialized implicitly
the same as objects that have static storage duration.

and:

If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate. If an object that has static
storage duration is not initialized explicitly, then:

  • if it has pointer type, it is initialized to a null pointer;
  • if it has arithmetic type, it is initialized to (positive or
    unsigned) zero;
  • if it is an aggregate, every member is initialized (recursively)
    according to these rules;
  • if it is a union, the first named member is initialized
    (recursively) according to these rules.

Thanks to this, id_table is defined as a pointer and not as an array inside usb_driver:

const struct usb_device_id *id_table;

Instead of passing an array size independently a function that uses id_table will increment pointer to id_table until one of its elements is NULL. See this short example that represents this technique:

#include <stdio.h>
#include <stdlib.h>

struct small
{
int a;
int b;
};

struct big
{
struct small *s;
};

struct small table[] =
{
{1, 1},
{2, 2},
{3, 3},
{}
};

int main(void)
{
struct big b = {
.s = table
};

const struct small *s;
/* traverse through table using pointer arithmetic */
for (s = b.s; s->a; s++)
{
printf("%d\n", s->a);
printf("%d\n", s->b);
}

exit(0);
}
  • I tried to initialize device id table in this way, but I am getting
    errors as near initialization

I don't, are you sure you're not trying to redefine pen_table? What's an error message?

How to insert my driver automatically on the insertion of USB mouse in Linux System?

Thanks all for your help.

I follow the udev approach to load module automatically on the USB insertion

Below is the procedure to load your Driver automatically on the Insertion of Hot plug-gable device (I experiment with the USB mouse and below procedure is working fine for it)

  1. Run Following command

    cmd > udevadm info -a -p $(udevadm info -q path -n /dev/input/mouse)

    In place of ?? in the above command user need to add the device ID based on its entry in /dev (e.g.for USB flash drive: sdb1 or sda1 etc. based on the device identity)

  2. Get the Value of the below parameters from the output of above command
    KERNEL, ATTRS{idVendor}, ATTRS{idProduct}, ATTRS{serial}

  3. Go to /etc/dev/rule.d directory and Add your rule

    cmd > sudo vim 40-usbmouse.rules
    ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd?1", ATTRS{idVendor}=="058f", ATTRS{idProduct}=="6387", ATTRS{serial} =="4EPLXAXE", SYMLINK+="usbpd", RUN+="/usr/local/bin/InsertModule.sh"

    Save this file.
    Above rule is defined for the USB Mouse.
    Parameter SYMLINK creates a link of your device in the /dev directory and In RUN+ you can give your script location which is going to execute on your device insertion.

    For more info on How to write a rule refer below link

    http://hackaday.com/2009/09/18/how-to-write-udev-rules/

  4. Now after you define your rule user need to restart the udev to take your rule in notice by kernel.
    cmd > sudo stop udev

    cmd > sudo start udev

  5. Insert your USB and validate that your script which you define in your rule shows its effact.
    For Mouse user can use below command

    cmd > udevadm info -a -p $(udevadm info -q path -n /dev/input/mouse)

P.S.: cmd stands for the command shell (Terminal).The above procedure is working with any USB device.

Minimal Linux kernel options to enable hid input

It turns out OHCI driver is needed to handle low speed peripherals even if they're connected to USB2 (EHCI) controller.

Actually MT7628 has a "secondary" OHCI controller not even advertised in Data Sheet.

This means that, on top of selecting CONFIG_USB_OHCI_HCD=m and CONFIG_USB_OHCI_HCD_PLATFORM=m also the following patch is needed:

diff --git a/arch/mips/boot/dts/ralink/mt7628a.dtsi b/arch/mips/boot/dts/ralink/mt7628a.dtsi
index bf6b6a459bd6..b4ac008fdfdf 100644
--- a/arch/mips/boot/dts/ralink/mt7628a.dtsi
+++ b/arch/mips/boot/dts/ralink/mt7628a.dtsi
@@ -323,6 +323,17 @@ ehci@101c0000 {
interrupts = <18>;
};

+ ohci@101c1000 {
+ compatible = "generic-ohci";
+ reg = <0x101c1000 0x1000>;
+
+ phys = <&usb_phy>;
+ phy-names = "usb";
+
+ interrupt-parent = <&intc>;
+ interrupts = <18>;
+ };
+
ethernet: ethernet@10100000 {
compatible = "ralink,rt5350-eth";
reg = <0x10100000 0x10000>;

Note address 101c1000 is nowhere mentioned in MT7628 programming manual and it's "one cell away" (0x1000) from standard (and documented) EHCI controller cell (at 101c0000).

I assume similar situation is also true for other SoCs because USB standard mandates to "hand over" low speed devices to a legacy USB1 controller.

I hope this will spare a lot of headache to whoever will stumble in the same problem.

PyVISA not listing USB instrument on Linux

I managed to find a solution which I share for the sake of future generations to come. I had just to add a line to the file /etc/udev/rules.d/99-com.rules with the content SUBSYSTEM=="usb", MODE="0666", GROUP="usbusers" (or append this line in case the file already exists) and then restart the computer. In summary:

  1. Enter into the sudo environment:
sudo su

  1. Now add the required line into the respective file:
echo 'SUBSYSTEM=="usb", MODE="0666", GROUP="usbusers"' >> /etc/udev/rules.d/99-com.rules

  1. Restart the computer.

  2. Enjoy.

$ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvisa
>>> pyvisa.ResourceManager().list_resources()
('ASRL/dev/ttyAMA0::INSTR', 'USB0::bla::bla::bla::INSTR')
>>> osc = pyvisa.ResourceManager().open_resource('USB0::bla::bla::bla::INSTR')
>>> osc.query('*IDN?')
'*IDN LECROY,WR640ZI,LCRY28blablabla,7.7.1\n'


Related Topics



Leave a reply



Submit