Hardware Drive - OSB Device under Linux (below) (Drive Development)

xiaoxiao2021-03-06  101

Zhao Ming (Carl__zhao@163.com) Lenovo Software Design Center Embedded R & D System Design Engineer July USB Skeleton Procedure (USB-Skeleton), is the basis of USB drivers, through learning and understanding of its source code, Let us quickly understand the USB drive architecture and quickly develop our own USB hardware drivers. In the preface "Hardware Drive - OSB Device (on) (on)" under Linux, we know how to use some of the most common USB devices under Linux. But for programmers for system design, this is not enough, we also need to have a driver reading, modification, and development capabilities. In this article, you have to enter the world of USB driver development with you through simple USB drivers. USB driver development After mastering the configuration of the USB device, for programmers, we can try to make some simple USB driver modifications and development. This paragraph, we will explain the basic USB framework, do two small USB drivers. USB skeleton in the Linux Kernel source code directory DRIVER / USB / USB-SKELETON.C provides us with the most basic USB driver. We call the USB skeleton. With it we only need to modify the very few parts, you can complete the driver of a USB device. Our USB driver development is also from she. USB devices that are not supported under Linux are almost all manufacturers specific products. If manufacturers use their own defined protocols in their products, they need a specific driver for this device. Of course, we know that some manufacturers disclose their USB protocol and help Linux drivers development, however some manufacturers do not disclose their USB protocol. Because each different protocol produces a new driver, there is this universal USB drive skeleton program, which is template with a PCI skeleton. If you are ready to write a Linux driver, you must first be familiar with the USB protocol specification. There is its help on the USB home page. Some of the more typical drivers can be found above, and also describe the concept of USB URBS, and this is the most basic in the USB driver. The first thing that Linux USB driver needs to do is to register in the Linux USB subsystem and provide some information. For example, this driver supports that device, when the supported device is inserted or pulled out of the system, there will be Which actions are moved. All this information is sent to the USB subsystem, the usb skeleton driver is represented: static struct usb_driver skel_driver = {name: "skeleton", probe: skel_probe, disconnect: skel_disconnect, fops: & skel_fops, minor: USB_SKEL_MINOR_BASE , id_table: skel_table,}; variable Name is a string that describes the driver. Probe and disconnect are a function pointer that is called when the device matches the variable information in id_table. FOPS and Minor variables are optional. Most USB drivers hooked another drive system, such as SCSI, network, or TTY subsystem. These drivers are registered in other drive systems, and any user space is provided through those interfaces. For example, we drive the SCSI device as another drive system hooked by our USB driver, then our USB device's read, Write When the operation, you can access the READ, WRITE function of the SCSI device accordingly.

But for drivers such as scanners, there is no matching driver system to use, then we have to handle orthographic functions with read, WRITE, etc. The USB subsystem provides a way to register a secondary device number and File_Operations function pointer, so that it can be easily interactively interact with the user space. The key to the USB skeleton program is as follows: 1. USB Drive Registration and Logout USB Driver Send a command to USB_REGISTER when registering, usually in the initialization function of the driver. When you want to uninstall the driver from the system, you need to log out of the USB subsystem. The need usb_unregister function processing: static void __exit usb_skel_exit (void) {/ * deregister this driver with the USB subsystem * / usb_deregister (& skel_driver);} module_exit (usb_skel_exit); when usb device is inserted, in order to make linux-hotplug (Linux in PCI, USB and other equipment hot-swap support) The system automatically loads the driver, you need to create a module_device_table. Code is as follows (this module only supports a particular device): / * table of devices that work with this driver * / static struct usb_device_id skel_table [] = {{USB_DEVICE (USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID)}, {} / * Terminating entry * / }; Module_device_table; USB_Device macro uses vendor ID and product IDs to provide us with unique identifiers for a device. When the system is inserted into a ID matching USB device to the USB bus, the drive will be registered in USB Core. The probe function in the driver will also be called. The USB_DEVICE structure pointer, the interface number and interface ID will be passed to the function. Static void * skel_probe (STRUCT USB_DEVICE * DEV, UNSIGNED INT IFNUM, Const Struct USB_DEVICE_ID * ID) The driver needs to confirm if the inserted device can be accepted, if not accept, or in the initialization process, the probe function returns one NULL value. Otherwise, a pointer containing the device driver status is returned. With this pointer, you can access the callback function in all structures. In the skeleton driver, the last point is what we have to register DEVFS. We created a buffer to save data that is sent to the USB device and data accepted on the device, while USB URB is initialized, and we register your device in the DEVFS subsystem, allow DEVFS users to access our devices.

Registration process as follows: / * initialize the devfs node for this device and register it * / sprintf (name, "skel% d", skel-> minor); skel-> devfs = devfs_register (usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USB_SKEL_MINOR_BASE SKEL-> Minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, & SLEWGRP | S_IROTH, & SKEL_FOPS, NULL); if the devfs_register function fails, don't worry, the DEVFS subsystem reports this situation to the user. Of course, finally, if the device is unplugged from the USB bus, the device pointer will call the disconnect function. The driver needs to clear all private data assigned, close URBS, and tune yourself from DEVFS. / * Remove Our devfs node * / devfs_unregister (Skel-> devfs); now, the Skeleton driver has been binded to the device, and any user state program is to operate this device can be done by the function defined by the File_Operations structure. First, we want Open this device. In the Open function, MODULE_INC_USE_COUNT macro is a key, and its role is a role of a count. There is a user program to open a device. If the counter adds one, for example, we add a driver in module, if the counter is not zero If you have any user programs, you cannot uninstall the drive module through the rmmod command. / * Increment our usage count for the module * / MOD_INC_USE_COUNT; skel-> open_count; / * save our object in the file's private structure * / file-> private_data = skel; finished device when open, read, write function will Can be collected, send data. 2. Skel's WRITE, and READ functions They are the response of the driver to read and write. In Skel_Write, a Fill_bulk_urb function completes the connection between the URB system Callbak and our own skel_write_bulk_callback. Note that skel_write_bulk_callback is an interrupt mode, so pay attention to it takes too long. In this program, it just reports some URB status, etc. The READ function is slightly different from the WRITE function that the program does not use the URB to transfer the data from the device to the driver, but we use the USB_BULK_MSG function instead, this function can send data without the need to create a URBS and an operation URB function. To the device, or from the device to receive data. We call the USB_BULK_MSG function and conduct a storage space to buffer and place the data received by the driver. If the data is not received, it will fail and return an error message. 3. USB_BULK_MSG function When reading or writing for a USB device, the USB_BULK_MSG function is very useful; however, when you need to read / write to the device continuously, it is recommended that you build your URBS while submitting URBS. USB subsystem. 4. Skel_disconnect function When we release the device file handle, this function will be called.

MOD_DEC_USE_COUNT macro will be used (and mod_inc_use_count just right, it reduces a counter), first confirm if there is any other program is accessing this device, if it is the last user, we can turn off any way, the operation is as follows : / * Decrement Our usage count for the device * / --skel-> open_count; if (skel-> open_count <= 0) {/ * shutdown any bulk writes That might be going on * / usb_unlink_urb (Skel-> Write_urb) Skel-> open_count = 0;} / * Decrement Our usage count for the module * / mod_dec_use_count; the most difficult is that USB devices can take away from the system at any time, even if the program is currently being accessed. The USB driver must be able to process this problem well, it needs to be able to cut off any current read and write while notifying the user spatial program: USB device has been taken away. If the program has an open device handle, in the current structure, we only assign it empty, just like it has disappeared. We must check if the USB_DEvice structure exists for other function operations such as read and write each time. If there is no existence, it indicates that the device has disappeared and returns a-enode error to the user program. When we finally call the Release function, when there is no file to open this device, it will empty the Skel_Disconnect function works regardless of whether the USB_DEvice structure exists. The USB skeleton driver provides sufficient example to help initiate a driver in the shortest time. More information You can go to Linux USB to develop newsgroups to find. U disk, USB card reader, MP3, digital camera driver For a cool U disk used in Windows, USB card reader, MP3 or digital camera, may not be supported under Linux. How to do? In fact, you don't have to be sad. Maybe after a little job, you can use it very conveniently. Usually this U disk, USB card reader, MP3 or digital camera does not require manufacturers in WindowsXP to identify as mobile storage devices, such devices can guarantee success, others look at your luck. USB storage devices, their read, Write and other operations are hooked to the SCSI device through the hook mentioned in the previous chapter. We don't need to handle specific data read and write. The first step: We get the device information on the USB bus that detects the current system via CAT / Proc / Bus / USB / Devices. It includes Vendor, Prodid, Product, etc.

Below is the information piece after I bought a cF card reader insert: T: bus = 01 lev = 01 prNT = 01 port = 01 cnt = 02 dev # = 5 SPD = 12 mxCH = 0 D: VER = 1.10 CLS = 00 (> IFC) SUB = 00 prot = 00 mXPS = 8 # cfgs = 1 P: vendor = 07c4 product = a400 REV = 1.13 S: Manufacturer = USB S: Product = mass storage c: * # = 1 CFG # = 1 ATR = 80 mxpwr = 70mA i: if # = 0 alt = 0 # eps = 2 CLS = 08 (vend.) SUB = 06 Prot = 50 Driver = USB-Storage E: AD = 81 (i) ATR = 02 (BULK) MXPS = 64 IVL = 0ms E: AD = 02 (O) ATR = 02 (BULK) MXPS = 64 IVL = 0ms where we are most concerned about Vendor = 07c4 product = a400 and manufacturer = USB (Sure enough It is a hit, and the manufacturer is not seen) Product = Mass Storage. For these mobile storage devices, we know that Linux drives to simulates support to SCSI devices through USB-storage.o, which is not supported, usually the USB-Storage driver does not include this vendor identification and product identification information (similar to Skel_Probe's USB initially detected when it was detected). The hardware access section of the USB storage device is usually consistent. So we have to support it, just modify the USB-Storage for the vendor identification and product identification list. The second part, open the drivers / usb / storage / unusual_devs.h file, we can see all the known product registration form, are based on UNUSUAL_DEV (idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, vendor_name, product_name, use_protocol, use_transport, init_function , Flags) method registration. Among them, you can judge according to naming. So as long as we fill in our own registration, we can let the USB-Storage drive to understand and discover it. UNUSUAL_DEV (07c4, A400, 0x0000, 0xfff, "usb", "mass storage", US_SC_SCSI, US_PR_INQUIRY | US_FL_START_STOP | US_FL_MODE_XLATE) Note: The location of the above sentence must be correct. Comparison discovery, USB-Storage drivers are all registered by Idvendor, and IDProduct values ​​are ranked from small to large. We must also put it in the corresponding position. Finally, fill in the above information, we can recompile to generate a kernel or a USB-Storage.o module. At this time, insert our device, you can visit the other U disk as a SCSI device. Keyboard shuttle supports a lot of keyboards with shuttle and tablet, and we try to add a driver for a keyboard shuttle.

In normal case, when we insert the USB interface keyboard, you will see multiple USB devices in / proc / bus / usb / devices. For example: the shuttle on your USB keyboard is one, your desktop will be one, if your USB keyboard has a USB extension connection, it will also be seen. Here is the specific information T: bus = 02 lev = 00 prNT = 00 port = 00 cnt = 00 dev # = 1 SPD = 12 mxCH = 2 b: alloc = 11/900 US (1%), # int = 1, # ISO = 0 D: VER = 1.00 CLS = 09 (HUB) SUB = 00 Prot = 00 MXPS = 8 # cfgs = 1 P: vendor = 0000 prodid = 0000 REV = 0.00 s: Product = USB UHCI Root Hub S : Serialnumber = d800 c: * # = 4 cfg # = 1 ATR = 40 MXPWR = 0mA i: if # = 0 alt = 0 # eps = 1 CLS = 09 (hub) SUB = 00 prot = 00 Driver = HUB E : Ad = 81 (i) ATR = 03 (int.) MXPS = 8 IVL = 255MS T: bus = 02 lev = 01 prNt = 01 port = 01 cnt = 01 dev # = 3 SPD = 12 mxCH = 3 D: VER = 1.10 CLS = 09 (HUB) SUB = 00 prot = 00 MXPS = 8 # cfgs = 1 P: vendor = 07e4 product = 9473 REV = 0.02 s: manufacturer = alcor s: product = Movado USB Keyboard C: * # IFS = 1 cfg # = 1 ATR = E0 MXPWR = 100mA i: if # = 0 alt = 0 # eps = 1 CLS = 09 (hub) SUB = 00 prot = 00 Driver = HUB E: AD = 81 (i) ATR = 03 (Int.) MXPS = 1 IVL = 255ms Find the corresponding information, you can start working. In fact, the definition of the shuttle and the keyboard key are usually the same, so we can refer to the drivers / usb / usbkbd..c code. Because I didn't get the corresponding hardware USB protocol, I didn't know what the mobile phone protocol was in the case of the communication agreement, I could only play it out of the information. Fortunately, it is relatively simple, in the USB_KBD_IRQ function below code (KBD-> New [0] == (CHAR) 0x01) and IF ((KBD-> New [1] >> 4) & 0x0f)! = 0x7 ) Is judged to the shuttle left-handed. The USB_KBD_IRQ function is the keyboard interrupt response function. His mount is in the USB_KBD_PROBE function in the USB_KBD_PROBE function (& KBD-> IRQ, DEV, PIPE, KBD-> NEW, MAXP> 8? 8: Maxp, USB_KBD_IRQ, KBD, Endpoint-> binterval); From the USB skeleton, we know that the USB_KBD_PROBE function is that the USB device is found to be running. Other parts are not critical.

You can make some modifications depending on the specific probe (vendor = 07e4 prodid = 9473, etc.). It is worth mentioning that in the keyboard interrupt, our practice is to receive the USB shuttle message, simulate it into the left direction button and the right direction key, here, see how you want to respond. Of course, you can also respond to expansion keys such as F14, F15. After learning this basic driver, you should be able to develop a corresponding drive for a keyboard that you have already got a communication protocol. See Appendix 1: Keyboard shuttle drive. Using this driver should pay attention: When you load this driver, you must first uninstall the HID device, load the USBHKEY.O module and load HID.O. Because if the HID exists, its Probe will block the system to use our driver to discover our devices. In fact, the shuttle is originally an HID device, the right way, maybe you should modify the HID's Probe function, then integrate our drive into it.

Reference 1. "Linux Device Driver" Alessandro Rubini, Lisoleg Translation 2. "Linux System Analysis and Advanced Programming Technology" Zhou Wei Song compiled 3. Linux kernel-2.4.20 source code and document description Appendix 1: Keyboard shuttle drive #include < Linux / kernel.h> #include #include #include #include #include #include / * * Version Information * / #define dRIVER_VERSION "" #define DRIVER_AUTHOR "TGE HOTKEY" #define DRIVER_DESC "USB HID Tge hotkey driver" #define USB_HOTKEY_VENDOR_ID 0x07e4 #define USB_HOTKEY_PRODUCT_ID 0x9473 // manufacturers and the product ID information is / proc / bus / usb / devices seen values ​​MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); struct usb_kbd {struct input_dev dev; struct usb_device * usbdev; unsigned char new [8]; unsigned char old [8]; Struct URB IRQ, LED; // DevRequest DR; // This line and the next line difference lies in the definition of the Kernel2.4.20 to the USB_KBD keyboard structure definition, Struct USB_CTRLREQUEST DR; UNSIGNED Char LEDs, Newleds; Char Name [ 128]; int open;}; // This structure comes from the kernel Drivers / USB / USBKBD..C static void usb_kbd_irq (struct urb * urb) {struct usb_kbd * kbd = urb-> con Text; int * new; new = (int *) kbd-> new; if (kbd-> new [0] == (char) 0x01) {IF (((kbd-> new [1] >> 4) & 0x0f )! = 0x7) {handle_scancode (0xE0, 1); handle_scancode (0x4b, 1); handle_scancode (0xE0, 0); handle_scancode (0x4b, 0);} else {handle_scancode (0xE0, 1); handle_scancode (0x4d, 1) Handle_scancode (0xE0, 0); handle_scancode (0x4d, 0);}}}} printk ("new =% x% x% x% x% x% x% x", KBD-> New [0], KBD- > New [1], KBD-> New [2], KBD-> New [3], KBD-> New [4], KBD-> New [5], KBD-> New [6], KBD-> New [7]);} static void * USB_KBD_PROBE (Struct USB_Device * dev, unsigned int ifnum, const struct usb_device_id * id) {struct usb_interface * ifce;

struct usb_interface_descriptor * interface; struct usb_endpoint_descriptor * endpoint; struct usb_kbd * kbd; int pipe, maxp; iface = & dev-> actconfig-> interface [ifnum]; interface = & iface-> altsetting [iface-> act_altsetting]; if ((dev !! -> descriptor.idVendor = USB_HOTKEY_VENDOR_ID) || (dev-> descriptor.idProduct = USB_HOTKEY_PRODUCT_ID) || (ifnum = 1)) {return NULL;} if (dev-> actconfig-> bNumInterfaces = 2) {!! return NULL;} if (interface-> bNumEndpoints = 1!) return NULL; endpoint = interface-> endpoint 0; pipe = usb_rcvintpipe (dev, endpoint-> bEndpointAddress); maxp = usb_maxpacket (dev, pipe, usb_pipeout (pipe) USB_SET_PROTOCOL (dev, interface-> binterfacenumber, 0); USB_SET_IDLE (DEV, Interface-> BinterFacenumber, 0, 0); Printk (Kern_info "Guo: VID =% .4x, PID =% .4x, device =%. 2X, IFNUM =% .2x, bufcount =% .8X // n ", dev-> descriptor.idvendor, dev-> descriptor.idproduct, dev-> descriptor.bcddevice, ifnum, maxp); if (! (Kbd = Kmalloc (Struct USB_KBD), GFP_kernel)) Return Null; MEMSET (KBD, 0, SIZEOF (STRUCT USB_KBD)); KBD-> USBDEV = dev; Fill_INT_URB (& KBD-> IRQ, DEV, PIPE, KBD-> New, MAXP> 8? 8: Maxp, USB_KBD_IRQ, KBD, Endpoint-> Binterval; KBD- > Irq.dev = KBD-> USBDEV; if (dev-> descriptor.imanufacture) USB_String (dev, dev-> descriptor.imanufacturer, kbd-> name, 63); if (USB_SUBMIT_URB (& KBD-> IRQ)) {Kfree (kbd); Return Null;} Printk (kern_info "INPUT% D:% s ON USB% D:% D.% d // n", KBD-> dev.Number, KBD-> Name, Dev-> bus- > Busnum, Dev-> devnum, ifnum); Return KBD;

转载请注明原文地址:https://www.9cbs.com/read-100387.html

New Post(0)