zoukankan      html  css  js  c++  java
  • Linux 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 ");
    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 ");
    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 ");
    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 ",major_number);
    printk(KERN_INFO " use "mknod /dev/%s c %d 0" for device file ",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 ");

    }


    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
    ",DEVICE);
        exit(-1);
      }
      printf("r=read from device 
    w=write to device
     enter command: ");
      scanf("%c",&ch);
    
      switch(ch)
      {
        case 'w':
          printf("enter data: ");
          scanf(" %[^
    ]",write_buf);
          write(fd,write_buf, sizeof(write_buf));
          break;
        case 'r':
          read(fd,read_buf,sizeof(read_buf));
          printf("device: %s
    ", read_buf);
          break;
        default:
          printf("command not recognized
    ");
          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
    新博客地址:www.ybliu.com
  • 相关阅读:
    星空Password
    股票交易
    【1】博客目录
    事务
    C#基础索引
    C# String
    MSIL
    Evaluation Stack
    Spring源码编译以及导入Intellij IDEA的操作步骤
    WebFlux响应式编程简单示例
  • 原文地址:https://www.cnblogs.com/yubao/p/8541954.html
Copyright © 2011-2022 走看看