Friday, December 27, 2024

udev notes

In Yocto notes - 3, we did the following update to drivers/usb/musb/musb_gadget.c to notify MUSB gedget setup/cleanup

int musb_gadget_setup(struct musb *musb) will notify the gadget-setup

and

void musb_gadget_cleanup(struct musb *musb) will notify the gadget-cleanup

To get the details in writing a udev rule for setup/cleanup, we can use udevadm(8)


For example, with the config fragment update usb_configfs.cfg, we get the musb


root@beaglebone-yocto:~# lsmod
Module                  Size  Used by
musb_dsps              16384  0
musb_hdrc             135168  1 musb_dsps


Run the udevadm (in the background), then unload the musb_dsps (rmmod musb_dsps), and we'll see gadget_cleanup in action.


Similarly, if we now insmod musb_dsps, we'll see gadget_setup in action.


root@beaglebone-yocto:~# udevadm monitor --env
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent
:

KERNEL[290.836192] change   /devices/platform/ocp/47400000.target-module/47401400.usb/musb-hdrc.0 (platform)
ACTION=change
DEVPATH=/devices/platform/ocp/47400000.target-module/47401400.usb/musb-hdrc.0
DRIVER=musb-hdrc
EVENT=gadget_setup
MODALIAS=platform:musb-hdrc
OF_ALIAS_0=usb0
OF_COMPATIBLE_0=ti,musb-am33xx
OF_COMPATIBLE_N=1
OF_FULLNAME=/ocp/target-module@47400000/usb@1400
OF_NAME=usb
SEQNUM=1790
SUBSYSTEM=platform

KERNEL[290.836524] bind     /devices/platform/ocp/47400000.target-module/47401400.usb/musb-hdrc.0 (platform)
ACTION=bind
DEVPATH=/devices/platform/ocp/47400000.target-module/47401400.usb/musb-hdrc.0
DRIVER=musb-hdrc
MODALIAS=platform:musb-hdrc
OF_ALIAS_0=usb0
OF_COMPATIBLE_0=ti,musb-am33xx
OF_COMPATIBLE_N=1
OF_FULLNAME=/ocp/target-module@47400000/usb@1400
OF_NAME=usb
SEQNUM=1791
SUBSYSTEM=platform

:


Add a udev rule for gedget-setup at startp. We are matching SUBSYSTEM, ACTION and EVENT keys, then RUN key assignment/append to run our script.


echo "SUBSYSTEM==\"platform\",ACTION==\"change\",ENV{EVENT}==\"gadget_setup\",RUN+=\"/home/root/setup.sh\"" > /etc/udev/rules.d/20-musb-setup-test.rules


setup.sh has the same content as we had in 'USB notes - 2'

#!/bin/ash

modprobe libcomposite
mount -t configfs none /sys/kernel/config/
cd /sys/kernel/config/usb_gadget/
mkdir g
cd g/
echo "0xA55A" > idVendor 
echo "0x0111" > idProduct 
mkdir strings/0x409
echo "0123" > strings/0x409/serialnumber 
echo "hello" > strings/0x409/manufacturer 
echo "ncm" > strings/0x409/product 
mkdir functions/ncm.usb0
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ncm" > configs/c.1/strings/0x409/configuration 
ln -s functions/ncm.usb0 configs/c.1/
echo "musb-hdrc.0" > UDC


Now, after booting the beagle and checking


ifconfig -a


we'lll see usb0


To get the eth working, from host,


ifconfig usb0 169.254.211.10 up


Instead of using the gadget_setup EVENT we added, we can use bind ACTION and the DRIVER name to get this working:

echo "SUBSYSTEM==\"platform\",ACTION==\"bind\",DRIVER==\"musb-hdrc\",RUN+=\"/home/root/setup.sh\"" > /etc/udev/rules.d/20-musb-setup-test.rules


Driver binding is the process of associating a device with a device driver that can control it (ref: Documentation/driver-api/driver-model/binding.rst).


Refer udev(7) for udev related details.


Here's the musb-gadget update where we have added the gadget_setup for demonstration (see Upstream-Status: Denied noted in Yocto notes - 3):


meta-mylayer/recipes-kernel/linux/linux-yocto/0001-musb-gadget-udev-notification.patch


Upstream-Status: Denied
---
 drivers/usb/musb/musb_gadget.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 051c6da7cf6d..e6e0fe52659a 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1770,6 +1770,15 @@ static inline void musb_g_init_endpoints(struct musb *musb)
  }
 }
 
+static void send_gadget_uevent(struct device *dev, const char *event)
+{
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+ snprintf(event_string, sizeof(event_string), "%s", event);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+}
+
+
 /* called once during driver setup to initialize and link into
  * the driver model; memory is zeroed.
  */
@@ -1803,6 +1812,8 @@ int musb_gadget_setup(struct musb *musb)
  if (status)
  goto err;
 
+ send_gadget_uevent(musb->controller, "EVENT=gadget_setup");
+
  return 0;
 err:
  musb->g.dev.parent = NULL;
@@ -1815,6 +1826,8 @@ void musb_gadget_cleanup(struct musb *musb)
  if (musb->port_mode == MUSB_HOST)
  return;
 
+ send_gadget_uevent(musb->controller, "EVENT=gadget_cleanup");
+
  cancel_delayed_work_sync(&musb->gadget_work);
  usb_del_gadget_udc(&musb->g);
 }