The previous blog post to Lichee did a series of analysis, in fact, in the "Seven itch," said, Android BSP has a basic quality-shell script, so we Lichee series of articles focused on the shell script and lichee the basic structure, Of course, as a qualified Android BSP engineer, mastering the Linux driver porting is also a basic skill. As a result, some of the drivers for sun4i will be analyzed in depth from the beginning of this article. Of course, the driver involves a wide range, such as the camera driver involves sensor porting and kernel queue and other data structure related content, SD card driver also involves the basic principle of DMA, touch screen driver involves input subsystem, interrupt context and other related knowledge, WiFi driver will involve wireless LAN protocol part as well as wap_supplicant and other related knowledge, 2g/3g module often involves Ril library and at command and so on, in addition, in order to facilitate management, most external devices are hung in IIC USB UART and other various bus (or virtual bus), each Development board has its own schematic diagram and route, the hardware related content is also BSP engineers in the debugging drive is not open. Reasoning, because of the complexity involved, in addition to my ability and limited, or feel standing in the angle of the BSP analysis, the first simple introduction of basic background knowledge, understand the meaning of the driver, and then proceed to optimize the transplant drive, with this more practical way to slowly module seemingly more difficult driver.
Processor: sun4i A10System: Android platform Architecture: ARM
From simple to complex, first let's explore the driver of sun4i Gpio DRIVERS/MISC/SUN4I-GPIO.C
First, what is a Gpio
GPIO General-purpose IO ports , which is the generic io port. Embedded systems often have a large number of, but relatively simple structure of external devices / circuit, on these devices / circuit some need cpu The provides the control means, and some need to be cpu as the input signal. Moreover, many such devices / circuit only requires one, that is, as long as there is a / The two States are sufficient, such as light and off. For these devices / circuit control, using a traditional serial port or parallel port is not appropriate. So on the microcontroller chip will generally provide a "universal programmable io Interface", that is gpio .
The interface has at least two registers, namely "Universal IO Control register" and "Universal IO data register". All data registers are directed to the outside of the chip, and the function of each bit in this register, that is, the direction of the signal flow of each bit, can be set by the corresponding bit independent in the control register. Thus, having a GPIO interface becomes a feature of the microcontroller that distinguishes it from microprocessors.
Second, A10 GPIO
The A10 has 8 sets of multifunction input/output gpio as shown below port A (PA): Input/output portport B (PB): Input/output portport C (PC): Input/output Portport D (PD): Input/output portport E (PE): Input/output portport F (PF): 6 input/output portport G (PG): Input/output portport H (PH): Input/output portport I (PI): Input/output portport S (PS): + input/output P ORT for DRAM Controller
In order to cope with the changeable system configuration, these sets of Gpio can be easily configured by software, in addition to PS, the other groups of Gpio can be configured as multi-functional mode, also support 32 software configuration of external interrupt source and interrupt mode port S (PS) is designed for the DRAM controller, So the Gpio ports we usually use are between PA-PI
Third, the source code parsing in the linux-3.0 directory drivers/misc/sun4i-gpio.c we know that when a driver is loaded, it executes the module_init, and the driver exits when it executes module_exit then we'll go from Module_ Init (sun4i_gpio_init) begins analysis, and when the driver is loaded, it goes to sun4i_gpio_init (void)
Normally, the function in the driver is usually decorated with static, because C language does not have the namespace in C + +, that is, the namespace, after being decorated with static, the function name is equivalent to in the current source file is visible, Even if the other source file has the same name function does not affect the compilation, here we choose the driver, the final one of the functionSun4i_gpio_init to the full text analysis
static int __init sun4i_gpio_init (void) {int err; int i; int sun4i_gpio_used = 0; struct Sun4i_gpio_data *gpio_i;/*includ E/linux/sysfs.h-------------------------------------struct Attribute {const char *name; struct module *owner; mode_t mode;}; struct Device_attribute {struct attribute attr; ssize_t (*show) (struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store) (struct device *dev, struct device_attribute *attr, const char *BUF, size_t count);}; These 2 are the SYS file system in the structure, the key point in the Device_attribute show and store, in fact, the device read and write * * struct device_attribute *attr_i; Char pin[16]; Pr_info ("sun4i gpio driver init\n");/* is used to get the Sys_config1.fex value of the sub-key Gpio_para The primary key gpio_used, if the value of gpio_used is 0, This means that the driver has been configured to shut down, so that the configuration can be used to control the open and close the driver here we know if we want to add a separately controlled gpio, we just need to add the Gpio_para primary key and the name Gpio_ in the Sys_config1.fex file. Used sub-key */err = Script_parser_fetch ("Gpio_para", "gpio_used", &sun4i_gpio_used, sizeof (sun4i_gpio_used)/sizeof (int)); if (err) {Pr_err ("%s script_parser_fetch \" Gpio_para\ "\" gpio_used\ "error\n", __function__); Goto exit; } if (!sun4i_gpio_used) {pr_err ("%s Sun4i_gpio is not used in config\n", __function__); Err =-1; Goto exit; }/* is used to get the value of the subkey Gpio_num in the Sys_config1.fex primary key Gpio_para, and it is clear that the value of the subkey Gpio_num is used to define how many gpio*/err = Script_parser_fetch in the configuration (" Gpio_para "," Gpio_num ", &sun4i_gpio_num, sizeof (sun4i_gpio_num)/sizeof (int)); if (err) {Pr_err ("%s script_parser_fetch \" Gpio_para\ "\" gpio_num\ "error\n", __function__); Goto exit; } sun4i_gpio_dbg ("sun4i_gpio_num:%d\n", sun4i_gpio_num); if (!sun4i_gpio_num) {pr_err ("%s sun4i_gpio_num is none\n", __function__); Err =-1; Goto exit; }/* register a miscellaneous device, the main device number is 10, and this device number is defined by the system */err = Misc_register (&sun4i_gpio_dev); if (err) {Pr_err ("%s register Sun4i_gpio as Misc device error\n", __function__); Goto exit; }/* applies a piece of memory to each GPIO struct, based on the number of Gpio, to hold the properties of each Gpio read from the sys_config1.fex file */Psun4i_gpio = kzalloc (sizeof (struct sun4i_ Gpio_data) * Sun4i_gPio_num, Gfp_kernel); */* According to the number of GPIO, request a device attribute per Gpio, each device attribute will be used to read and write to the GPIO in the SYS file system */pattr = kzalloc (sizeof (struct device_ Attribute) * Sun4i_gpio_num, Gfp_kernel); if (!psun4i_gpio | |!pattr) {pr_err ("%s kzalloc failed\n", __function__); err =-enomem; Goto exit; } gpio_i = Psun4i_gpio; Attr_i = pattr;/* Loop reads the value of each gpio in the Sys_config1.fex file and saves the parsed value to Gpio_i */for (i = 0; i < Sun4i_gpio_num; i++) {/* by As you can see, the sub-keys resemble gpio_pin_1 gpio_pin_2 gpio_pin_3 ... This way to name the */sprintf (PIN, "gpio_pin_%d", i+1); sun4i_gpio_dbg ("pin:%s\n", pin); Err = Script_parser_fetch ("Gpio_para", PIN, (int *) &gpio_i->info, sizeof (script_gpio_set_t)); if (err) {Pr_err ("%s script_parser_fetch \" Gpio_para\ "\"%s\ "error\n", __function__, PIN); Break }/************************************************************************************************************* * This is a description of the CSP_GPIO_REQUEST_EX function * csp_gpio_request_ex** function Name: * * Parameter description: Main_name The primary key name, matching module (driver name) * * Sub_name passed the sub-key name, if it is empty , which represents all, otherwise find to match the individual GPio** return Value: 0:err* other:success** Description: no conflict check ********************************************************************* /Gpio_i->gpio_handler = GPIO_REQUEST_EX ("Gpio_para", pin); sun4i_gpio_dbg ("Gpio handler:%d", gpio_i->gpio_handler); if (!gpio_i->gpio_handler) {Pr_err ("%s can not get \" Gpio_para\ "\"%s\ "Gpio handler, already used by others?", _ _FUNCTION__, PIN); Break } sun4i_gpio_dbg ("%s:port:%d, portnum:%d\n", PIN, Gpio_i->info.port, gpio_i->info.port_num); /* Turn the name to PA1, PB2 etc ... */sprintf (gpio_i->name, "p%c%d", ' A ' +gpio_i->info.port-1, gpio_i->info.port_num); sun4i_gpio_dbg ("psun4i_gpio->name%s\n", gpio_i->name); /* Add attributes to the group *//* here to initialize the properties to the SYS file system and assign values to the members of the Device_attribute struct, which is actually the function that defines the read/write IO Sun4i_gpio_enable_ Show is to read the data of Io, and Sun4i_gpio_enable_store is to write the value to IO */sysfs_attr_init (&ATTR_I->ATTR); Attr_i->attr.name = gpio_i->name; Attr_i->attr.mOde = s_irugo| s_iwusr| s_iwgrp| S_iwoth; Attr_i->show = Sun4i_gpio_enable_show; Attr_i->store = Sun4i_gpio_enable_store; Sun4i_gpio_attributes[i] = &attr_i->attr; gpio_i++; attr_i++; } sysfs_create_group (&sun4i_gpio_dev.this_device->kobj, &sun4i_gpio_attribute_group); Exit:return err;} static void __exit sun4i_gpio_exit (void) {sun4i_gpio_dbg ("Bye, Sun4i_gpio exit\n"); Sysfs_remove_group (&sun4i_ Gpio_dev.this_device->kobj, &sun4i_gpio_attribute_group); Misc_deregister (&sun4i_gpio_dev); Kfree (Psun4i_gpio); Kfree (pattr);} struct Sun4i_gpio_data, this struct is actually used to describe a gpiostruct sun4i_gpio_data {int status; The current state, in fact, is the value of the Gpio, 0 or 1 unsigned gpio_handler; Used to identify this gpio, equivalent to a unique ID script_gpio_set_t info; Char Name[8]; A 8-byte string is used to describe a name such as "PI09"}script_gpio_set_t struct, which is really used to describe a single gpiotypedef struct{char gpio_name[32]; int port; int Port_ Num int Mul_sel; int pull; int drv_level; int data;} script_gpio_set_t;
Let's start with a look at the Gpio configuration file.;--------------------------------------------------------------------------------; GPIO configuration PC19-PC22 4 io ports are input; gpio_pin_1 buzzer; gpio_pin_2 Camera Light; Gpio_pin_3 printer lamp;--------------------------------------------------------------------------------[Gpio_para]gpio_used = 1Gpio_num = Onegpio_pin_1 = port:pi09<1><default><default><0>gpio_pin_2 = port:pb03<1><default><default><0>gpio_pin_3 = port:ph22<1><default><default><0>gpio_pin_4 = port:ph23<1><default><default><0>gpio_pin_5 = port:ph24<1><default><default><0>gpio_pin_6 = port:ph25<1><default><default><0>gpio_pin_7 = port:ph26<1><default><default><0>gpio_pin_8 = port:pc19<1><default><default><0>gpio_pin_9 = port:pc20<1><default><default><0>gpio_pin_10 = port:pc21<1><default><default><0>gpio_pin_11 = port:pc22<1><default><default><0>
Take gpio_pin_1 as an example, err = Script_parser_fetch ("Gpio_para", PIN, (int *) &gpio_i->info, sizeof (script_gpio_set_t)); This code means to get the primary key to "Gpio_para" from the configuration file, and the sub-key "gpio_pin_1" is stored in the structure script_gpio_set_t.
Gpio_name = "Gpio_pin_1"
Port = ' I '
Port_num =09mul_sel =1pull =defaultdrv_level =defaultdata =0 in the Lichee (v) SYSCONFIG1.FEX configuration System "in this article, we have briefly analyzed sysconfig1.fex and the form of a gpio description
describes the form of Gpio: Port: Ports + Intra-group sequence number < function assignment >< internal resistance status >< drive capability >< Output level status >
Corresponding, Mul_sel is the function assignment, is the abbreviation of the multifunction Select, this determines what function, because we here is the output function, so the default value is 1 to view the relevant Gpio manual, the Mul_sel choice is as follows:
The pull corresponds to the internal resistor state, and the drv_level corresponds to the drive capability, generally using the default value Defalut
Data represents the output level state of the GPIO, typically 1 for high, and 0 for low
The Sysfssys file system is an in-memory virtual file system that provides us with a hierarchy of Kobject objects, helping users to observe the topology of devices in a system in a simple file system. With the Property object, Kobject can provide the kernel variables to the user for reading or writing, in the same way as the exported file. The device model was originally proposed for the convenience of power management of a device topology, but SYSFS is quite unexpected harvest, in order to facilitate debugging, the device model of the developer decided to export the device tree as a file system. This move quickly proved to be very sensible, first SYSFS replaced the device-related files under/proc, and it provided a useful view for system objects, in fact, Sysfs was originally called Driverfs, which appeared earlier than Kobject. Finally Sysfs made us realize that a new object model was very beneficial to the system, so kobject came into being. Starting with the introduction of kernel in 2.6 Sysfs, SYSFS is always part of the essential kernel.
Iv. Results
When we load this drive, we have a gpio with the same name as our Sys_config1.fex file, and we can use echo 1 >/sys/devices/virtual/misc/sun4i-gpio/pin/pi9echo 0 >/sys/devices/virtual/misc/sun4i-gpio/pin/pi9 directly to control the GPIO, and do not need to pass the program here is also a point worth noting, so the files are-rw-rw-rw-, That is, any user can read and write the file, and this is Attr_i->attr.mode = s_irugo| s_iwusr| s_iwgrp| S_iwoth; This code controls the
V. Analysis when I first saw the driver, I was surprised to find that there was no real open, write, read, and so on, because they sun4i_gpio_write and Sun4i_gpio_open were doing the next print, Read function Even print no, there is no, I then seriously read all the code to find out, this gpio driver all gave up file_operations this way, but use SYSFS way to read and write Gpio
Now , let's summarize the benefits of using SYSFS to handle Gpio.1. The characteristics of Gpio determine the use of Sysfs very well, Gpio driver is the most important work is to pull the level of high pull low (sometimes also to send waveform pulses), pull high, can give some equipment to provide voltage, let equipment work, this kind of equipment typical has, buzzer, LED lights, Vibration motors (motor), etc. 2. The use of SYSFS in the Android operating system is also very very suitable, some applications often need to control the hardware, such as the control of the LED light off, buzzer and not sound, if the system is called to open write read, Then we have to provide a JNI interface to the Java program of the application layer, but these interfaces are very simple, it is very troublesome to compile a so library for them. With SYSFS, our application only needs to read and write a file to operate the Gpio.
static int Sun4i_gpio_open (struct inode *inode, struct file *file) {pr_info ("Sun4i_gpio open\n"); return 0;} ssize_t sun4i_gpio_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) {pr_info ("Sun4i_gpio WRI Te\n "); return 0;} static const struct File_operations sun4i_gpio_fops = {. open = Sun4i_gpio_open,. Write = Sun4i_gpio_write,. release= sun4 I_gpio_release};
After the introduction of Lichee, we have a basic understanding of lichee, especially to Sys_ Config1.fex to configure the drive way of understanding, mentioned a very simple driver, this article also tries to explain the driver more thorough, so that beginners more clear, but in the process of writing found that if you want a background knowledge of the introduction, will often lead to another background of the introduction, so want to read the driver, really still Need to have a certain foundation here, Sun4i-gpio Drive the difficulties, mainly sys_ The combination of Config1.fex, as well as the understanding of SYSFS, for these 2 points are more familiar with the people, this drive is really very simple, and is a better driver, not as the author in Kconfig inside the introduction said "a ugly gpio driver" ^_^