stanzlavos
stanzlavos

Reputation: 91

How to find which device is attached to a USB-serial port in Linux using C?

We are making a device and it has 8 serial ports. It runs on the Monta Vista Pro5 kernel. And we are working in C.

Suppose: A device gets attached to ttyUSB0, ttyUSB1 and ttyUSB2. The next device gets connected to ttyUSB3 and another to ttyUSB4. How can I know which device gets attached to which port ?? ie ttyUSB0 or ttyUSB1 or so on. Is there a way to directly query the device and find which port it is attached to. Or, in C, open ttyUSB0, query it somehow and get some reply as to which device it is ??

A rather complicated way: do a stat of, say /dev/ttyUSB0. Get the device number. And search for this in /proc/bus/usb/devices and find the vendor id or something to identify the device.

Or: Is there some way to reserve ttyUSB0,ttyUSB1 and ttyUSB2 for one device, ttyUSB3 for another and so on when they are plugged in ? This way I will know which device is connected to which port.

Help please..... :)

Thanks in advance. Nubin Stanley

Upvotes: 9

Views: 21418

Answers (4)

Alex Robinson
Alex Robinson

Reputation: 609

This Python code seems to find the /dev/ttyUSB number for the given vendor ID and product ID. Not hard to translate it to C. Parsing the output from hwinfo --usb can do the trick, too. The regx is:

"\s\sVendor:\susb\s0x([0-9a-f]{4}).*?\s\sDevice:\susb\s0x([0-9a-f]{4}).*?\s\sDevice\sFile:\s/dev/ttyUSB([0-9]+)"
import  glob
import  os
import  re

def find_usb_tty(vendor_id = None, product_id = None) :
    tty_devs    = []

    for dn in glob.glob('/sys/bus/usb/devices/*') :
        try     :
            vid = int(open(os.path.join(dn, "idVendor" )).read().strip(), 16)
            pid = int(open(os.path.join(dn, "idProduct")).read().strip(), 16)
            if  ((vendor_id is None) or (vid == vendor_id)) and ((product_id is None) or (pid == product_id)) :
                dns = glob.glob(os.path.join(dn, os.path.basename(dn) + "*"))
                for sdn in dns :
                    for fn in glob.glob(os.path.join(sdn, "*")) :
                        if  re.search(r"\/ttyUSB[0-9]+$", fn) :
                            #tty_devs.append("/dev" + os.path.basename(fn))
                            tty_devs.append(os.path.join("/dev", os.path.basename(fn)))
                        pass
                    pass
                pass
            pass
        except ( ValueError, TypeError, AttributeError, OSError, IOError ) :
            pass
        pass

    return tty_devs

print find_usb_tty()

Upvotes: 2

Noam
Noam

Reputation: 933

Here's my code, based on Alex Robinson's, but without global "except":

import os
from os.path import join

def find_tty_usb(idVendor, idProduct):
    """find_tty_usb('067b', '2302') -> '/dev/ttyUSB0'"""
    # Note: if searching for a lot of pairs, it would be much faster to search
    # for the enitre lot at once instead of going over all the usb devices
    # each time.
    for dnbase in os.listdir('/sys/bus/usb/devices'):
        dn = join('/sys/bus/usb/devices', dnbase)
        if not os.path.exists(join(dn, 'idVendor')):
            continue
        idv = open(join(dn, 'idVendor')).read().strip()
        if idv != idVendor:
            continue
        idp = open(join(dn, 'idProduct')).read().strip()
        if idp != idProduct:
            continue
        for subdir in os.listdir(dn):
            if subdir.startswith(dnbase+':'):
                for subsubdir in os.listdir(join(dn, subdir)):
                    if subsubdir.startswith('ttyUSB'):
                        return join('/dev', subsubdir)

Upvotes: 3

rsmoorthy
rsmoorthy

Reputation: 2372

You can use udev rules to create symbolic links just to your device:

(these rules go in /etc/udev/rules.d/-name.rules -- look at your udev documentation

KERNEL=="ttyUSB*", ATTRS{idVendor}=="<vendorid>", MODE="0666", SYMLINK+="mydev"

You have to specify your vendor id and/or product id for your device. Then those devices will be available at /dev/mydev in the above example.

You can also use various other parameters to create appropriate unique symbolic links for your use. Check udev man page.

Upvotes: 9

James
James

Reputation: 25523

The best way to do this is would be to use libusb, but if that doesn't give you enough information about your devices (which it may not), then you'll have to use the /proc filesystem which the kernel makes available, specifically /proc/bus/usb/.

Have a read of this information on /proc/bus/usb: in particular on /proc/bus/usb/devices. But as you say, this is all a bit hacky!

Upvotes: 0

Related Questions