HID on BBB with 4.9 kernel

I’ve tried several times to create a HID device with configfs using the 4.9 kernel. I’ve configured it with what appear to
be the necessary options (I would list them here, but I can’t remember them all. I can post a kernel configuration file
if I need to). I have the following modules loaded:

usb_f_hid 10893 2 libcomposite 55711 10 usb_f_hid musb_dsps 11548 0 musb_hdrc 123670 1 musb_dsps udc_core 43032 3 musb_hdrc,libcomposite,usb_f_hid phy_am335x 2825 2 phy_generic 6644 1 phy_am335x phy_am335x_control 3300 1 phy_am335x

You can see that the usb_f_hid driver got loaded. I was able to script the following steps:

`
modprobe libcomposite
cd /sys/kernel/config/usb_gadget

mkdir g1

cd g1

echo 0x1234 > idVendor
echo 0x5678 > idProduct

echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB

mkdir -p strings/0x409

echo “0123456789” > strings/0x409/serialnumber
echo “Manufacturer Inc.” > strings/0x409/manufacturer
echo “My HID Dev” > strings/0x409/product

mkdir -p configs/c.1/strings/0x409

echo “Config 1: MY HID Cfg” > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

mkdir -p functions/hid.0

echo 1 > functions/hid.0/protocol
echo 1 > functions/hid.0/subclass
echo 9 > functions/hid.0/report_length

cat ~/hid_desc.bin > functions/hid.0/report_desc

ln -s functions/hid.0 configs/c.1

ls /sys/class/udc > UDC

`

The script is dumb and stupid and doesn’t check anything at all because I’m trying to get some basic things working.
So, when the last line is executed, things go awry:

`
[ 104.598213] Unable to handle kernel NULL pointer dereference at virtual address 00000002
[ 104.606375] pgd = dc700000
[ 104.609292] [00000002] *pgd=9b466831, *pte=00000000, *ppte=00000000
[ 104.615656] Internal error: Oops: 17 [#1] SMP ARM
[ 104.620385] Modules linked in: usb_f_hid libcomposite musb_dsps musb_hdrc udc_core phy_am335x phy_generic phy_am335x_control omap_aes omap_sham crypto_engine evdev omap_rng rng_core tps65217_charger omap_wdt musb_am335x uio_pdrv_genirq uio cpufreq_dt cpufreq_conservative cpufreq_userspace cpufreq_ondemand cpufreq_powersave bluetooth
[ 104.650061] CPU: 0 PID: 1141 Comm: ls Not tainted 4.9.0bpw-1-armv7-devel-r9 #4
[ 104.657314] Hardware name: Generic AM33XX (Flattened Device Tree)
[ 104.663435] task: db05e180 task.stack: dc6ec000
[ 104.668091] PC is at alloc_ep_req+0x34/0xa0 [libcomposite]
[ 104.673602] LR is at 0x0
[ 104.676150] pc : [] lr : [<00000000>] psr: a0000013
sp : dc6edd48 ip : 00000000 fp : dc6edd64
[ 104.687679] r10: dc75c51c r9 : 00000100 r8 : dc75c4d0
[ 104.692927] r7 : dc75c4a8 r6 : db41c280 r5 : db352490 r4 : 00000009
[ 104.699483] r3 : 00000000 r2 : ffffffff r1 : 00000000 r0 : db41c280
[ 104.706043] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 104.713209] Control: 10c5387d Table: 9c700019 DAC: 00000051
[ 104.718980] Process ls (pid: 1141, stack limit = 0xdc6ec218)
[ 104.724665] Stack: (0xdc6edd48 to 0xdc6ee000)
[ 104.729048] dd40: 00000001 bf1d0ab4 dc7f8490 00000000 dc6edd9c dc6edd68
[ 104.737268] dd60: bf1cf72c bf1bfb18 db3531f8 c02cc074 00000000 00000001 00000001 dc7f8490
[ 104.745488] dd80: dc75c4a8 bf1cf688 dc7f84e8 dc75c4d0 dc6eddd4 dc6edda0 bf1ba048 bf1cf694
[ 104.753708] dda0: 00000001 dc728e5c dc728e94 db3f9208 00000000 00000200 dc75c4c4 dc75c4a8
[ 104.761928] ddc0: dc7f8490 dc7f84e8 dc6ede1c dc6eddd8 bf1bed30 bf1b9fc0 c120414c dc728e94
[ 104.770148] dde0: bf1c1fc0 dc728de8 db3531c0 dc728e5c dc677011 dc5cc600 dc728de8 dc7f3680
[ 104.778368] de00: dc728de8 bf12d69c 00000000 dc677000 dc6ede3c dc6ede20 bf12af7c bf1beac8
[ 104.786588] de20: 00000000 dc5cc600 bf12d6b0 dc7f3680 dc6ede64 dc6ede40 bf12b414 bf12af44
[ 104.794808] de40: dc7f3680 dc7f3780 dc728c00 dc728d90 00000011 00000000 dc6ede8c dc6ede68
[ 104.803028] de60: bf1bf820 bf12b324 00000011 dc7f3780 dc7f3798 dc6edf70 dc6d5d80 b6fb5000
[ 104.811248] de80: dc6edec4 dc6ede90 c0368890 bf1bf778 dc6edef4 00000051 c0bc2248 c120414c
[ 104.819468] dea0: dc6d5d80 00040900 dc6edf70 dc6edf70 00000011 00000000 dc6edf3c dc6edec8
[ 104.827688] dec0: c02de4e0 c03687a4 00000073 c120a1ec c120414c 00000817 c0bc2094 c02df15c
[ 104.835908] dee0: dc6edfb0 00033318 00000011 00000000 dc6d5d80 00000001 dc6edf3c dc6edf08
[ 104.844128] df00: c02df15c c06a1a1c 00000003 00000022 dc5eb578 00040900 00000011 dc6d5d80
[ 104.852348] df20: b6fb5000 dc6edf70 b6fb5000 dc6ec000 dc6edf6c dc6edf40 c02df41c c02de4a4
[ 104.860568] df40: 00000000 c030191c dc6d5d80 c120414c dc6d5d80 00000011 b6fb5000 dc6ec000
[ 104.868788] df60: dc6edfa4 dc6edf70 c02e061c c02df374 00000000 00000000 00000022 00040900
[ 104.877007] df80: 00000000 00000011 b6fb5000 b6f50b50 00000004 c0108fc4 00000000 dc6edfa8
[ 104.885227] dfa0: c0108e00 c02e05c4 00000011 b6fb5000 00000001 b6fb5000 00000011 00000000
[ 104.893448] dfc0: 00000011 b6fb5000 b6f50b50 00000004 00000011 00000000 00000001 00033338
[ 104.901667] dfe0: 00000000 beb3178c b6eb3c85 b6eeef26 40000030 00000001 00000001 00000000
[ 104.909973] [] (alloc_ep_req [libcomposite]) from [] (hidg_bind+0xa4/0x298 [usb_f_hid])
[ 104.919808] [] (hidg_bind [usb_f_hid]) from [] (usb_add_function+0x94/0x1f4 [libcomposite])
[ 104.930007] [] (usb_add_function [libcomposite]) from [] (configfs_composite_bind+0x274/0x41c [libcomposite])
[ 104.941836] [] (configfs_composite_bind [libcomposite]) from [] (udc_bind_to_driver+0x44/0x108 [udc_core])
[ 104.953345] [] (udc_bind_to_driver [udc_core]) from [] (usb_gadget_probe_driver+0xfc/0x164 [udc_core])
[ 104.964505] [] (usb_gadget_probe_driver [udc_core]) from [] (gadget_dev_desc_UDC_store+0xb4/0xcc [libcomposite])
[ 104.976518] [] (gadget_dev_desc_UDC_store [libcomposite]) from [] (configfs_write_file+0xf8/0x1a4)
[ 104.987277] [] (configfs_write_file) from [] (__vfs_write+0x48/0x144)
[ 104.995501] [] (__vfs_write) from [] (vfs_write+0xb4/0x1bc)
[ 105.002850] [] (vfs_write) from [] (SyS_write+0x64/0xcc)
[ 105.009949] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x3c)
[ 105.017564] Code: ebfda595 e2506000 0a000011 e5953024 (e1d320d2)
[ 105.023806] —[ end trace 6370b9fa6506820e ]—

`

I’ve used the references in the kernel dump above to track the issue to hidg_bind in f_hid.c:
`
static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_ep *ep;
struct f_hidg *hidg = func_to_hidg(f);
struct usb_string *us;
struct device *device;
int status;
dev_t dev;

/* maybe allocate device-global string IDs, and patch descriptors */
us = usb_gstrings_attach(c->cdev, ct_func_strings,
ARRAY_SIZE(ct_func_string_defs));
if (IS_ERR(us))
return PTR_ERR(us);
hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id;

/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
if (status < 0)
goto fail;
hidg_interface_desc.bInterfaceNumber = status;

/* allocate instance-specific endpoints */
status = -ENODEV;
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
if (!ep)
goto fail;
hidg->in_ep = ep;

ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
if (!ep)
goto fail;
hidg->out_ep = ep;

/* preallocate request and buffer */
status = -ENOMEM;
hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length);

`

At this point, I believe hidg->in_ep is “okay”, however the problem comes in at this point in u_f.c:

`
struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len)
{
struct usb_request *req;

req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
req->length = usb_endpoint_dir_out(ep->desc) ?
usb_ep_align(ep, len) : len;
req->buf = kmalloc(req->length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request(ep, req);
req = NULL;
}
}
return req;
}

`

At the underlined point, I believe ep->desc is NULL because using the kernel and an arm objdump variant,
I located the assembly that is causing the NULL dereference. Inside of usb_endpoing_dir_out, it tries to
dereference ep->desc, but ep->desc must be NULL otherwise things would likely go swimmingly. The problem
is, I don’t know what would cause ep->desc == NULL? Whatever causes this (and it might be related to
a function called “usb_gadget_ep_match_desc”) I’d like to know because knowing might tell me how to fix
whatever it is I’m doing wrong or maybe patch the code so that things might work.

I’m hoping someone knowledgeable about am335x USB can help here, or maybe let me know what I’m missing
in my HID configuration. The above configuration steps may not work, however, some python code I had previously
also fails to function. It might even be possible that I just need to use the regular HID driver and not one based on
libcomposite.

Thanks for reading this. Hopefully there are some answers.

At the underlined point, I believe ep->desc is NULL because using the
kernel and an arm objdump variant,

I located the assembly that is causing the NULL dereference. Inside of
usb_endpoing_dir_out, it tries to
dereference ep->desc, but ep->desc must be NULL otherwise things would
likely go swimmingly. The problem
is, I don't know what would cause ep->desc == NULL? Whatever causes this
(and it might be related to
a function called "usb_gadget_ep_match_desc") I'd like to know because
knowing might tell me how to fix
whatever it is I'm doing wrong or maybe patch the code so that things
might work.

I'm hoping someone knowledgeable about am335x USB can help here, or maybe
let me know what I'm missing
in my HID configuration. The above configuration steps may not work,
however, some python code I had previously
also fails to function. It might even be possible that I just need to use
the regular HID driver and not one based on
libcomposite.

Thanks for reading this. Hopefully there are some answers.

So, I'm not a USB composite framework expert. I only started reading about
it last night for another reason. A lot of what you're stating in your last
couple paragraphs here do not make sense to me. What I'm reading from your
post is that the end point descriptor must be NULL. but you're not sure why
it's NULL . . .yadda yadda yadda . . .That should not be true.

My first impression after looking through that code is user error. Simply
because a function that's being used requires a valid end point descriptor
reference as an argument, and that argument is NULL. Which tells me that
whole "object" was never instantiated in the first place.

To clarify my response somewhat. It does seem to me that you’re using configfs to create your HID device. I get that, so you’re not modifying the kernel module, or anything like that. What I’m saying is that perhaps things have changed in how configfs is used, in order to setup a composite HID device. Or the kernel module code has reverted to an earlier state that was previously non functional. When moving to 4.9.x. This( the later ) seems to happen a lot in these “cutting edge” kernels. Which is why I personally sty away from them for a few weeks at least.

I’m also not sure who would need to be contacted for this type of situation. But it’s likely the maintainer for this part of the kernel.

At the underlined point, I believe ep->desc is NULL because using the kernel and an arm objdump variant,

I located the assembly that is causing the NULL dereference. Inside of usb_endpoing_dir_out, it tries to
dereference ep->desc, but ep->desc must be NULL otherwise things would likely go swimmingly. The problem
is, I don’t know what would cause ep->desc == NULL? Whatever causes this (and it might be related to
a function called “usb_gadget_ep_match_desc”) I’d like to know because knowing might tell me how to fix
whatever it is I’m doing wrong or maybe patch the code so that things might work.

I’m hoping someone knowledgeable about am335x USB can help here, or maybe let me know what I’m missing
in my HID configuration. The above configuration steps may not work, however, some python code I had previously
also fails to function. It might even be possible that I just need to use the regular HID driver and not one based on
libcomposite.

Thanks for reading this. Hopefully there are some answers.

So, I’m not a USB composite framework expert. I only started reading about it last night for another reason. A lot of what you’re stating in your last couple paragraphs here do not make sense to me. What I’m reading from your post is that the end point descriptor must be NULL. but you’re not sure why it’s NULL . . .yadda yadda yadda . . .That should not be true.

The yadda yadda yadda was kind of the point. I actually have looked into it further and the only way that reference would actually be null is if the autoepconfig function couldn’t choose any available endpoint because none of them matched the correct criteria. I’m not sure where I’m supposed to SET UP the appropriate criteria, hence the question, and the details.

My first impression after looking through that code is user error. Simply because a function that’s being used requires a valid end point descriptor reference as an argument, and that argument is NULL. Which tells me that whole “object” was never instantiated in the first place.

those objects aren’t “instantiated”. They are actually endpoints that are “built-in” (you can see one for full-speed, high-speed, and now super-speed). One of the endpoints is supposed to get selected based on an appropriate description. Mine probably doesn’t match or I haven’t set one, hence it doesn’t work. But I don’t see anywhere where I can actually SPECIFY the necessary things in configfs… Maybe you just can’t build a HID device with configfs right now? Or maybe something changed. Either way, I’m researching the answer to that question so I can figure out what I really need to do. Maybe there is another way I can configure a HID driver, not using configfs.

The things I was able to do in the 3.13.xx kernel don’t seem to work with this kernel either, or I don’t have them set up correctly, hence I figured the “new” or current method was to use configfs. But maybe this isn’t the case.

I have tried to get the “latest” from the TI repo, and the results are the same. So I’m guessing that my kernel configuration was probably okay, but somehow I’m not doing something right with configfs, or configfs doesn’t work for HID devices yet (I don’t know if I believe that, but its possible). At any rate, I’ve not managed to get it working yet.

Yeah that's all I was really saying. Sometimes *things* like to be done in
a certain order, or maybe a configfs step that was required was missed ?
Theres a LWN article I was reading the other day, that seems to be pretty
full of information. However, the "walk-thru" only talks about
re-implementing the mass storage gadget using USB composite.
https://lwn.net/Articles/395712/

I've also seen a few presentation type PDF's out there. I do not really
know enough about the framework to know how useful these are though. Passed
that, I have not yet seen one for HiD. Although . . . you know what, I
think DR. Phil Polstra did a presentation on emulating a keyboard using HiD
USB device, and I do think he used configfs . . . However he may have used
an older kernel as well.

I'll tell you what though, even though I'm not necessarily interested in
creating an HiD device. I have interest in this whole composite framework.
SO I'll do some searching on my own, and let you know what I find. I may
even just start out with an HiD "thing" just to get my feet wet.

Maybe you've seen these already ? I'm not sure if any, or all of this is
already know to you, but here goes . . .

Matt Porter:
http://events.linuxfoundation.org/sites/events/files/slides/USB%20Gadget%20Configfs%20API_0.pdf
Andrzej Pietrasiewicz:
https://events.linuxfoundation.org/sites/events/files/slides/LinuxConNA-Make-your-own-USB-gadget-Andrzej.Pietrasiewicz.pdf

Additional documentation / example code:
http://lxr.free-electrons.com/source/Documentation/usb/gadget_hid.txt