Need help with the MCP2210 on Linux with libusb

nsaspook

Joined Aug 27, 2009
13,081
Thanks! Reading your code quicky, some questions arise:
- Is "cur_dev" a C++ structure that is being instantiated dynamically?
- Why using the same instance of "buf" and "rbuf" throughout the code?
- Do you need to enumerate all the HID devices, or you can just jump to hid_open() after hid_init()?

Otherwise, the code seems to be straighthforward to me. It resembles what one would do with libusb. The MCP2210 might deserve a class, similar to what I did with the CP2130. Basically, it will be a wrapper around hiddev. I like what I see!

I'll test this. What libraries are you including in your makefile, by the way?
Like I said this is a version of the hidapi test program (the enumeration section is not needed for proper operation) that was modified quickly from a already modified version from the net to make it work the adapter SPI devices. Most of the variables and structure preexisted my modifications.

Original test source code:
https://github.com/libusb/hidapi/tree/master/hidtest

My system already had a udev rule to make the hidraw device. You might need to add one for your system.
https://github.com/libusb/hidapi/blob/master/udev/69-hid.rules

A wrapper example.
https://github.com/kerrydwong/MCP2210-Library

Note, the compiled code needs root access to the device and need to be run using "sudo". You may need to add the provided udev rule (99-hid.rules) to the /etc/udev/rules.d directory.

https://github.com/kerrydwong/MCP2210-Library/blob/master/99-hid.rules
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Thanks. Strangely I've created a udev rule, restarted the udev service, and still I can't open the device. However, I can open it when I execute the program as root. Probably the driver needs to be detached.

As for the wrapper, I'm thinking about doing it myself. It will be a Qt wrapper class that will be able to keep the context of a device. Something in the lines of what I did for the CP2130: https://github.com/bloguetronica/cp2130-qt . However, it will be done around hidapi.
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,081
Thanks. Strangely I've created a udev rule, restarted the udev service, and still I can't open the device. However, I can open it when I execute the program as root. Probably the driver needs to be detached.

As for the wrapper, I'm thinking about doing it myself. It will be a Qt wrapper class that will be able to keep the context of a device. Something in the lines of what I did for the CP2130: https://github.com/bloguetronica/cp2130-qt . However, it will be done around hidapi.
The default udev permission is root access only for the hidraw* devices.
You also need a udev rule to change the permission to something more open.

This works for the MCP2210 device on my system to allow non-privileged user programs access.
https://github.com/kerrydwong/MCP2210-Library/blob/master/99-hid.rules

Code:
# This is a sample udev file for HIDAPI devices which changes the permissions
# to 0666 (world readable/writable) for a specified device on Linux systems.


# If you are using the libusb implementation of hidapi (hid-libusb.c), then
# use something like the following line, substituting the VID and PID with
# those of your device. Note that for kernels before 2.6.24, you will need
# to substitute "usb" with "usb_device". It shouldn't hurt to use two lines
# (one each way) for compatibility with older systems.

# HIDAPI/libusb
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666"


# If you are using the hidraw implementation, then do something like the
# following, substituting the VID and PID with your device. Busnum 1 is USB.

# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666"

# Once done, optionally rename this file for your device, and drop it into
# /etc/udev/rules.d and unplug and re-plug your device. This is all that is
# necessary to see the new permissions. Udev does not have to be restarted.

# Note that the hexadecimal values for VID and PID are case sensitive and
# must be lower case.

# If you think permissions of 0666 are too loose, then see:
# http://reactivated.net/writing_udev_rules.html for more information on finer
# grained permission setting. For example, it might be sufficient to just
# set the group or user owner for specific devices (for example the plugdev
# group on some systems).
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Thanks, but I've used those rules, and to no avail. Meanwhile. I've been sniffing the USB traffic to the board. Each operation requires two transactions (two request/response pairs). Not bad!

Screenshot_20210523_124841.png

In comparison, the CP2130 does 19 transactions (38 packets) to read the status of 5 GPIOs, setup the chip select, and read the value from the ADC 6 times! So, the MCP2210 does have a tall order to match this.

Screenshot_20210523_125507.png

It is an apple to oranges comparison but, in the end, I want to use the MCP2210 for a similar purpose. The CP2130 is integrated on the ITUSB2, a USB switch that I've built to test enumeration and read the consumption current of USB devices.
 

nsaspook

Joined Aug 27, 2009
13,081
Thanks, but I've used those rules, and to no avail.
...
It is an apple to oranges comparison but, in the end, I want to use the MCP2210 for a similar purpose. The CP2130 is integrated on the ITUSB2, a USB switch that I've built to test enumeration and read the consumption current of USB devices.
Strange, the rules did this on my system to fix permissions.
PXL_20210523_043030686.jpg
Before and after 99-hid.rules update (unplug and re-plug device) hidraw permissions. /dev/hidraw3 is the MCP2210.

Pretty neat device. https://github.com/bloguetronica
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Well, I've done "sudo service udev restart" and re-connected the device. It usually works that way with the CP2130. I've even gave it 0666 permissions, which should work even better. Tried different rules. I'll have to try this inside a Debian VM, to see if I get a different result.

Nevertheless, thanks for your comment! I'll post the details about the project here, in AAC, pretty soon.
 

nsaspook

Joined Aug 27, 2009
13,081
Thanks for making me bump the work queue on the MCP2210. I finally received a PCB (from jlcpcb) for the TiC12400 24 input chip I built a prototype for.
PXL_20210523_203956656.jpg
PXL_20210523_191239532.jpg
I hack another quick Linux C demo (with few data/function abstractions to show a few required programming details for proper USB and SPI transfers) to make the TIC12400 control the MCP23S08 on the eval board.
PXL_20210529_205633352.jpg


It polls the switch via SPI once after 10 led rolls so it's slow to update switch changes. It's very easy to make it poll faster by changing the processing loop slightly to read the External Interrupt Pin (GP6) Event Status as a flag to update the switch buffer.

https://github.com/nsaspook/daq_gert/tree/p8055/hidapi/linux_test/tictest
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
I have to say that the demo program I've used ("hidapi_test", that is) works fine, until I try to delete the while and for loops with the intent of doing a single transfer to light a combination of LEDs. I've replaced the variables, of course. It compiles fine, but breaks the program on execution, showing a message. It doesn't make sense because the setup part stays the same.

Anyway, good work! If I can make this work, the MCP2210 will be a great replacement for the CP2130. I suspect that the library might be broken, somehow. Or it is the program that is not very editable, because it sure relies on past states.
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
I've discovered what is going on with the permissions. It is not the udev rules per se, but the fact that the file corresponding to the device appears accessible just for the root user. To fix this, in my case, I have to do a "sudo chmod 0666 /dev/hidraw3". This is temporary, though, because the file will disappear once I remove the device.

Additionally, I've removed the udev rules and restarted udev, re-attaching the device once more. Fixed the permission again, and it works. The rules seem to be unnecessary.

Edit: Is there a way to use the libusb implementation instead of the hidraw one? I can't find any info about this. I don't know if it is a compilation option, an include option, a define we must set... The lack of documentation on this is appalling, especially to a new user like me. I think the libusb implementation would solve the issue.
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,081
I've discovered what is going on with the permissions. It is not the udev rules per se, but the fact that the file corresponding to the device appears accessible just for the root user. To fix this, in my case, I have to do a "sudo chmod 0666 /dev/hidraw3". This is temporary, though, because the file will disappear once I remove the device.

Additionally, I've removed the udev rules and restarted udev, re-attaching the device once more. Fixed the permission again, and it works. The rules seem to be unnecessary.

Edit: Is there a way to use the libusb implementation instead of the hidraw one? I can't find any info about this. I don't know if it is a compilation option, an include option, a define we must set... The lack of documentation on this is appalling, especially to a new user like me. I think the libusb implementation would solve the issue.
root@hpdesk:/etc/udev/rules.d# ls -l
total 40
-rw-r--r-- 1 root root 1524 May 22 21:28 99-hid.rules
-rw-r--r-- 1 root root 20919 Apr 5 10:46 99-jlink.rules
-rw-r--r-- 1 root root 961 May 10 16:10 z010_mchp_tools.rules
-rw-r--r-- 1 root root 606 Apr 5 10:45 z011_mchp_jlink.rules
-rw-r--r-- 1 root root 252 May 10 16:10 z012_mchp_efr.rules

My system udev rules change the permission to 666 each time the device is plugged in automatically.
KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666"

The device loads the standard hid driver so, NO, there is no libusb implementation unless you write one. the hidraw implementation seems to handle simple SPI sequences pretty well.

I created a MCP2210 DIO board for testing the Linux driver.
16 24vdc capable outputs (MC33996) and 24 24vdc capable inputs (TIC12400).
https://www.ti.com/lit/ds/symlink/t...48545&ref_url=https%3A%2F%2Fwww.google.com%2F
https://www.mouser.com/datasheet/2/302/MC33996-1126506.pdf

https://github.com/nsaspook/mcp2210/tree/main/linux_test/tictest
PXL_20210628_004123552.jpg
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Probably I'm better off by detaching the driver and just write my own libusb implementation. I set the correct access permissions, but udev just doesn't set the correct permissions for the corresponding virtual file. I suspect that udev and the file corresponding to the HID device are separate things.

These are the rules I'm using:
Code:
# This is a sample udev file for HIDAPI devices which lets unprivileged
# users who are physically present at the system (not remote users) access
# HID devices.

# If you are using the libusb implementation of hidapi (libusb/hid.c), then
# use something like the following line, substituting the VID and PID with
# those of your device.

# HIDAPI/libusb
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", TAG+="uaccess"

# If you are using the hidraw implementation (linux/hid.c), then do something
# like the following, substituting the VID and PID with your device.

# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", TAG+="uaccess"

# Once done, optionally rename this file for your application, and drop it into
# /etc/udev/rules.d. Note that these rules must have priorty before 70-uaccess.rules
# for example, name the file /etc/udev/rules.d/69-my-application-hid.rules.
# Then, replug your device or run:
# sudo udevadm control --reload-rules && sudo udevadm trigger

# Note that the hexadecimal values for VID and PID are case sensitive and
# must be lower case.

# TAG+="uaccess" only gives permission to physically present users, which
# is appropriate in most scenarios. If you require remote access to the
# device, add
# GROUP="plugdev", MODE="660"
# to the end of the udev rule lines, add your user to the plugdev group with:
# usermod -aG plugdev USERNAME
# then log out and log back in (or restart the system).
I've specified the mode to 0666 as well, but no success.
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Found a possible workaround. I've used these rules instead:
Code:
# This is a sample udev file for HIDAPI devices which lets unprivileged
# users who are physically present at the system (not remote users) access
# HID devices.

# If you are using the libusb implementation of hidapi (libusb/hid.c), then
# use something like the following line, substituting the VID and PID with
# those of your device.

# HIDAPI/libusb
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# If you are using the hidraw implementation (linux/hid.c), then do something
# like the following, substituting the VID and PID with your device.

# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# Once done, optionally rename this file for your application, and drop it into
# /etc/udev/rules.d. Note that these rules must have priorty before 70-uaccess.rules
# for example, name the file /etc/udev/rules.d/69-my-application-hid.rules.
# Then, replug your device or run:
# sudo udevadm control --reload-rules && sudo udevadm trigger

# Note that the hexadecimal values for VID and PID are case sensitive and
# must be lower case.

# TAG+="uaccess" only gives permission to physically present users, which
# is appropriate in most scenarios. If you require remote access to the
# device, add
# GROUP="plugdev", MODE="660"
# to the end of the udev rule lines, add your user to the plugdev group with:
# usermod -aG plugdev USERNAME
# then log out and log back in (or restart the system).
In addition, I had to add my user to the plugdev group, of course. However, the device file still appears with access permissions only for root. To fix this, I have to type "sudo udevadm trigger" on a terminal each time I plug in the device.
 

nsaspook

Joined Aug 27, 2009
13,081
That sounds like Systemd madness. I'm still a old school sysvinit guy on all my operational systems and try not have the Systemd virus on my stuff.
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Oh, systemd. That POC! Really, systemd and pulseaudio are the worst that ever happened to Linux. And Lennart Poettering, the developer behind it? That guy shouldn't be allowed to contribute for any major distros, with his attitude.
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Finally I've got around to have a closer look at the MCP2210 library and hidapi source code. Probably, this still won't fix my problem, but I'm curious to see what happens if I define "DETACH_KERNEL_DRIVER" right inside "mcp2210.h". If that doesn't solve the problem, probably I'll have to sacrifice one MCP2210 by changing its PID. Probably, some driver is attached, because Linux attaches the "proper" (not in this case) driver if the device is not classless.
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
Ok, finally I've came to a conclusion, and I didn't have to try to define "DETACH_KERNEL_DRIVER", aind it wouldn't work anyway, because that is specific to the libusb implementation, and <hidapi/hidapi.h> seems to be using hidraw anyways. I've used the rules below and added myself to plugdev. The results were inconsistent, though, because sometimes the corresponding device file was accessible to me, as a plugdev user, and sometimes it was only accessible to root, until it is applied to plugdev after long minutes. It seems to be an issue with systemd.

Code:
# This is a sample udev file for HIDAPI devices which lets unprivileged
# users who are physically present at the system (not remote users) access
# HID devices.

# If you are using the libusb implementation of hidapi (libusb/hid.c), then
# use something like the following line, substituting the VID and PID with
# those of your device.

# HIDAPI/libusb
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# If you are using the hidraw implementation (linux/hid.c), then do something
# like the following, substituting the VID and PID with your device.

# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# Once done, optionally rename this file for your application, and drop it into
# /etc/udev/rules.d. Note that these rules must have priorty before 70-uaccess.rules
# for example, name the file /etc/udev/rules.d/69-my-application-hid.rules.
# Then, replug your device or run:
# sudo udevadm control --reload-rules && sudo udevadm trigger

# Note that the hexadecimal values for VID and PID are case sensitive and
# must be lower case.

# TAG+="uaccess" only gives permission to physically present users, which
# is appropriate in most scenarios. If you require remote access to the
# device, add
# GROUP="plugdev", MODE="660"
# to the end of the udev rule lines, add your user to the plugdev group with:
# usermod -aG plugdev USERNAME
# then log out and log back in (or restart the system).
Mind that the first rule has no effect. The last rule does not work with the tag, so you need to use the mode and the group instead.

I'm considering doing my own libusb implementation, specifically for the MCP2210 (no generalization for other HID devices), since there is no clear consensus (depending on the distro, your implementation may use hidraw or not). The HID writes are interrupt transfers and the HID reads are control transfers. I've seen the libusb implementation, and the code is pretty much straightforward. Kernel detach will be forced, for sure.
 

nsaspook

Joined Aug 27, 2009
13,081
Ok, finally I've came to a conclusion, and I didn't have to try to define "DETACH_KERNEL_DRIVER", aind it wouldn't work anyway, because that is specific to the libusb implementation, and <hidapi/hidapi.h> seems to be using hidraw anyways. I've used the rules below and added myself to plugdev. The results were inconsistent, though, because sometimes the corresponding device file was accessible to me, as a plugdev user, and sometimes it was only accessible to root, until it is applied to plugdev after long minutes. It seems to be an issue with systemd.

Code:
# This is a sample udev file for HIDAPI devices which lets unprivileged
# users who are physically present at the system (not remote users) access
# HID devices.

# If you are using the libusb implementation of hidapi (libusb/hid.c), then
# use something like the following line, substituting the VID and PID with
# those of your device.

# HIDAPI/libusb
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# If you are using the hidraw implementation (linux/hid.c), then do something
# like the following, substituting the VID and PID with your device.

# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00de", MODE="0666", GROUP="plugdev"

# Once done, optionally rename this file for your application, and drop it into
# /etc/udev/rules.d. Note that these rules must have priorty before 70-uaccess.rules
# for example, name the file /etc/udev/rules.d/69-my-application-hid.rules.
# Then, replug your device or run:
# sudo udevadm control --reload-rules && sudo udevadm trigger

# Note that the hexadecimal values for VID and PID are case sensitive and
# must be lower case.

# TAG+="uaccess" only gives permission to physically present users, which
# is appropriate in most scenarios. If you require remote access to the
# device, add
# GROUP="plugdev", MODE="660"
# to the end of the udev rule lines, add your user to the plugdev group with:
# usermod -aG plugdev USERNAME
# then log out and log back in (or restart the system).
Mind that the first rule has no effect. The last rule does not work with the tag, so you need to use the mode and the group instead.

I'm considering doing my own libusb implementation, specifically for the MCP2210 (no generalization for other HID devices), since there is no clear consensus (depending on the distro, your implementation may use hidraw or not). The HID writes are interrupt transfers and the HID reads are control transfers. I've seen the libusb implementation, and the code is pretty much straightforward. Kernel detach will be forced, for sure.
Glad to see you're still on the problem. I've moved to https://www.devuan.org/ on my latest server to eliminate the systemd 'virus'.
Devuan GNU+Linux is a fork of Debian without systemd that allows users to reclaim control over their system by avoiding unnecessary entanglements and ensuring Init Freedom.
So far it's been wonderful if you've been a long-time Debian user. :D
PXL_20211028_230107480.jpgPXL_20211028_230035356.jpgPXL_20211028_234249623.jpg
HP DL360p GEN-8 12 core 64GB
https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-c03223744
 
Last edited:

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
I think I could avoid the systemd problem by using libusb directly. Basically, I'll have to create a "libusb-hid.c" file with the HID implementation, which should be simple. I'm aware that a libusb implementation for hidapi exists, but there is no info on how to use it. It is a mess.

As for systemd, yes, I already have tried removing in on a VM for testing, but without success. It is sad that all the main distros decided to follow Red Hat (which never did any real thing to promote free software), and implemented PulseAudio along with systemd. I might add that PulseAudio still has issues, namely echo on the microphone, and switching left and right channels.

To finish, this issue was never forgotten. I hadn't have the time to tackle it, but it will be tackled very soon.
 

Thread Starter

bloguetronica

Joined Apr 27, 2007
1,541
I've had a breakthrough. Basically, you use the libusb backend by replacing "hidapi-hidraw" by "hidapi-libusb" inside "Makefile-Debug.mk". Search for the following:

Code:
# Link Libraries and Options
LDLIBSOPTIONS=`pkg-config --libs hidapi-hidraw`

# Build Targets
.build-conf: ${BUILD_SUBPROJECTS}
    "${MAKE}"  -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/hidapi_test

${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/hidapi_test: ${OBJECTFILES}
    ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
    ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/hidapi_test ${OBJECTFILES} ${LDLIBSOPTIONS}

${OBJECTDIR}/hidtest.o: hidtest.cpp
    ${MKDIR} -p ${OBJECTDIR}
    ${RM} "$@.d"
    $(COMPILE.cc) -g `pkg-config --cflags hidapi-hidraw`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/hidtest.o hidtest.cpp
However, it doesn't work when using the libusb backend, unless the program is ran with sudo.

Edit: I've managed to run the compiled program that used the libusb backend without sudo. I have to investigate this more.
 
Last edited:
Top