Menulis USB Driver #1

Berikut adalah contoh sederhana dalam menulis USB driver di Linux. Dalam tulisan ini, akan dibahas dengan singkat sebuah driver yang memiliki file operation minimum agar dapat berkomunikasi dengan user space dan berkirim data lewat Kernel USB API.

Sebuah USB device wajib memiliki VendorID dan ProductID. Dari kedua identifier tersebut USB root menunjuk device yang bersangkutan. Untuk mengetahui VendorID dan ProductID dari sebuah USB device dapat dilakukan dengan mengetik perintah berikut:

lsusb
Bus 008 Device 002: ID 0a5c:2150 Broadcom Corp.
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bus 002 Device 002: ID 04f2:b13e Chicony Electronics Co., Ltd
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Dari output lsusb di atas mari kita ambil contoh

Bus 002 Device 008: ID 0fca:8004 Research In Motion, Ltd.
VendorID = 0x0fca
ProductID = 0x8004

Kedua identifier tersebut akan kita gunakan sebagai device_id untuk didaftarkan ke dalam USB device table.

static struct usb_device_id usbfoo_table[] = {
        {USB_DEVICE(0x0fca, 0x8004)},
        {}
};

Sebuah USB driver yang akan kita tulis memiliki struktur seperti berikut:

struct usbfoo_dev {
        struct usb_device *udev;
        struct mutex io_mutex;
        char *bulkout_buffer;
        __u8 bulk_out_endpointAddr;
};

Struktur di atas mendeklarasikan struktur usb_device, mutex, buffer dan Alamat bulk_out_endpoint untuk kepentingan operasi driver.

Driver yang akan kita buat ini memiliki interface ke user space di /dev/usbanu agar aplikasi dapat berinteraksi lewat system call (open, read, write, ioctl). Untuk membuatnya, seperti biasa kita rancang sebuah file operation dari driver tersebut. Kita sebut driver tersebut usbfoo.

static struct file_operations usbfoo_fops = {
        .owner=THIS_MODULE,
        .read=usbfoo_read,
        .write=usbfoo_write,
        .open=usbfoo_open,
        .release=usbfoo_release,
};

Langkah selanjutnya adalah mendeklarasikan nama device dan file operationnya ke dalam usb_class_driver sebagai berikut:

static struct usb_class_driver usbfoo_class = {
        .name="usbfoo%d",
        .fops=&secbulk_fops,
        .minor_base=100,
};

Sesudahnya kita definisikan usb_driver sebagai berikut

static struct usb_driver usbfoo_driver= {
        .name="usbfoo",
        .probe=usbfoo_probe,
        .disconnect=usbfoo_disconnect,
        .id_table=usbfoo_table,
        .supports_autosuspend=0,
};

Sampai di sini kita telah merancang kerangka sebuah USB driver yang paling sederhana, dapat diakses dari /dev filesystem dengan nama /dev/usbfoo%d.

Langkah selanjutnya adalah memenuhi kerangka dasar dari sebuah driver yaitu init dan exit.

Inisialisasi driver:

static init __init usbfoo_init (void)
{
       int result;
       printk(KERN_INFO "usbfoo:usbfoo dimuatken n");
       result = usb_register(&usbfoo_driver);
       if (result) {
               printk(KERN_ERR "usbfoo:usb_register gagal: %d", result);
               return result;
       }
       return 0;
}

Exit driver:

static void __exit usbfoo_init(void)
{
        usb_deregister(&usbfoo_driver);
        printk(KERN_INFO "usbfoo dikeluarkann");
}

Mari kita bahas satu per satu langkah-langkah sebuah driver dari mulai inisialisasi hingga dapat berfungsi.

Langkah pertama dari sebuah USB driver (dan driver pada umumnya) adalah registrasi ke dalam kernel yang sedang berjalan yaitu dengan usb_register(&usbfoo_driver). Kita perhatikan isi dari struktur usbfoo_driver sebagai referensi.

Hal selanjutnya adalah urusan dari USB API dari Linux kernel untuk mengecek tiap fungsi yang didefinisikan di dalam usbfoo_driver lalu mengeksekusinya, dimulai dari usbfoo_probe, menambahkan id_table ke dalam list USB id_table. Nama-nama dalam element usb_driver sudah cukup representatif tanpa perlu dijelaskan lebih lanjut bukan?😉

Mari kita tulis implementasi dari usbfoo_probe. Inti dari usbfoo_probe adalah mengecek apakah USB device dengan VendorID dan ProductID yang didefinisikan dalam id_table sudah terdeteksi oleh USB Root atau belum, lalu mendaftarkan interface yang didefiniskan di usbfoo_class.

iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
       endpoint = &(iface_desc->endpoint[i].desc);
       if (!dev->bulk_out_endpointAddr
           && usb_endpoint_is_bulk_out(endpoint)) {
                printk(KERN_INFO "usbfoo:ditemukan bulk out endpoint!n");
                dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
                break;
       }
}

Registrasi interface yang telah didefinisikan di usbfoo_class:

ret = usb_register_dev(interface, &usbfoo_class);
if (ret) {
        printk(KERN_ERR "usbfoo: usb_register_dev failed!n");
        return ret;
}
dev->udev = usb_get_dev(interface_to_usbdev(interface));
usb_set_intfdata(interface, dev);
mutex_init(&dev->io_mutex);

Sampai di sini kita telah berhasil mendaftarkan satu USB driver untuk device dengan VendorID dan ProductID, dan memiliki interface di /dev/usbfoo0

Pos ini dipublikasikan di Linux dan tag , , , . Tandai permalink.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s