vpelletier / python-functionfs

Pythonic API for linux's functionfs
GNU General Public License v3.0
40 stars 13 forks source link

Error 22 when writing descriptor to ep0 #1

Closed xpk closed 7 years ago

xpk commented 7 years ago

Following the manual for running the test, I'm trying to start the device part of it but getting the following error:

root@chip:~/dev/python-functionfs# python -m functionfs.tests.device /mnt
Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 210, in <module>
    main(*sys.argv[1:])
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 202, in main
    with FunctionFSTestDevice(path) as function:
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 121, in __init__
    common.INTERFACE_NAME,
  File "functionfs/__init__.py", line 544, in __init__
    ep0.write(desc_s)
IOError: [Errno 22] Invalid argument

root@chip:~/dev/python-functionfs# ls -l /mnt/ep0
-rw------- 1 root root 0 Apr  5 20:18 ep0

I assume something is wrong with the descriptor data it's trying to write into ep0. I also see a note saying "# TODO: try v1 on failure ?" just after the failing code, but the v1 descriptor apparently is not implemented. Could you please help with debugging this further and fixing?

vpelletier commented 7 years ago

First thing, functionfs is not very friendly on the error reporting side. There are many different reasons for which a write to ep0 could fail, and they mostly all fail with the same errno. You may have a line of error in dmesg, but it's not always the case.

I suspect the issue is the number of endpoint the test tries to declare. There is AFAIK no way to detect this (at least not via functionfs). Different UDCs support a different number of endpoints. Actually, I think a recent patch against the dwc3 (the controler I tested this against) makes this fail, as it was discovered that 2 endpoints are non-functional, fixing the maximum number of endpoints to 14 2, down from 15 2.

Could you edit the for x in xrange(1, 16) line in FunctionFSTestDevice.__init__ and set it to for x in xrange(1, 2) ? This will try to only request one IN and one OUT endpoints. If this works, you can increase the number of endpoints until it starts failing again. If this does not work, it means my assumption was wrong (but I have no other idea at the moment).

About the "v1" descriptors, they are indeed not implemented. Kernel-side, "v2" was implemented many kernel versions ago (I cannot find right now, I remember it as being from 2.6 era, but don't take my word for it) with more features, so supporting v1 would be to support very old kernels. Hence my lack of interest in these early versions...

xpk commented 7 years ago

Thank you, your suggestion solved the original issue. However, going forward, another one came up:

# python -m functionfs.tests.device /mnt
Servicing functionfs events forever...
functionfs: BIND
functionfs: ENABLE
Real interface 0: 0
0
/mnt/ep1:
0   
    0x07        bLength
    0x05        bDescriptorType
    0x81        bEndpointAddress
    0x02        bmAttributes
  0x0200        wMaxPacketSize
    0x00        bInterval
    0x07        bRefresh
    0x05        bSynchAddress
  FIFO status:
Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 211, in <module>
    main(*sys.argv[1:])
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 206, in main
    function.processEventsForever()
  File "functionfs/__init__.py", line 646, in processEventsForever
    self.__process(_INFINITY)
  File "functionfs/__init__.py", line 638, in __process
    getattr(self, event_dict[event.type])()
  File "/root/dev/python-functionfs/functionfs/tests/device.py", line 156, in onEnable
    value = ep_file.getFIFOStatus()
  File "functionfs/__init__.py", line 413, in getFIFOStatus
    return self._ioctl(FIFO_STATUS)
  File "functionfs/__init__.py", line 349, in _ioctl
    result = fcntl.ioctl(self, func, *args, **kw)
IOError: [Errno 22] Invalid argument

As a side note, I have also tested the ffs-test function that comes in tools/usb/ of the linux kernel tree, and it seems to be working ok.

vpelletier commented 7 years ago
  File "functionfs/__init__.py", line 413, in getFIFOStatus
    return self._ioctl(FIFO_STATUS)
  File "functionfs/__init__.py", line 349, in _ioctl
    result = fcntl.ioctl(self, func, *args, **kw)
IOError: [Errno 22] Invalid argument

On my UDC (dwc3), the driver fails with ENOTSUP and not EINVAL. I guess I should just catch and report any error in such test/sample code.

vpelletier commented 7 years ago

I guess I should just catch and report any error in such test/sample code.

Implemented in 3cc4202575f5c1403ee25bf9a4e0bc1d8edc5229 .

I also implemented a trivial retry-with-one-EP-less way of auto-detecting the number of available endpoints. Could not test it as something else is error'ing out in my setup.

vpelletier commented 7 years ago

Could not test it as something else is error'ing out in my setup.

Found the cause: there are 2 levels where endpoint descriptors can be rejected, and I completely forgot about this.

First is when writing them to ep0 file, second is when actually binding. Which makes me wonder why you had the error you reported in your original report: if it is controller-dependent, it should error-out when binding the function to the controller (ie, echo ... > /sys/kernel/config/usb_gadget/g1/UDC failing with errno 524), not when declaring the function.

xpk commented 7 years ago

After your latest changes, with the default 16 endpoints, I actually started getting the 524 error when binding the function to controller. It looks like the changes were supposed to make it reduce the number of endpoints automatically but something didn't work out. I'll try to play with it in debug a bit later... Anyway, after I changed the number of endpoints to 2, it all finally started working, so I'll keep testing. Thanks for your prompt feedback!