Friday, June 08, 2012

Write a device driver in Linux

/* Necessary includes for device drivers http://www.freesoftwaremagazine.com/articles/drivers_linux?page=0%2C1 */

#include <linux init.h>

//#include <linux config.h> no more since 2.6.19 deprecated

#include <linux module.h>

#include <linux kernel.h> /* printk() */

#include <linux slab.h> /* kmalloc() */

#include <linux fs.h> /* everything... */

#include <linux errno.h> /* error codes */

#include <linux types.h> /* size_t */

#include <linux proc_fs.h>

#include <linux fcntl.h> /* O_ACCMODE */

#include <asm system.h> /* cli(), *_flags */

#include <asm uaccess.h> /* copy_from/to_user */



MODULE_LICENSE("Dual BSD/GPL");



/* Declaration of memory.c functions */

int memory_open(struct inode *inode, struct file *filp);

int memory_release(struct inode *inode, struct file *filp);

ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);

ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);

void memory_exit(void);

int memory_init(void);



/* Structure that declares the usual file */

/* access functions */

struct file_operations memory_fops = {

  read: memory_read,

  write: memory_write,

  open: memory_open,

  release: memory_release

};



/* Declaration of the init and exit functions */

module_init(memory_init);

module_exit(memory_exit);



/* Global variables of the driver */

/* Major number */

int memory_major = 60;

/* Buffer to store data */

char *memory_buffer;



int memory_init(void) {

  int result;



  /* Registering device */

  result = register_chrdev(memory_major, "memory", &memory_fops);

  if (result < 0) {

    printk(

      "<1>memory: cannot obtain major number %d\n", memory_major);

    return result;

  }



  /* Allocating memory for the buffer */

  memory_buffer = kmalloc(1, GFP_KERNEL); 

  if (!memory_buffer) { 

    result = -ENOMEM;

    goto fail; 

  } 

  memset(memory_buffer, 0, 1);



  printk("<1>Inserting memory module\n"); 

  return 0;



  fail: 

    memory_exit(); 

    return result;

}



void memory_exit(void) {

  /* Freeing the major number */

  unregister_chrdev(memory_major, "memory");



  /* Freeing buffer memory */

  if (memory_buffer) {

    kfree(memory_buffer);

  }



  printk("<1>Removing memory module\n");



}



int memory_open(struct inode *inode, struct file *filp) {



  /* Success */

  return 0;

}

int memory_release(struct inode *inode, struct file *filp) {



  /* Success */

  return 0;

}

ssize_t memory_read(struct file *filp, char *buf, 

                    size_t count, loff_t *f_pos) { 



  /* Transfering data to user space */ 

  copy_to_user(buf,memory_buffer,1);



  /* Changing reading position as best suits */ 

  if (*f_pos == 0) { 

    *f_pos+=1; 

    return 1; 

  } else { 

    return 0; 

  }

}

ssize_t memory_write( struct file *filp, char *buf,

                      size_t count, loff_t *f_pos) {



  char *tmp;



  tmp=buf+count-1;

  copy_from_user(memory_buffer,tmp,1);

  return 1;

}

///----Makefile
obj-m = hello.o memory.o
KVERSION = $(shell uname -r)
all:
    make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
///----Testing after make
$sudo nsmod memory.ko
$sudo rmmod memory.ko
$ dmesg | less
[223447.209899] Inserting memory module
[223629.779878] Removing memory module
[223663.099549] Loading hello module...
# mknod /dev/memory c 60 0 (make device using system call see http://www.kernel.org/doc/man-pages/online/pages/man2/mknod.2.html  In the above, c means that a char device is to be created, 60 is the major number and 0 is the minor number.)
Insert character into the device
#chmod 666 /dev/memory
#insmod memory.ko
#echo -n ABC > /dev/memory
#cat /dev/memory
C
Note: .ko kernel object,.so /usr/lib (library), .ro (module plugin gedit)
.o for object then link gcc -o test test.c

Questions:
Q. Can you explain me what is device files and how do I access or see device files? Why UNIX / Linux has device files?
A. Under Linux and UNIX each and every hardware device treated as a file. A device file allows to accesses hardware devices so that end users do not need to get technical details about hardware.
In short, a device file (also called as a special file) is an interface for a device driver that appears in a file system as if it were an ordinary file. This allows software to interact with the device driver using standard input/output system calls, which simplifies many tasks.

Device file two types

There are two types of device files based upon how data written to them and read from them is processed by the operating system and hardware:
  • Character special files or Character devices
  • Block special files or Block devices

Understanding Character special files or Character devices

  • Talks to devices in a character by character (1 byte at a time)
  • Examples: Virtual terminals, terminals and serial modems etc

Understanding Block special files or Block devices

  • Talks to devices 1 block at a time ( 1 block = 512 bytes to 32KB)
  • Examples: Hard disk, DVD/CD ROM, and memory regions etc

Why use device files?

Device file allows transparent communication between user space applications and computer hardware.

What is a Zombie process?

http://en.wikipedia.org/wiki/Zombie_process On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution but still has an entry in the process table. This entry is still needed to allow the parent process to read its child's exit status. The term zombie process derives from the common definition of zombie — an undead person. In the term's metaphor, the child process has "died" but has not yet been "reaped". Also, unlike normal processes, the kill command has no effect on a zombie process.

How do I kill zombie process?

You cannot kill zombies, as they are already dead. But if you have too many zombies then kill parent process or restart service.
You can kill zombie process using PID obtained from any one of the above command. For example kill zombie process having PID 4104:
# kill -9 4104
create zombie.c

#include <stdlib.h&g

#include <sys types.h&g

#include <unistd.h&g



int main ()

{

pid_t child_pid;



child_pid = fork (); // system call to create a new process referred to as the child process

if (child_pid > 0) {

sleep (60);

}

else {

exit (0);                  // parent exist make child becomes zombie if the parent crashes makes it becomes

}                             // orphan process will waste resources but zombie is no harm except running out PID

return 0;

}

gcc zombie.c -o zombie
./zombie
after 1 minute
ps -ax
  1815 ?        Sl     0:00 /usr/bin/python /usr/bin/bzr-notify
 6314 pts/1    S+     0:00 ./zombie
 6315 pts/1    Z+     0:00 [zombie]
The child process is marked as , and its status code is Z, for zombie.
When the program exits, the child process is inherited by init. This process should cleans up the zombie proces automatically.

Zombie vs. Orphan process

http://en.wikipedia.org/wiki/Zombie_process
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution but still has an entry in the process table. This entry is still needed to allow the parent process to read its child's exit status. The term zombie process derives from the common definition of zombie — an undead person. In the term's metaphor, the child process has "died" but has not yet been "reaped". Also, unlike normal processes, the kill command has no effect on a zombie process.
A zombie process is not the same as an orphan process. An orphan process is a process that is still executing, but whose parent has died. They do not become zombie processes; instead, they are adopted by init (process ID 1), which waits on its children.

No comments: