基础 字符设备驱动框架

ARM 57浏览

 

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

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#include "hello.h"

MODULE_LICENSE("GPL");

int hello_major = 250;
int hello_minor = 0;

int  number_of_devices = 2;

struct hello_device{
 char data[128];
 struct cdev cdev;
}hello_devices[2];

#define to_hello_t(d) container_of(d, struct hello_device, cdev)

dev_t devno;

static int hello_open(struct inode *inode, struct file *file)
{
 printk(KERN_INFO"Hey! device openedn");
 struct hello_device *hello = to_hello_t(inode->i_cdev);
 file->private_data = hello;

 printk("hello address %pn", hello);

 return 0;
}

static int hello_release(struct inode *inode, struct file *file)
{
 printk(KERN_INFO"Hmmm! device closed n");
 return 0;
}

ssize_t hello_read(struct file *file, char *buff, size_t count, loff_t *offp)
{
 char str_buf[100] = "";

 printk(KERN_INFO"hello read address  %pn", file->private_data);
 sprintf(str_buf, "hello read %p", file->private_data);
 
 copy_to_user(buff, str_buf, strlen(str_buf));

 return strlen(str_buf); /*return 0 errno*/
}

ssize_t hello_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
 ssize_t ret = 0;
 char data[100] = "";
#if __dump_stack__
 printk("dump_stack startn");
 dump_stack();
 printk("dump_stack end n");
#endif
 if(count > 127) return -ENOMEM;
 if(copy_from_user(data, buf, count))
 {
  ret = -EFAULT;
 }
 else
 {
  data[count] = '';
  printk(KERN_INFO"Received: %sn", data);
  ret = count;
 }
 return ret;
}

long hello_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
 int ret = 0;
 switch(cmd)
 {
 case HELLO_ONE:
  printk(KERN_INFO"HELLO_ONE calledn");
  break;
 case HELLO_TWO:
  if(!capable(CAP_SYS_ADMIN))
   return -EPERM;
  printk(KERN_INFO"HELLO_TWO calledn");
  break;
 case HELLO_TRE:
  {
   node_t tmp;
   copy_from_user(&tmp, (void*)arg, sizeof(tmp));
   printk(KERN_INFO"node_t.a %d node_t.b %d n", tmp.a, tmp.b);
   break;
  }
 default:
  printk(KERN_INFO"CMD is invaluden");
  return -EINVAL;
 }
 return ret;
}

struct file_operations hello_fops = {
 .owner = THIS_MODULE,
 .open = hello_open,
 .release = hello_release,
 .read = hello_read,
 .write = hello_write,
 .unlocked_ioctl = hello_ioctl
};

static void char_reg_setup_cdev(dev_t devno)
{
 int error;

 cdev_init(&hello_devices[0].cdev, &hello_fops);
 hello_devices[0].cdev.owner = THIS_MODULE;
 cdev_init(&hello_devices[1].cdev, &hello_fops);
 hello_devices[1].cdev.owner = THIS_MODULE;

 error = cdev_add(&hello_devices[0].cdev, devno, 1);
 if(error)
  printk(KERN_NOTICE"Error %d adding char_reg_setup_cdev", error);
 error = cdev_add(&hello_devices[1].cdev, devno+1, 1);
 if(error){
  printk(KERN_NOTICE"Error %d adding char_reg_setup_cdev", error);
  cdev_del(&hello_devices[0].cdev);
 }
 
}

static int __init hello_2_init(void) /*__init 在模块中失去意义*/
{
 int result;
 
 devno = MKDEV(hello_major, hello_minor);

 result = register_chrdev_region(devno, number_of_devices, "hello_device");
 if(result < 0 )
 {
  printk(KERN_WARNING"Registered character drivern");
  return result;
 }
 char_reg_setup_cdev(devno);

 printk(KERN_INFO"Registered character drivern");
 printk(KERN_INFO"hello address %p hello address  %p n", &hello_devices[0], &hello_devices[1]);
 return 0;
}
static void __exit hello_2_exit(void) /*__exit 在模块中失去意义*/
{
 cdev_del(&hello_devices[0].cdev); 
 cdev_del(&hello_devices[1].cdev); 

 unregister_chrdev_region(devno, number_of_devices);
 printk(KERN_INFO"Char driver cleaned upn");
}

module_init(hello_2_init);
module_exit(hello_2_exit);