Wednesday, June 19, 2013

Device driver diary : my notes

Virtual device are devices which does not have real hardware, these are used to provide certain functionality.
Character devices are used to provide interface to platform to access hardware through certain file operations.
Platform devices are used to put certain functionality inside the device, so that other devices(virtual or physical) can use its functionality.
How init function of each driver is getting called ?
Ans : When we compile the module code, it puts the function pointer of that module init in a file called init.txt. So at the running time, in main.c file a function
reads all of these function pointer and call those one by one.
- device_create() is used to create device, but we need to tell whether it is platform device or character device. Character device do that using cdev_add or cdev_init.
platform device use platform_device_register().
- Major and Minor combination is used identify the device driver by device file.so whenever we create the device as well as add the device to device hierarchy we use this number.
Character Device:
Refere this link : http://www.linuxforu.com/2011/02/linux-character-drivers/

Device Driver Diary : Uevent and Netlink Socket for Kernel-Platform Communication

uevent is a kernel state change notification method. So whenever there is any change in hardware, which needs to be conveyed to platform,platform uses uevent to send those. There will be a daemon from platform side which will monitors these events and respond accordingly.
So uevent is nothing but a notification which consists detailed information about this event. For example :
add@/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host6 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host6 SUBSYSTEM=scsi DEVTYPE=scsi_host SEQNUM=1165
This tells many things like what is the device name, device id, subsystem, device type, action(add,remove).
so lets see how it adds the variable info:
to do the same it needs a method add_uevent_var().Here we put the information. for example :
env = kzalloc (sizeof (struct kobj_uevent_env), GFP_KERNEL);
retval = add_uevent_var (env, “ACTION =% s”, action_string);
retval = add_uevent_var (env, “DEVPATH =% s”, devpath);
retval = add_uevent_var (env, “SUBSYSTEM =% s”, subsystem);
now as string is ready, we will call
kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]);
/*for usb specific*/
kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,disconnected);
So if you want to send any event to platform, you have to use this method ultimately.
Now lets understand a little bit insight of how kobject_event_env() works. Basically this method uses the netlink socket inside.Netlink sockets are the socket which is used to intiate connection from kernel side. It works like this.
1. We create a socket at kernel side, and associate a buffer with this buffer.
2. It calls netlink_broadcast_filtered()
3. It calls do_one_braodcast()
4. It calls netlink_broadcast_deliver() which puts socket into a socket buffer queue. Also it calls sk->dk_data_ready()
5. finally it calls sock_def_readable, it signals the user side socket that the data at kernel side is ready to be read.
At Platform side we have a file at hardware/libhardware_legacy/uevent/ named as uevent.c. This have a function, uvent_init(), it creates the netlink socket at platform side using socket(), and associate the local buffer to it using bind() function. Then in uevent_next_event() function,it will keep on checking the socket for new data. uevent_next_event() function will be called by application.
Important Files :
1. hardware/libhardware_legacy/uevent/uevent.c
2. kernel/lib/kobject_uevent.c
3. kernel/net/netlink/af_netlink.c
4. kernel/drivers/usb/gadget/android.c [for usb related uevents]
5. frameworks/base/core/java/android/os/UEventObserver.java
6. frameworks/base/services/java/com/android/server/usb/UsbService.java
References :
1. http://blog.csdn.net/dfysy/article/details/7330919 [translate it, it will help you a lot about how uevent flow]
2. http://www.linuxjournal.com/article/7356 [complete tutorial on netlink socket, with example]
3. Man page of socket(), bind() and netlink() @ http://linux.die.net
I hope this will help you. Still I have one doubt that how netlink socket is different from normall polling, if you have clue, please comment below.
EDIT : Mr. Rami Rosen told me that its the generic kernel implementation that when a write operation is done on the queue of the socket, a flag which says that the socket can be awakened is set. So until then poll is in blocking state.

Relation between device registration and driver registration

Hi all,
Today I observe one interesting thing during calling platform_driver_register(). The normal thing is if you have a device, and also a driver, It will be linked. But suppose you want to do some different functionality with the device, like you want to do some initialization of few variables  before starting the real functionality of the device.  So a nice way to do this is create multiple device with the same name but different id and register those usingplatform_device_register() or platform_add_devices().
So now when you will call platform_driver_register(), it will check for all devices available with the same name and the same number of probe() function will be called. Here in probe function you can put your logic for initialization according to your id.
Hope it will help you.

Tuesday, June 18, 2013

An Overview of Surfaceflinger

Basic Terminology:

Surface: A Surface in Android corresponds to an off screen buffer into which application renders its content. From application point of view, each application may correspond to one or more graphical interfaces. Each interface can be regarded as surface. Each surface has its position, size, content and other elements.

Surfaceflinger : It is a system-wide surface composer function which resides in android framework. It takes data( which is surface) from different application which could be 2D or 3D and finally combine it to obtain a main surface which will be fed to memory( which is framebuffer).
Surfaceflinger synthesize all the surface according to their position, size and other parameters, although this synthesis is done by OpenGL(which is invoked by Surfaceflinger), but we need Surfaceflinger to calculate the relevant parameters like overlapping function.

HardwareComposer : This is part of HAL, it is used by surfaceflinger to composite surfaces to the screen. The hardware composer abstracts things like overlays and 2D blitters and helps offload some things that would normally be done by OpenGL. This is done by using 3D GPU or a 2D graphics engine.

Gralloc : this is also part of HAL. Gralloc stands for Graphics memory allocator. It has two parts
                1. First provide pmem interface, which is responsible for contiguous memory allocation.
                2. Other is responsible for framebuffer refresh where UI actually put framebuffer data.        
      
Display: it is the physical display device. Current version of surfaceflinger supports only one display device which corresponds to display hardware.

Surfaceflinger, it does 3 main tasks:
                1. It creates a new displayHardware, which is used to establish a FramebufferNativeWindow to determine the data output device interface
                2. Initialize OpenGL, as this is the one which synthesize.
                3. Create main surface, on which all surfaces will be merged.     

How Surfaceflinger starts:

Step 1. SystemServer.main [Defined in SystemServer.java]
         It loads library named android_servers, and then call init1(args) function.

Step 2. SystemServer.init1 [Defined in com_android_server_SystemServer.cpp]
         It further calls system_init() funcion. Now in system_init.cpp it calls like property_get("system_init.startsurfaceflinger", propBuf, "1");  and finally  SurfaceFlinger::instantiate() After this, function checks whether system supports Binder inter-process communication mechanism. It it supports, it will call startThreadPool Binder to start a thread pool, and call the current thread IPCThreadState to be added in front of the Binder thread pool.

Step 3. BinderService.instantiate [Defined in BinderService.h]
        This function is inherited in Surfaceflinger by parent class BinderService.

Step 4. BinderService.publish [Defined in BinderService.h]
        BinderService publish static member function of class action is performed to create a SurfaceFlinger instance which will be used as a system SurfaceFlinger service. And this service will be registered with ServiceManager, so that in future after it starts anyone can use it in the system.  
 
Step 5. New SurfaceFlinger [Defined in SurfaceFlinger.cpp]
        This cunstructor will call init to perform initialization operations.
                
Step 6. SurfaceFlinger.init [Defined in SurfaceFlinger.cpp]
        Here we do some debugging stuff, and as surfaceflinger is Binder proxy object, we passs a pointer of type IBinder strong reference as a parameter. And this will call onFirstRef() function. 
              
Step 7. SurfaceFlinger.onFirstRef [Defined in SurfaceFlinger.cpp]
        First it calls a thread name Surfaceflinger and then it is used to perform UI rendering operations. There is a member class variable in Surfaceflinger, it is used to described as a barrier.It is a thread synchronization tool that blocks the current thread untill the surfaceflinger service UI rendering thread completes initialization operation. It will ultimately will call readyToRun.     
                
Step 8. SurfaceFlinger.readyToRun [Defined in SurfaceFlinger.cpp]
         This code first creates a Display Hardware object, used to describe the device display. And then use this object to initialize Surfaceflinger class member variable mGraphicPlanes which is described as GraphicsPlane. 
This function further allocate 4KB shared memory, it is used to hold the device display attribute information such as width, height, density and no of frames per second. Other process can access this block using getcblk.
Now it initialize dpy(display)'s element like width, length, pixel format and finally make it as primary display. Next we initialize OpenGL Library, as it will be OpenGL which will be rendering.Further, LayerDim:initDimmer() function is called. LayerDim is udes to describe surface with a color gradient function. Then it allows system UI rendering as initialization is complete. Finally we will call boot animation.      
                     
How Framebuffer is opened from SurfaceFlinger:
                      If you remember I mentioned earlier that we create FramebufferNativeWindow. Here it calls framebuffer_open and gralloc_open. First lets take about framebuffer_open. Call goes like : framebuffer_open() -> fb_device_open() -> gralloc_open() -> gralloc_device_open()         
                                                               -> mapFramebuffer() -> mapFramebufferLocked() -> It opens the device as /dev/graphics/fbX or /dev/fbX. Further we pass all other info using IOCTL FBIOPUT_VSCREENINFO depending on Pixel format which we get using property_get() function.
             At the same time we call grDev->alloc which calls gralloc_alloc  which ultimately calls gralloc_alloc_buffer, it allocates ashmem memory for graphics buffer.              
   
How framebuffer is updated:
As we saw Surfaceflinger initialization part, once it is done, surfaceflinger service waits for any event to occur. Event could be anything like new application launched, orientation changed or any other app came in foreground. So after initialization Surfaceflinger is stuck at waitForEvent(). When event occurs, onMessageRecieved() is called. It calls
        -> handleTransaction(), it takes care of shifting layers and adjusting layers according to the size or orientation of window.
         -> handlePageFlip(), it will traverse through each layer and calculate the dirty region(which needs to update). During this time lock is held on frontBuffer.
         -> handleRepaint(), it composes surfacesAs Overlay is present so composer assume framebuffer as transparent and finally draw layer by layer using OpenGL calls.
         -> postFrameBuffers(), This is final call to swap the buffer. call flow goes like this                                              -> flip()[DisplayHardware]->eglSwapBuffers[OpenGL] -> queueBuffer(libui) -> fb_post(gralloc).

How GraphicsBuffer is associated with user application:

In gralloc.h there is a member structure as gralloc_module_t which defines all the method associated with this HAL module. Here we have register_buffer()/unregister_buffer() [Defined in mapper.cpp].                                These methods link the graphics buffer allocated by gralloc_alloc_buffer() to the application address space using native_handle_t(this is one more data structure).

MISC about HAL:
   - For display system, gralloc is provided as a HAL module. Its job is to encapsulates all access to the framebuffer operations.
   - With gralloc device, the user space application can allocate a graphics buffer.
   - Each HAL module has an ID value which will be used to open the module using hw_get_module(). Here it is GRALLOC_HARDWARE_MODULE_ID "gralloc"
   - hw_get_module will load following so file : gralloc..so, gralloc..so, gralloc..so, gralloc..so.[Here in paranthesis these are properties ]
   - you can check private_module_t for a lot of details.

References: 

Saturday, July 28, 2012

Infix to postfix conversion algorithm


This blog has been moved to android.rahulblogs.com
For this post please go to 


http://algo.rahulblogs.com/2012/07/infix-to-postfix-conversion-algorithm/

Tuesday, June 26, 2012

Trek to Thirumaleguppi

Its been a long time since I have been writing a travel blog, and the reason was pretty much because of laziness. So here I am with a new travel blog about my 3rd trekking experience, a place called Thirumaleguppi(apparently it means three peaks) . Although it took me a complete day to remember this name and a whole night, full of bumpy night to reach there, this place worth this trouble.
As you will find Karnataka full of Tourist places specially Natural beauty, sometimes I doubt why people doesn't consider it as a must go travel destination rather than just a IT Hub. Anyways here is my journey details.

Distance : This place is around 300 Kms from Bangalore City Near to Mangalore.

How To reach : you can hire a travel company to arrange the cabs according to your need, or you can take train till Mangalore and can hire cab from there. Once you reach the place, you have to take a Jeep to reach the base camp, as it is around 40 mins ride from the village to base camp.And I must say it is one of the most difficult part of journey, as you will every part of your body shaking specially stomach.


When to Go : I will suggest to go there before heavy rainy season starts which almost be there around July. As this place is surrounded by thick forest too. And slippery place can make your trekking difficult.

What to do : Its a pretty straight forward answer, "do Trekking" :).

How's the trek : Trek is nice and if it is not raining i guess you won't find much problem.  The distance is around 7 Kms one way. And apart from one particular place between peak two and three, it is decent trek.

What to Carry : As water falls is there in between, you may find leeches few places. so I would suggest carry all the necessary items accordingly like knife, salt and specially any spray, it will help you to remove leeches as well as it can be used if you get any strain in your muscles. Apart from these carry raincoat, water bottles and some snacks, as the whole trek will take around 8 hours to complete. Also take care of your shoes, as at the time of getting down, the place is slippery.And yeah if you are planning to stay overnight there please carry the sleeping bag too. Also pack your medicine box with first-aid as well as motion-sickness tablets as road is very bumpy.

Fee : To trek there you have to take the permission of Forest department, they charge around 275 Rs per person. Although as you will take some local guide for trekking, he will arrange it for you, so you don't need to bother. For your reference I am sharing a guide number and name where we stayed, he arrange our breakfast-lunch-dinner as well as the passes and night stay. His name is Satish, and number is 08263-249595 / 9481074530 / 8722847688)

What else : Apart from this, if you want to trek more, you can also go to Kudremukh, it is just adjacent to Thirumaleguppi. One fall is also there which is called as Somavathi Falls, and I must say the water is cold man.

If you are interested to go for other places to trek, I guess you can contact Bangalore Mountaineering Club, those guys organize trekking almost every weekend. I hope this blog will help your preparation for Trekking to Thirumaleguppi.

Keep Enjoying.

Friday, June 15, 2012

OpenGrok : Installation Guide

Hi Guys,
Here is one more useful post for Linux users who use grep to search strings or references in huge code-base.So here it is
Prerequisites :
1. jdk 1.6 + version
2.  tomcat 6 + version
3. exuberant-ctags
I will suggest that become root user (using sudo -s) so that you don’t need to give sudo prefix and then type the password every time you want to run any command. One line command to install all of these :
apt-get install sun-java6-jdk tomcat6 tomcat6-admin exuberant-ctags
4. Download the opengrok-0.8.1 from the site.
Steps:
1. Extract the downloaded package.
2. Create a directory structure like follows
  • mkdir /opengrok
  • mkdir /opengrok/bin(this will contain all lib file and jar file)
  • mkdir /opengrok/data ( this will contain the index data).
3. Go to extracted opengrok directory and run following commnad
  • cp -r run.sh opengrok.jar lib /opengrok/bin
4. Go to /opengrok/bin, open the run.sh file and Edit it in the following way
  • modify SRC_ROOT = /path/to/your/project/directory
  • modify DATA_ROOT = /opengrok/data
  • modify EXUB_CTAGS = /usr/bin/ctags (this is default location for ctags, you can verify with ur system if it doesn’t exist there)
5.  Go to extracted opengrok directory, and create one folder called source
  • mkdir source
  • cd source
  • unzip ../source.war
6. open WEB_INF/web.xml file and add the following code and save it
DATA_ROOT/opengrok/dataREQUIRED: Full path of the directory where data files generated by OpenGrok are stored
SRC_ROOT
//path/to/your/source/directory
REQUIRED: Full path to source tree
SCAN_REPOS
false
Set this variable to true if you would like the web application to scan for external repositories (Mercurial)
Here one more thing you do check for CONFIGURATION tab and in that please check the path of opengrok configuration file. The path should be same as the correct location of that configuration file.
7. Again zip the code
  • cd source
  • zip -r source.war ./
8. Now finally we need to start indexing, so just go to /opengrok/bin folder and give the following command
  • java -Xmx1524m -jar opengrok.jar -W /opengrok/configuration.xml -P -S -v -s  /path/to/your/source/directory  -d /opengrok/data
9.  After indexing completes, you have to modify the admin rights for apache so that you can manage it, So open /etc/tomcat6/tomcat-users.xml and add the following line


10. Now your setup is ready, you just need to deploy the source.war you created earlier. for that follow these steps
  • http://localhost:8080
  • click on manager webapp or directly open the link [http://localhost:8080/manager/html]
  • give username “admin” and password “admin”
  • There is a option in that page called Select War File to upload, there click Browse button and give the path for your source.war file.
  • And finally click on Deploy.
  • After Deploy is complete in List of Application on the same page, you can see /source click on it. And you have just completed the installation. you can see the opengrok home page.
11. If you are getting the permission denied error then add the following code in /etc/tomcat6/policy.d/50local.policy
grant codeBase "file:${catalina.base}/webapps/opengrok/" {
     permission java.security.AllPermission;
}; grant codeBase "file:${catalina.base}/webapps/opengrok/WEB-INF/lib/"; {    permission java.security.AllPermission; };
Thanks for Vincent Liu for his wonderful post which helped me a lot.