יום שני, 17 ביוני 2013

device with simple ioctl

The char driver code

  1: #include <linux/kernel.h>  /* We're doing kernel work */
  2: #include <linux/module.h>  /* Specifically, a module */
  3: #include <linux/fs.h>
  4: #include <asm/uaccess.h>  /* for get_user and put_user */
  5: #include  <linux/slab.h>
  6: 
  7: #include "chardev.h"
  8: #define SUCCESS 0
  9: #define DEVICE_NAME "char_dev"
 10: #define BUF_LEN 80
 11: #define DEBUG  
 12: /* 
 13:  * Is the device open right now? Used to prevent
 14:  * concurent access into the same device 
 15:  */
 16:  int Device_Open = 0;
 17: 
 18: static int device_open(struct inode *inode, struct file *file)
 19: {
 20:   printk(KERN_INFO "device_open(%p)\n", file);
 21: 
 22:   /* 
 23:    * currenlty void more then on client at a time 
 24:    */
 25:   if (Device_Open)
 26:   {
 27:     return -EBUSY;
 28:    }
 29:   Device_Open++;
 30:   /*
 31:    * Initialize the message 
 32:    */
 33:   
 34:   try_module_get(THIS_MODULE);
 35:   return SUCCESS;
 36: }
 37: 
 38: static int device_release(struct inode *inode, struct file *file)
 39: {
 40: #ifdef DEBUG
 41:   printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
 42: #endif
 43: 
 44:   /* 
 45:    * We're now ready for our next caller 
 46:    */
 47:   Device_Open--;
 48: 
 49:   module_put(THIS_MODULE);
 50:   
 51:   return SUCCESS;
 52: }
 53: 
 54: static void HandleCountFor (void * userData )
 55: {
 56:   int mFrom ;
 57:   
 58:   int mTo;
 59:   
 60:   int mStep;
 61:   
 62:   int * theKernelSpaceData ;
 63:   
 64:   printk(KERN_ALERT "Enter HandleCountFor 1\n");
 65:   
 66:   theKernelSpaceData = kmalloc(sizeof(int) * 3, GFP_KERNEL);
 67:   
 68:   copy_from_user(theKernelSpaceData, (void *)userData, sizeof(int) * 3);
 69: 
 70:     mFrom = theKernelSpaceData[0];
 71:   
 72:   mTo = theKernelSpaceData[1];
 73:   
 74:   mStep = theKernelSpaceData[2];
 75:     
 76:   printk(KERN_ALERT "Countr From %d mTo %d mStep %d \n" , mFrom, mTo, mStep);
 77: 
 78:   kfree(theKernelSpaceData);
 79:  
 80: } 
 81: 
 82: 
 83: int device_ioctl(
 84:      struct file *file,  /* ditto */
 85:      unsigned int ioctl_num,  /* number and param for ioctl */
 86:      unsigned long ioctl_param)
 87: {
 88:   /* 
 89:    * Switch according to the ioctl called 
 90:    */
 91:   switch (ioctl_num) {
 92:   case IOCTL_SET_COUNTFOR_VARIABLES:
 93:     
 94:     HandleCountFor (ioctl_param);
 95: 
 96:     break;
 97:   
 98:   }
 99: 
100:   return SUCCESS;
101: }
102: 
103: /* Module Declarations */
104: 
105: /* 
106:  * This structure will hold the functions to be called
107:  * when a process does something to the device we
108:  * created. Since a pointer to this structure is kept in
109:  * the devices table, it can't be local to
110:  * init_module. NULL is for unimplemented functions. 
111:  */
112: struct file_operations Fops = {  
113:   .unlocked_ioctl = device_ioctl,
114:   .open = device_open,
115:   .release = device_release,  /* a.k.a. close */
116: };
117: 
118: /* 
119:  * Initialize the module - Register the character device 
120:  */
121: int init_module()
122: {
123:   int ret_val;
124:   /* 
125:    * Register the character device (atleast try) 
126:    */
127:   ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
128: 
129:   /* 
130:    * Negative values signify an error 
131:    */
132:   if (ret_val < 0) {
133:     printk(KERN_ALERT "%s failed with %d\n",
134:            "Sorry, registering the character device ", ret_val);
135:     return ret_val;
136:   }
137: 
138:   printk(KERN_INFO "%s The major device number is %d.\n",
139:          "Registeration is a success", MAJOR_NUM);
140:   printk(KERN_INFO "If you want to talk to the device driver,\n");
141:   printk(KERN_INFO "you'll have to create a device file. \n");
142:   printk(KERN_INFO "We suggest you use:\n");
143:   printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
144:   printk(KERN_INFO "The device file name is important, because\n");
145:   printk(KERN_INFO "the ioctl program assumes that's the\n");
146:   printk(KERN_INFO "file you'll use.\n");
147: 
148:   return 0;
149: }
150: 
151: /* 
152:  * Cleanup - unregister the appropriate file from /proc 
153:  */
154: void cleanup_module()
155: { 
156:   unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
157: }

The header file


  1: #include <linux/ioctl.h>
  2: 
  3: /* 
  4:  * The major device number. We can't rely on dynamic 
  5:  * registration any more, because ioctls need to know 
  6:  * it. 
  7:  */
  8: #define MAJOR_NUM 100
  9: 
 10: #define IOCTL_SET_COUNTFOR_VARIABLES _IOWR(MAJOR_NUM, 3, int * )
 11: 
 12: /* 
 13:  * The name of the device file 
 14:  */
 15: #define DEVICE_FILE_NAME "char_dev"

The make file


  1: obj-m := chardev.o 
  2: 
  3: KDIR  := /lib/modules/$(shell uname -r)/build
  4: PWD   := $(shell pwd)
  5: 
  6: default:
  7:   $(MAKE) -C $(KDIR) M=$(PWD) modules
  8: 

The test file


  1: #include <stdio.h>
  2: #include <stdlib.h>
  3: #include <fcntl.h>    /* open */
  4: #include <unistd.h>    /* exit */
  5: #include <sys/ioctl.h>    /* ioctl */
  6: 
  7: 
  8: #include <linux/ioctl.h>
  9: 
 10: #define MAJOR_NUM 100
 11: 
 12: #define IOCTL_SET_COUNTFOR_VARIABLES _IOWR(MAJOR_NUM, 3, int * )
 13: 
 14: /*
 15:  * The name of the device file
 16:  */
 17: #define DEVICE_FILE_NAME "char_dev"
 18: 
 19: void ioctl_Send_FromToStep (int file_desc,int pFrom, int pTo, int pStep)
 20: {
 21:   int  theBuf [3];
 22: 
 23:   theBuf[0] = pFrom;
 24: 
 25:   theBuf[1] = pTo;
 26: 
 27:   theBuf[2] = pStep;
 28: 
 29:   ioctl(file_desc, IOCTL_SET_COUNTFOR_VARIABLES, theBuf);
 30: 
 31: }
 32: 
 33: void main()
 34: {
 35:   int file_desc, ret_val;
 36:   char *msg = "Message passed by ioctl\n";
 37: 
 38:   char * theDriver = "/home/zvika/myStaff/CharDrivers/chardev/char_dev3";
 39: 
 40:   printf (theDriver);
 41: 
 42:   file_desc = open(theDriver, O_RDWR);
 43:   if (file_desc < 0) {
 44:     printf("Can't open device file: %s\n", "char_dev");
 45:     exit(-1);
 46:   }
 47: 
 48:   ioctl_Send_FromToStep (file_desc ,1 , 60 , 4);
 49: 
 50:   close(file_desc);
 51: }

The helper bash file to compile and deploy the device




  1: #!/bin/bash
  2: 
  3: echo "use: sudo ./chardev.sh"
  4: 
  5: echo "Start deploying" 
  6: 
  7: # Root or die  
  8: if [ "$(id -u)" != "0" ]  
  9: then  
 10:   echo "You must be root to load or unload kernel modules"  
 11:   exit 1  
 12: fi  
 13: 
 14: make
 15: 
 16: rmmod chardev.ko
 17: 
 18: insmod chardev.ko

The Result:
Calling: dmesg


[ 6385.292794] device_open(ffff88008025b700)
[ 6385.292798] Enter HandleCountFor 1
[ 6385.292801] Countr From 1 mTo 100 mStep 2
zvika@ubuntu:~/myStaff/CharDrivers/PlayWithKernel$


Making a device file so a user mode program could access it
zvika@ubuntu:~/myStaff/CharDrivers/PlayWithKernel$ sudo mknod char_dev c 100 0Remove the device file
zvika@ubuntu:~/myStaff/CharDrivers/PlayWithKernel$ unlink char_dev
Deploy the module 
zvika@ubuntu:~/myStaff/CharDrivers/PlayWithKernel$ sudo insmod chardev.ko
Remove the deployed module
zvika@ubuntu:~/myStaff/CharDrivers/PlayWithKernel$ sudo rmmod chardev.ko


Resources:
http://www.techrepublic.com/article/loading-and-unloading-modules-in-linux/5031591
http://stackoverflow.com/questions/10713956/failed-to-open-device

http://elinux.org/Debugging_by_printing
http://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/

אין תגובות:

הוסף רשומת תגובה