Menulis USB Driver #2

Melanjutkan pembahasan sebelumnya … Saat ini kita telah memilik sebuah driver yang _seharusnya_ sudah berhasil dimuat dalam kernel yang sedang berjalan namun masih minim fitur yang memungkinkan user untuk menggunakannya.

Mari kita implementasikan beberapa fungsi file operation yang telah didefinisikan di usbfoo_fops.

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

Untuk saat ini kita akan membahas 3 file operation saja yaitu: usbfoo_open, usbfoo_write, dan usbfoo_release.

usbfoo_open adalah handler bagi system call open(2) ketika diarahkan ke device node /dev/usbfoo0. Berikut implementasinya:

static int usbfoo_open(struct inode *node, struct file *file)
{
        struct usb_interface *interface;
        struct usbfoo_dev *dev;

        interface = usb_find_interface(&usbfoo_driver, iminor(node));
        if (!interface)
                return -ENODEV;

        dev = usb_get_intfdata(interface);
        dev->bulkout_buffer = kzalloc(BULKOUT_BUFFER_SIZE, GFP_KERNEL);
        if (!(dev->bulkout_buffer))
                return -ENOMEM;
        if (!mutex_trylock(&dev->io_mutex))
                return -EBUSY;
        file->private_data = dev;
        return 0;
}

Inti dari usbfoo_open adalah memperoleh interface dari usbfoo_driver, lalu menginisialisasi bulkout buffer untuk digunakan di operasi selanjutnya.

Fungsi selanjutnya yang akan diimplementasikan adalah usbfoo_write yang memiliki fungsi utama untuk mentransfer data dari user ke device. Untuk USB device, proses tulis-menulis dan mengirim data memiliki aturan sendiri, yaitu menggunakan usb_bulk_msg() sebagai berikut:

 while (len > 0) {
        to_write = min(len, BULKOUT_BUFFER_SIZE);

        if (copy_from_user
           (dev->bulkout_buffer, buf + total, to_write)) {
                 printk(KERN_ERR "usbfoo:copy_from_user failed!n");
                 return -EFAULT;
           }

        ret = usb_bulk_msg(dev->udev,
                   usb_sndbulkpipe(dev->udev,
                   dev->bulk_out_endpointAddr),
                   dev->bulkout_buffer, to_write, &actual_length,
                   3 * HZ);
        if (ret || actual_length != to_write) {
               printk(KERN_ERR "usbfoo:usb_bulk_msg failed!n");
               return -EFAULT;
        }
        len -= to_write;
        total += to_write;
}
return total;

usbfoo_release adalah handler ketika close(2) dipanggil. Berikut implementasinya:

static int usbfoo_release(struct inode *node, struct file *file)
{
        struct usbfoo_dev *dev;

        dev = (struct usbfoo_dev *)(file->private_data);
        kfree(dev->bulkout_buffer);
        mutex_unlock(&dev->io_mutex);
        return 0;
}

Fungsi di atas sederhana namun fatal jika diabaikan:

1. Membebaskan alokasi memori bulkout_buffer

2. unlock io_mutex

Testing

make -C /lib/modules/`uname -r`/build M=`pwd` modules
insmod usbfoo.ko
dmesg | tail
[296497.670541] usbfoo:usbfoo probing...
[296497.670548] usbfoo:bulk out endpoint found!

Demikian pembahasan mengenai USB driver paling sederhana yang pernah ada :P

Referensi:

LDD 3rd Edition

http://www.linuxjournal.com/article/7353

Pos ini dipublikasikan di Embedded, Linux. 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