I'm writing a small C application to run on my (Linux) QNAP NAS that will talk to an Arduino (I have no difficulty with any of the USB code for the arduino). (The arduino has a trusted application on it that accepts text commands via USB serial.)
My wish was to find it using the USB vendor/product IDs (only half implemented at the moment). What I have so far (see below) works quite nicely in that it does find the device.
// runs on NAS
#include <stdio.h>
#include <usb.h>
main () {
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("Trying %s/%s\n", bus->dirname, dev->filename);
printf("\tVendor = 0x%04x\n", dev->descriptor.idVendor);
printf("\tBus = 0x%03x\n", bus->location);
printf("\tFile = %s\n", dev->filename);
if (dev->descriptor.idVendor==0x403) {
printf("\t HEY, THIS IS MINE!\n");
usb_dev_handle *handle = usb_open(dev);
printf("\t HANDLE 0x%08x\n", (int) handle);
//printf(handle, "1,5,62,75\n");
usb_close(handle);
}
}
}
}
The trouble is that now I want to send/receive a little bit of text with the device and I don't know how to do that.
I have expected I should be generating a device name from something in the usb_device struct and then open it like a file (like one would do on Windows).
If that's correct, I need to know the correct way to find out the device name...
I believe I'm using libusb.
I happen to know that -- as currently configured/connected -- it's ttyUSB0 but I'd like to know that using code.
thank you!
I suggest using libusbp. It is a C library with a C++ wrapper, and there is example code showing how to get the name of a serial port based on the vendor ID and product ID of the USB device:
https://github.com/pololu/libusbp/blob/master/examples/port_name/port_name.cpp
libusb is a library used for low level communication with USB devices. But when your communication is limited just to reading device's USB descriptor - libusb is not the best tool.
Linux systems use udev subsystem to manage hot-plug devices. udev reads descriptors of all plugged USB devices and stores them in its database. libudev is the library that you should use to get such info like device names of enumerated devices. In your case you need to remember that usb_device and usb_interface are separate things - only the latter would have the tty device file assigned to it.
Alternatively you could just use udev config to assign a constant device name to your specific device. So you would not have to be looking for it.
Related
I am trying to setup a Half Duplex RS-485 communication using libmodbus on a Raspberry Pi running Raspian Buster, with a FTDI USB to Serial adapter. My FTDI adapter shows as ttyUSB0 when I run ls /dev/.
I tried the following sample code:
#include <modbus.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void) {
modbus_t *ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 1);
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return 0;
}
if (modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) == -1) {
fprintf(stderr, "Error setting the serial port as RS-485\n");
fprintf(stderr, "errno: %d\n (EBADF == 9)", errno);
modbus_free(ctx);
return 0;
}
}
Compiled with gcc test1.c -I/usr/include/modbus -lmodbus.
And I get errno as 9, or EBADF, even if I run this code with sudo.
There is a very easy solution to your problem: just don't set MODBUS_RTU_RS485, quite likely you don't need it.
This mode is actually a workaround for devices without automatic (hardware) direction control. As you know, Modbus RTU works over a half-duplex RS485 link (only one device is allowed to talk while all others must be listening only), and hence requires an additional (to RX and TX) signal to control what device is writing to the bus at all times (direction control).
So you would only need to set MODBUS_RTU_RS485 if your device lacks this feature, which is nowadays quite unlikely or if you are building your own transceiver. Most devices based on the FTDI chip, in particular, should have this feature since the chip itself has a TXDEN (transmit enable) pin. See here for more details and a trick to expose the TXDEN signal to a non-default pin.
It is when you don't have this feature (one frequent scenario is when you want to use the embedded UART on your Rpi for Modbus over RS485, implementing your own transceiver) that you need a software (or hardware) workaround. And that's where MODBUS_RTU_RS485 should come handy, repurposing the RTS flow control signal. Unfortunately, most serial drivers (including ftdi_sio, the one you are probably using) don't support this mode (refer again to the link above).
Luckily, there are workarounds to the workaround: see here for a complete discussion. You can also take a look at this answer where I explained how to set up libmodbus with support for toggling the direction on the bus using a GPIO pin on a Rpi (also applicable to most SBCs, I've used this method successfully with a Pocket Chip computer, for instance).
You can find more background on this issue elsewhere: here and here.
I'm studying linux device driver. currently, I understand flows of device driver approximatively, but I dont know how probe() function gets its arguments.
For example, here is my code and this is based on kernel 3.10.
static int gpio_led_probe(struct platform_device *pdev) {
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
....
priv = gpio_leds_create_of(pdev);
....
}
As like this, the argument 'pdev' is using for various point of source. I'm understading when probe() called and it's role, but I cannot find where the data 'pdev' comes from.
thanks for read my thread, and sorry that my english is not good.
platform device specific data while probing comes from the platform setup code or from device tree.
you can find the related code in arch/arm/borad/device files
struct platform_device embedded with platform_data structure where you will pass the platform related data to the drivers.
in modern kernels platform data is passed to device drivers through device tree. device tree can be found in /arch/arm/boot/dts/your_device
You can provide the platform device information by filling the platform_device structure or you have to provide your device information in device tree, during system bootup, platform_device structure gets populated based on the device tree information.In latest kernel usually we use device tree to get the device information.
I am quite new to kernel programming and I am following the tutorial given at :
USB boot authentication
I want to get a 'device struct' of a USB drive. I have 'dev_t' instance of the USB device. Further, I want to check whether the device struct is a USB device or not. I am not able to figure out how to start...
Thanks
As hiteshradia said dev_t is a device number (a major number and minor number). You can however use this along with the knowledge that it is for a block device to get access to the struct device associated with it. To do so, use struct block_device *bdget(dev_t) from linux/fs.h. From this you can use block_device->bd_part to get a struct hd_struct * for the device and finally use struct device *part_to_dev(struct hd_struct *) defined as a macro in linux/genhd.h.
dev_t is only a device number which represents a /dev/sdb1 partition as seen from your link. It is not possible to get the underlying usb drive details using it.
In the link you provided there is section
if(udev->serial != NULL)
{
if((strcmp(udev->serial, "3513001D97827E69")) == 0) /* Hard coded usb device serial here*/
{
key_dev_found = 1;
}
}
where you can get usb device details and struct usb_device *udev
I am trying add some debug messages in block io to track the io operation in linux kernel.
IO could happen to multiple block device, I have dev_t value with me.
I can get major and minor number from dev_t.
I want to know is there any way to get the device file name from /dev/ dir using these major and minor number?
Of course, I need kernel APIs.
It's simple:
Use bdget function to find the block_device by dev_t.
Use bdevname to get the device name.
Use bdput to put the device reference.
Have fun.
You can also use libudev. Since you already have the dev_t id this way is aesier.
#include <libudev.h>
// Create the udev context.
struct udev *udev = udev_new();
// Create de udev_device from the dev_t.
struct udev_device *dev = udev_device_new_from_devnum(udev, 'b', sb.st_dev);
// Finally obtain the node.
const char* node = udev_device_get_devnode(dev);
udev_unref(udev);
In general, you cannot do such simple reverse mapping. This is because knowing some major and major numbers, one can always use mknod to create valid device file anywhere, not necessarily under /dev.
At the end of the day, kernel does not care much how did any particular device node with certain major/minor came about - such a node is simply entry point into the kernel device driver that can handle this hardware or software device.
Granted, in practice on most modern Linux systems most device nodes are located in /dev and maintained by udev - but it is user-space daemon, which your kernel driver cannot talk to. Also note that udev can be configured to create new device nodes with any name.
I'm currently work on kernel-mode USB driver for Seowon SWU-3220A WiMAX USB modem. It is a complex device (after plugging it appear in system as USB CDROM, and driver needs to switch it to modem mode). My problem is that the probe() function from my driver is never called. I think it because OS uses standard usb mass storage driver instead of my own.
I initialize driver as follow:
#define GDM7213_VENDOR_ID 0x1076
#define GDM7213_PRODUCT_ID 0x7f40
static struct usb_device_id gdm7213_table [] = {
{ USB_DEVICE(GDM7213_VENDOR_ID, GDM7213_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, gdm7213_table);
static struct usb_driver gdm7213_driver = {
.name = "gdm7213",
.probe = gdm7213_probe,
.disconnect = gdm7213_disconnect,
.suspend = gdm7213_suspend,
.resume = gdm7213_resume,
.pre_reset = gdm7213_pre_reset,
.post_reset = gdm7213_post_reset,
.id_table = gdm7213_table,
};
static int gdm7213_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
printk(KERN_INFO "GDM7213 gdm7213_probe()\n");
return 0;
}
static int __init gdm7213_init_module(void)
{
int result;
printk(KERN_INFO "GDM7213 init_module()\n");
result = usb_register(&gdm7213_driver);
if (result)
err("usb_register failed. Error number %d", result);
return result;
}
static void __exit gdm7213_cleanup_module(void)
{
printk(KERN_INFO "GDM7213 cleanup_module()\n");
usb_deregister(&gdm7213_driver);
}
module_init(gdm7213_init_module);
module_exit(gdm7213_cleanup_module);
Can anybody say me where is a bug or suggest any workaround?
If it is the USB mass storage driver stealing it before you get a chance you might want to blacklist the VID/PID for the device with that driver.
Since you mentioned it's a USB WiMAX adapter I'm going to have a wild guess though that it's presenting a USB mass storage device that contains a driver for it on Windows. If that's the case you would be better off working with USB Modeswitch, which already handles this for 3G modems. Typically the devices expect some magic bytes (which often is actually a SCSI eject command) to persuade them to stop being mass storage devices and become the real modem. (That has a different PID normally too).
Even if your device can't be persuaded to show the real device instead of the driver with one of the existing USB Modeswitch rules it would be more appropriate to fix the problem with that than a kernel hack.
Doing it with USB Modeswitch has a number of advantages over what you proposed:
Keeps everything modular:
Your driver only has to care about WiMAX and one VID/PID for the device
The mass storage driver doesn't need to care about crazy devices - it just looks like plugging and unplugging a device. Teaching the mass storage driver about every single one of these sort of devices isn't appropriate, your device doesn't seem to be a special case.
The knowledge about the split personalities of the device is only relevant to USB Modeswitch, which only exists to solve this problem.
It doesn't break the USB mass storage aspects of the device - users might want to view the Windows driver under Linux for some reason, blacklisting this device would make that impossible. This might be important if you end up using some firmware shipped with the Windows driver under Linux too.
It follows the existing setup and keeps your changes local to your module. This might well be important if you want to get your driver in the mainline kernel ever.