Tìm source code của USB Driver trên Linux


Ở bài Tìm driver cho Linux cũng đã nói qua rồi, nhưng bài này muốn chỉ ra chi tiết hơn một chú cho nhưng ai muốn đọc source.

Cách tìm source code driver cho thiết bị USB

1. Nói qua về thiết bị USB

  • Linux kernel xác định driver phù hợp cho thiết bị bằng 2 thông tin chính.
    Đó là Vendor (nhà sản xuất), và Product (sản phẩm).
    Thông tin về Vendor được mô tả bằng một id, trong source thường là idVendor.
    Thông tin về Product cũng được mô tả bằng một id, trong source thường là idProduct.
    2 thông tin trên sẽ xác định duy nhất một loại thiết bị.
    Thông tin về id của mỗi Vendor, Product được đăng kí với tổ chức hỗ trợ USB.

  • Driver không phải là tất cả để một thiết bị cắm vào hoạt động.
    Nhiều thiết bị để hoạt động được thì còn cần thêm một cái là firmware nữa.
    Firmware chứa mã chương trình mà driver sẽ tống vào thiết bị.
    Sau khi thiết bị chạy được bằng firmware đó rồi.
    Thì giao tiếp phía sau sẽ là giữa firmwaredriver.
    Firmware thường chứa những đoạn chương trình không thể công khai của Vendor.
    Vì thế, cách này thường được dùng để giữ những tài sản công nghệ của họ.

2. Lấy thông tin Vendor, Product từ /var/log/syslog

  • Như ta đã biết, linux có một hệ thống file log, chứa những thông tin trong
    quá trình hoạt động của nhân, các phần mềm, dịch vụ. Nó thường nằm ở /var/log/
    Trong trường hợp này, ta chỉ quan tâm đến log của nhân, ta sẽ xem file /var/log/syslog/
    Câu lệnh để xem ở chế độ live là:
$tail -f /var/log/syslog
  • Để quan sát được toàn bộ log của quá trình từ lúc cắm thiết bị đến lúc dùng được
    ta sẽ bật lệnh xem log ở trên ở một terminal khác cho tiện.
    Nếu không, ta phải xem lại file log ở trên và tìm ra được tương ứng cho thiết bị.

    Để dễ hiểu hơn, ta sẽ lấy ví dụ về thiết bị cụ thể:

  • Thiết bị là USB-Serial Converter, có giao tiếp bằng USB.
    Ta cùng xem sẽ lấy được thông tin gì từ log của thiết bị này:
    Đoạn log ta lấy được như như sau:
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.576063] usb 2-3.1: new full-speed USB device number 14 using xhci_hcd
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671613] usb 2-3.1: New USB device found, idVendor=0403, idProduct=6015
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671617] usb 2-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671620] usb 2-3.1: Product: FT230X Basic UART
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671622] usb 2-3.1: Manufacturer: FTDI
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671624] usb 2-3.1: SerialNumber: DJ00LL3D
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.675291] ftdi_sio 2-3.1:1.0: FTDI USB Serial Device converter detected
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.675344] usb 2-3.1: Detected FT-X
Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.675737] usb 2-3.1: FTDI USB Serial Device converter now attached to ttyUSB0
Apr 23 12:01:54 OEDEV-Ubuntu mtp-probe: checking bus 2, device 14: "/sys/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1"
Apr 23 12:01:54 OEDEV-Ubuntu mtp-probe: bus: 2, device: 14 was not an MTP device

Ta thấy từ log trên có đoạn:

Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.671613] usb 2-3.1: New USB device found, idVendor=0403, idProduct=6015

Chính dòng này đang chứa id của VendorProduct:
Cụ thể: idVendor = 0403, idProduct = 6015

Về cơ bản, thông tin đến đây là đủ để tìm driver trong source của nhân rồi.
Ngoài ra bạn cũng sẽ thấy một số thông tin về Vendor cũng như thiết bị trong log ở trên:

Ví dụ:
Product: FT230X Basic UART
Manufacturer: FTDI
SerialNumber: DJ00LL3D

Ở đây, từ log trên ta cũng biết được một thông tin quan trọng khác là thiết bị đã chạy hay chưa.

Apr 23 12:01:54 OEDEV-Ubuntu kernel: [ 5046.675737] usb 2-3.1: FTDI USB Serial Device converter now attached to ttyUSB0

Chính dòng này đã cho ta biết được là thiết bị đã chạy được.
Vì sao?
Nó đã được attached vào vị trí /dev/ttyUSB0 để cho phép các ứng dụng khác sử dụng.
Tức là ta có một cổng COM giống như trên windows rồi.
Nhưng vì ở Linux thì mọi thứ là file nên cổng com cũng là một file.

Nếu không có bước này thì ta có thể coi như thiết bị chưa dùng được cho dù kernel đã nhận
biết được có một thiết bị được cắm vào.

3. Lấy thông tin Vendor, Product từ lsusb

lsusb là câu lệnh liệt kê tất cả các thiết bị usb hiện có, kể cả thiết bị chưa sử dụng được.
Output của nó kiểu như sau:

$ lsusb
Bus 001 Device 002: ID 8087:8001 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 009: ID 064e:c231 Suyin Corp.
Bus 002 Device 005: ID 8087:07dc Intel Corp.
Bus 002 Device 013: ID 1f55:0004
Bus 002 Device 014: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

2 giá trị được ngăn cách bởi : phía sau ID chính là id của VendorProduct.

Nếu bản linux của bạn hỗ trợ lsusb, bạn có thể dễ dàng xác định bằng cách
so sánh đầu ra của câu lệnh lsusb trước và sau khi cắm một thiết bị vào máy.

Ví dụ:
Trước khi cắm thiết bị, output của lsusb là:

$ lsusb
Bus 001 Device 002: ID 8087:8001 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 009: ID 064e:c231 Suyin Corp.
Bus 002 Device 005: ID 8087:07dc Intel Corp.
Bus 002 Device 013: ID 1f55:0004
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Sau khi cắm thiết bị, output của lsusb là:

$ lsusb
Bus 001 Device 002: ID 8087:8001 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 009: ID 064e:c231 Suyin Corp.
Bus 002 Device 005: ID 8087:07dc Intel Corp.
Bus 002 Device 013: ID 1f55:0004
Bus 002 Device 014: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Như ta đã thấy, thiết bị mà ta vừa xác đinh ở trên chỉ xuất hiện ở lệnh lsusb sau.

4. Tìm source code từ thông tin Vendor, Product

Giả định rằng ta đã có id của Vendor hay idVendor và id của Product hay idProduct
Ta tiếp tục sử dụng thiết bị ở trên:

Product: FT230X Basic UART
Manufacturer: FTDI
SerialNumber: DJ00LL3D
idVendor = 0403
idProduct = 6015

Ta cần tìm source của driver cho thiết bị này trong source của kernel.

Ta tải bạn kernel statble mới nhất tại https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.10.12.tar.xz, và giải nén:

$ cd linux-4.10.8/
$ ls
arch   COPYING  Documentation  fs       ipc      kernel       Makefile         modules.order   README   security    tools  vmlinux
block  CREDITS  drivers        include  Kbuild   lib          mm               Module.symvers  samples  sound       usr    vmlinux.o
certs  crypto   firmware       init     Kconfig  MAINTAINERS  modules.builtin  net             scripts  System.map  virt

Ta tìm source driver cho thiết bị trên như sau:

  • Tìm theo vendor id:
$ grep -n -R 0x0403 drivers/usb
drivers/usb/serial/ipaq.c:66:   { USB_DEVICE(0x045E, 0x0403) }, /* Windows Powered Pocket PC 2002 */
drivers/usb/serial/cp210x.c:203:        { USB_DEVICE(0x1FB9, 0x0403) }, /* Lake Shore Model 475A Gaussmeter */
drivers/usb/serial/ftdi_sio.h:449: * 8  idVendor        2       0x0403  Vendor ID
drivers/usb/serial/ftdi_sio_ids.h:16:#define FTDI_VID   0x0403  /* Vendor Id */
drivers/usb/serial/ftdi_sio_ids.h:47: * OpenRD Base, Client use VID 0x0403
drivers/usb/serial/ftdi_sio_ids.h:233: * Almost all of these devices use FTDI's vendor ID (0x0403).
drivers/usb/serial/ftdi_sio_ids.h:346: * Hameg HO820 and HO870 interface (using VID 0x0403)
drivers/usb/serial/ftdi_sio_ids.h:1352: * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
drivers/usb/serial/ftdi_sio_ids.h:1373: * Segway Robotic Mobility Platform USB interface (using VID 0x0403)
drivers/usb/misc/ftdi-elan.c:86:#define USB_FTDI_ELAN_VENDOR_ID 0x0403

$ grep -n -R 0x6015 drivers/usb
drivers/usb/serial/ftdi_sio_ids.h:26:#define FTDI_FTX_PID   0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */

Nếu ta đã biết về lập trình C, thì thường giá trị hardcode như 0403, 0615 sẽ được định nghĩa
và sử dụng định nghĩa đó ở những nơi khác chứ không sử dụng trực tiếp giá trị.

Từ kết quả ở trên ta thấy có 2 dòng define cho giá trị 0x04030x6015
cùng ở file drivers/usb/serial/ftdi_sio_ids.h. Đó là

drivers/usb/serial/ftdi_sio_ids.h:16:#define FTDI_VID   0x0403  /* Vendor Id */
drivers/usb/serial/ftdi_sio_ids.h:26:#define FTDI_FTX_PID   0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) *

Ta hiểu rằng, 2 giá trị trên sẽ được sử dụng bằng tên đại diện FTDI_VIDFTDO_FTX_PID ở những nơi khác.

Ta tiếp tục tìm, vì một nhà sản xuất sẽ có rất nhiều thiết bị.
Vì thế ta nên tìm thiết bị để có kết quả chính xác hơn. Trong trường hợp này là FTDO_FTX_PID

$ grep -n -R FTDI_FTX_PID
drivers/usb/serial/ftdi_sio_ids.h:26:#define FTDI_FTX_PID   0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
drivers/usb/serial/ftdi_sio.c:177:      { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },

Và đây, source cho driver của thiết bị nằm ở drivers/usb/serial/ftdi_sio.c.

5. Tham khảo

Để biết thêm về cách tạo, đọc một driver (đặc biệt của usb) trong linux.
Có lẽ không chỗ nào tốt hơn chính là tài liệu (hoặc sách) do người viết (maintain) những driver đó.

Thực sự nên đọc cuốn sách Linux Device Driver 3rd Edition (hoàn toàn free) của chính những maintainer tại địa chỉ https://lwn.net/Kernel/LDD3/

Một cuốn nữa (và cũng free) nên đọc là Linux in A Nutshell (link tại http://files.kroah.com/lkn/ ) cũng của một maintainer chính cho nhân Linux.

Advertisements

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s