Current location - Quotes Website - Collection of slogans - How to write USB device driver under linux
How to write USB device driver under linux
There are four basic things to do when writing USB drivers: devices to be supported by drivers, registering USB drivers, detecting and disconnecting connections, and submitting and controlling urb(USB request block).

Devices supported by the driver: there is a structure struct usb_device_id, which provides a list of different types of usb devices supported by the driver. For drivers that only control specific USB devices, the struct usb_device_id table is defined as:

/* List of devices supported by drivers */

Static structure usb_device_id skel_table [] = {

{USB devices (USB _ SKEL _ supplier _ID, USB _ SKEL _ product _ID)},

{}/* Terminate the entrance */

};

MODULE_DEVICE_TABLE (usb,skel _ TABLE);

For PC driver, MODULE_DEVICE_TABLE is necessary, usb must be the first value of macro, and USB _ SKEL _ manufacturer _ID and USB _ SKEL _ product _ID are the ID of the manufacturer and product of this special device. We changed the definition value of USB in the program, such as:

/* Define the ID number of the manufacturer and product */

# define USB _ SKEL _ supplier _ID 0x 1234.

# define USB _ SKEL _ product _ID 0x2345

These two values can be used by the command lsusb, of course, you have to plug the usb device into the host first. Or check the manufacturer's USB device manual. Running lsusb on my machine is like this:

Bus 004 Device 00 1: ID 0000:0000

Bus 003 Equipment 002: ID 1234:2345 Abc Company

Bus 002 Device 00 1: ID 0000:0000

Bus 00 1 device 00 1: ID 0000:0000.

Get these two values and define them in the program.

Register USB drivers: The structure that all USB drivers must create is struct usb_driver. This structure must be filled by USB driver, including many callback functions and variables, which describe USB driver to USB core code. In order to create an effective struct usb_driver structure, only five fields need to be initialized, which is the case in the framework program:

Static structure usb_driver skel_driver = {

. Owner = THIS_MODULE,

. name = "skeleton ",

. probe = skel_probe,

. disconnect = skel_disconnect

. id_table = skel_table,

};

Detection and disconnection: When a device is installed and the USB core thinks that it should handle the driver, it calls the detection function, which checks the device information passed to it and judges whether the driver is really suitable for the device. When the driver should not control the device for some reason, it will call the disconnect function, which can do some cleaning work. In the probe callback function, the USB driver initializes any local structure that can be used to control USB devices, and it also saves any required device-related information into the local structure.

Submit and control urb: When the driver has data to send to the USB device (mainly in the driver's write function), an urb should be allocated to transmit the data to the device:

/* Create a urb and allocate a cache for it */

urb = usb_alloc_urb(0,GFP _ KERNEL);

If (! urb) {

retval =-eno mem;

Goto error;

}

After the urb is successfully allocated, a DMA buffer should be created to send data to the device in an efficient way, and the data passed to the driver should be copied to the buffer:

buf = USB _ buffer _ alloc(dev-& gt; udev,count,GFP _ KERNEL & amp; urb-& gt; transfer _ DMA);

If (! buf) {

retval =-eno mem;

Goto error;

}

if (copy_from_user(buf,user_buffer,count)) {

retval =-e fault;

Goto error;

}

When data is copied from user space to local buffer correctly, urb must be initialized correctly before it can be submitted to USB core:

/* Initialize urb */

usb_fill_bulk_urb(urb,dev-& gt; Uddhav,

USB _ sndbulkpipe(dev-& gt; udev,dev-& gt; bulk_out_endpointAddr),

buf,count,skel_write_bulk_callback,dev);

urb-& gt; TRANSFER _ flags | = URB _ NO _ TRANSFER _ DMA _ MAP;

The urb can then be submitted to the USB core for transmission to the device:

/* Send data from batch output port */

retval = usb_submit_urb(urb,GFP _ KERNEL);

if (retval) {

Error ("%s-commit for writing urb failed with error %d", __FUNCTION__, retval);

Goto error;

}

When the urb is successfully transferred to the USB device, the urb callback function will be called by the USB kernel. In our example, we initialize the urb to point to the skel_write_bulk_callback function, as follows:

Static void skel _ write _ bulk _ callback (struct urb * urb, struct pt_regs *regs)

{

struct usb _ skel * dev

dev =(struct USB _ skel *)ur B- & gt; Context;

if(urb-& gt; Status and responsibility. & amp

! (urb-& gt; Status == -ENOENT ||

urb-& gt; status = =-econreset | |

urb-& gt; status == -ESHUTDOWN)) {

Dbg("%s-non-zero write batch status received: %d ",

__FUNCTION__,urb-& gt; Status);

}

/* Release allocated buffer */

USB _ buffer _ free(urb-& gt; dev,urb-& gt; Transmission buffer length,

urb-& gt; transfer_buffer,urb-& gt; transfer _ DMA);

}

Sometimes the USB driver just wants to send or receive some simple data, and the driver can transmit data without urb. This involves two simple interface functions: usb_bulk_msg and usb_control_msg. In this USB framework program, the read operation is such an application:

/* Perform a blocked bulk read to get data from the device */

retval = USB _ bulk _ msg(dev-& gt; Uddhav,

USB _ rcvbulkpipe(dev-& gt; udev,dev-& gt; bulk_in_endpointAddr),

dev-& gt; bulk_in_buffer

min(dev->; Bulk_in_size, count),

& Count, Hz *10);

/* If the reading is successful, copy it to user space */

If (! retval) {

if (copy_to_user(buffer,dev-& gt; bulk_in_buffer,count))

retval =-e fault;

other

retval = count

}

The definition of usb_bulk_msg interface function is as follows:

Intusb _ bulk _ msg (structusb _ device * usb _ dev, unsigned int pipe,

void *data,int len,int *actual_length,int time out);

Its parameters are:

Struct usb_device *usb_dev: the pointer to the target usb device to which the batch message is sent.

Unsigned int pipe: the specific endpoint of the target USB device to which the batch message is sent. This value is created by calling usb_sndbulkpipe or usb_rcvbulkpipe.

Void *data: If it is an OUT endpoint, it is a pointer to the data to be sent to the device. If it is an IN endpoint, it is a pointer to the location where the data read from the device should be stored.

Intlen: The buffer size indicated by the data parameter.

Int *actual_length: a pointer to the location where the actual number of bytes transmitted is saved. Whether it is sent to or received from the device depends on the direction of the endpoint.

Int timeout: timeout of waiting, in seconds. If the value is 0, the function will wait for the end of the message.

If the interface function is called successfully, the return value is 0, otherwise, a negative error value is returned.

The usb_control_msg interface function is defined as follows:

Int usb_control_msg (structure usb_device *dev, unsigned int pipe, __u8 request, _ _ u 8 request type, __u 16 value, __u 16 index, void * data, __u 16 size.

Except that the driver is allowed to send and receive USB control messages, the operation of usb_control_msg function is similar to that of usb_bulk_msg function, and its parameters are different from usb_bulk_msg in several important aspects:

Struct usb_device *dev: a pointer to the target usb device sent by the control message.

Unsigned int pipe: controls the specific endpoint of the target USB device to which the message is sent. This value is created by calling usb_sndctrlpipe or usb_rcvctrlpipe.

__u8 request: USB request value of the control message.

__u8 requesttype: the USB request type value of the control message.

__u 16 value: USB message value of control message.

__u 16 index: USB message index value of control message.

Void *data: If it is an OUT endpoint, it is a pointer to the data to be sent to the device. If it is an IN endpoint, it is a pointer to the location where the data read from the device should be stored.

_ _ u 16 size: the buffer size indicated by the data parameter.

Int timeout: the timeout that should be waited in seconds. If 0, the function will wait for the end of the message.

If the interface function is successfully called, the number of bytes sent to or read from the device is returned; If it is unsuccessful, it will return a negative error value.

Neither of these interface functions can be called in an interrupt context or with a spin lock. Similarly, this function cannot be cancelled by any other function, so be careful when using it.

If you want to write a driver for an unknown USB device, you only need to modify this framework program slightly. We have said that we need to modify the id numbers of manufacturers and products, and change the two values of 0xfff0 to the ID numbers of unknown USB.

# define USB _ SKEL _ vendor _ID 0xfff0

# define USB _ SKEL _ product _ID 0xfff0

In addition, the type of the interface endpoint to be detected is written in the detection function. In this framework program, only a batch of (USB_ENDPOINT_XFER_BULK)IN and OUT endpoints are detected. Here, a mask (USB_ENDPOINT_XFERTYPE_MASK) can be used to detect other endpoint types. The driver will test each interface of the USB device once, and when the test is successful, the driver will be bound. Then there is the initialization of urb. If you just write a simple USB driver, you don't need to consider it. What is in the framework program is enough. Here we briefly introduce three auxiliary functions for initializing urb:

Usb_fill_int_urb: Its function prototype is as follows:

Void usb_fill_int_urb (structure urb *urb, structure usb_device *dev,

Keywords unsigned integer pipeline, void *transfer_buff,

int buffer_length,usb_complete_t complete

void *context,int interval);

This function is used to correctly initialize the urb to be sent to the interrupt endpoint of USB device.

Usb_fill_bulk_urb: Its function prototype is as follows:

Void usb_fill_bulk_urb (structure urb *urb, structure usb_device *dev,

Unsigned integer pipeline, void *transfer_buffer,

int buffer_length,usb_complete_t complete)

This function is used to correctly initialize the batch urb endpoint.

Usb_fill_control_urb: Its function prototype is as follows:

void USB _ fill _ control _ urb(struct urb * urb,struct usb_device *dev,unsigned int pipe,unsigned char *setup_packet,void *transfer_buffer,int buffer_length,usb_complete_t complete,void * context);

This function is used to correctly initialize the control urb endpoint.

Isochronous urb also has initialization function, but there is no initialization function at present, so they must be initialized manually in the driver before being submitted to USB core. You can refer to the konicawc.c file under /usr/src/~/drivers/usb/media in the kernel source code tree.