Linux Driver 入门 - Character Device Driver 字符设备驱动

 

Character Device Driver Sample Code

#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/fs.h> //file operations. which of course allows use open/close, read/write to device
#include <linux/cdev.h> //this is a char driver; makes cdev available
#include <linux/semaphore.h> //synchronization behaviors

#include <linux/uaccess.h> //copy_to_user; copy_from_user

//(1) Create a structure for our fake device
struct fake_device{
char data[100];
struct semaphore sem;
} virtual_device;

//(2) To later register our device we need a cdev object and some other varibles
struct cdev *mcdev; //m stands for "my"
int major_number;
int ret; // Will be used to hold return values of functions; this is because the kernel stack is very small. So declaring variables all over the pass in our module functions eats up the stack very fast

dev_t dev_num; //will hold major number that kernel gives us

#define DEVICE_NAME "Mycharacterdevice"

//(7) Called on device_file open
// inode reference to the file on disk
// and contains information about that file
// struct file is represents an abstract open file
int device_open(struct inode *inode, struct file *flip)
{
//only allow one process to open this device by using a semaphore as mutual exclusive lock - muttex
if(down_interruptible(&virtual_device.sem)!=0)
{
printk(KERN_ALERT "Mycharacterdevice: could not lock device during open\n");
return -1;
}

printk(KERN_INFO "Mycharacterdevice: opened device");
return 0;
}

//(8) called when user wants to get information from the device
ssize_t device_read(struct file* filp, char* buffStoreData, size_t bufCount, loff_t* curOffset)
{
//take data from kernel space(device) to user space (process)
//copy_to_user (destination,source, sizeToTransfer)
printk(KERN_INFO "Mycharacterdevice: Reading from device");
ret=copy_to_user(buffStoreData, virtual_device.data, bufCount);
return ret;
}

//(9) called when user wants to send information to the device
ssize_t device_write(struct file* filp, const char* bufSourceData, size_t bufCount, loff_t* curOffset)
{
//send data from user to kernel
//copy_from_user(dest, source, count)
printk(KERN_INFO "Mycharacterdevice: writing to device\n");
ret=copy_from_user(virtual_device.data,bufSourceData, bufCount);
return ret;
}

//(10) called when close
int device_close(struct inode *inode, struct file *filp)
{
//by calling up which is opposite of down for semaphore, we release the mutes that we obtained at device open, this has the effect of allowing other process to use the device now
up(&virtual_device.sem);
printk(KERN_INFO "mycharacterdevice: closed device\n");
return 0;
}


//(6) Tell the kernel which functions to call when user operates on our device file
struct file_operations fops={
.owner=THIS_MODULE, //prevent unloading of this module when operations are in use
.open=device_open, //Points to the method to call when opening the device
.release=device_close,
.write=device_write,
.read=device_read
};

static int driver_entry(void)
{
//(3) Register our device with the system: a two step process
//Step(1) use dynamic allocation to assign our device
// a major number -- alloc_chrdev_region(dev_t*,unit fminor, uint count,char* name)
ret=alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);
if(ret<0){
printk(KERN_ALERT "MyCharacterdevice: failed to allocate a major number");
return ret; //propagate error
}
major_number=MAJOR(dev_num);
printk(KERN_INFO "mycharacterdevice: major_number is %d \n",major_number);
printk(KERN_INFO "\tuse \"mknod /dev/%s c %d 0\" for device file \n",DEVICE_NAME, major_number);
//Step(2)
mcdev=cdev_alloc(); //create our cdev structure, initialized our cdev
mcdev->ops=&fops;
mcdev->owner=THIS_MODULE;

//now that we created cdev, we have to add it to the kernel
ret=cdev_add(mcdev,dev_num,1);
if(ret<0)
{
printk(KERN_ALERT "Mycharacterdevice: unable to add cdev to kernel");
}

//(4) Initialize our semaphore
sema_init(&virtual_device.sem,1); //initialize value of one

return 0;
}

static void driver_exit(void)
{
//(5) unregister everything in reverse order
//(a)
cdev_del(mcdev);
//(b)
unregister_chrdev_region(dev_num,1);
printk(KERN_ALERT "Mycharacterdevice: unloaded module\n");

}


module_init(driver_entry);
module_exit(driver_exit);

 

   makefile

obj-m :=MyCharacterDevice.o

KERNEL_DIR=/usr/src/linux-headers-$(shell uname -r)

all:
    $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules

clean:
    rm -rf *.o *.ko *.mod.* *.symvers *.order *~

 

 

 

insmod character device driver

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ sudo insmod MyCharac terDevice.ko

 

dmesg

[12479.254529] mycharacterdevice: major_number is 239
[12479.254546]  use "mknod /dev/Mycharacterdevice c 239 0" for device file

 

create device node

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ sudo mknod /dev/Mych aracterdevice c 239 0
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ls /dev |grep "device"
Mycharacterdevice

 

 

Application Code

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define DEVICE "/dev/Mycharacterdevice"
int main()
{
  int i,fd;
  char ch, write_buf[100],read_buf[100];

  fd=open(DEVICE, O_RDWR);
  if(fd==-1)
  {
    printf("file %s either does not exist or has been locked by another process\n",DEVICE);
    exit(-1);
  }
  printf("r=read from device \nw=write to device\n enter command: ");
  scanf("%c",&ch);

  switch(ch)
  {
    case 'w':
      printf("enter data: ");
      scanf(" %[^\n]",write_buf);
      write(fd,write_buf, sizeof(write_buf));
      break;
    case 'r':
      read(fd,read_buf,sizeof(read_buf));
      printf("device: %s\n", read_buf);
      break;
    default:
      printf("command not recognized\n");
      break;
  }

  close(fd);
  return 0;
}

 

 

compile

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ gcc -o userapp userA pp.c
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ls
Makefile       Module.symvers       MyCharacterDevice.ko     MyCharacterDevice.mod.o  userapp
modules.order  MyCharacterDevice.c  MyCharacterDevice.mod.c  MyCharacterDevice.o      userApp.c yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ./userapp
file /dev/Mycharacterdevice either does not exist or has been locked by another process

 

Change access privilege

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ls -l /dev/Mycharact erdevice
crw-r--r-- 1 root root 239, 0 Mar 10 17:58 /dev/Mycharacterdevice
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ sudo chmod 757 /dev/ Mycharacterdevice

 

Run

Write device

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ./userapp
r=read from device
 w=write to device
 enter command: w
enter data Linux Driver Example

 

Read device

yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/CharacterDeviceDriver$ ./userapp
r=read from device
 w=write to device
 enter command: r
device: Linux Driver Example

 

posted on 2018-03-10 20:54  LiuYubao  阅读(1109)  评论(0编辑  收藏  举报

导航