Windows XP Windows 7 Windows 2003 Windows Vista Windows教程綜合 Linux 系統教程
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟件教程
 Windows教程網 >> Linux系統教程 >> Linux系統常見問題解答 >> linux設備驅動程序的編寫

linux設備驅動程序的編寫

日期:2017/1/20 17:44:15      編輯:Linux系統常見問題解答

先介紹下我的環境,用的ubuntu發行版,kernel版本是3.8.0,《Linux設備驅動程序》一書是針對2.6.0的kernel,在這個例子中會看到一些差異。這個例子要實現的目標是,編譯裝載該module後,通過udev動態的生成設備節點star0,讀取設備節點cat /dev/star0可以打印出星號,星號的數量可以由模塊參數動態的指定。以下為源代碼:

  star.h

  #ifndef STAR_H_H_H

  #define STAR_H_H_H

  #define AUTHOR "Tao Yang"

  #define DESCRIPTION "A CHAR DEVICE DIRVERS SAMPLE USING UDEV"

  #define VERSION "0.1"

  #endif

  star.c

  //module_init module_exit

  #include

  #include

  //module_param

  #include

  //printk container_of

  #include

  //dev_t MAJOR MINOR MKDEV

  #include

  //file_operations file register/unregister_chrdev_region alloc_chrdev_region register/unregister_chrdev(old)

  #include

  //cdev cdev_init/add/del

  #include

  //copy_from_user copy_to_user

  #include

  #include

  #include "star.h"

  //define device number

  #define STAR_MAJOR 0

  #define STAR_MINOR 0

  #define STAR_DEVS 1

  #define DEVICE_NAME "star0"

  #define CLASS_NAME "star"

  static int howmany=5;

  module_param(howmany,int,S_IRUGO);

  //module info

  MODULE_AUTHOR(AUTHOR);

  MODULE_DESCRIPTION(DESCRIPTION);

  MODULE_VERSION(VERSION);

  MODULE_LICENSE("GPL");

  //device variables

  static struct class* star_class=NULL;

  static struct device* star_sysdevice=NULL;

  int star_major=STAR_MAJOR;

  int star_minor=STAR_MINOR;

  int star_nr_devs=STAR_DEVS;

  //device struct

  static struct star_dev {

  char *data;

  struct cdev cdev;

  };

  static struct star_dev star_device;

  static ssize_t star_read(struct file * filp,char * buf,size_t count,loff_t *ppos)

  {

  int i;

  char star_str[10000];

  struct star_dev *dev=filp->private_data;

  for (i=0;i

  star_str[i]='*';

  }

  star_str[howmany]='\n';

  int len=strlen(star_str);

  if(count

  return -EINVAL;

  if(*ppos!=0)

  return 0;

  if(copy_to_user(buf,star_str,len))

  return -EINVAL;

  *ppos=len;

  return len;

  }

  int star_open(struct inode *inode,struct file *filp)

  {

  struct star_dev *dev;

  dev=container_of(inode->i_cdev,struct star_dev,cdev);

  filp->private_data=dev;

  //......

  return 0;

  }

  //file operations

  static const struct file_operations star_fops = {

  .owner = THIS_MODULE,

  .read = star_read,

  .open = star_open,

  };

  static void star_setup_cdev(struct star_dev *dev,int index)

  {

  int err,devno=MKDEV(star_major,star_minor+index);

  printk(KERN_ALERT "setup cdev...\n");

  cdev_init(&dev->cdev,&star_fops);

  dev->cdev.owner=THIS_MODULE;

  dev->cdev.ops=&star_fops;

  err=cdev_add(&dev->cdev,devno,1);

  if(err)

  printk(KERN_ALERT "Error %d adding star%d",err,index);

  }

  static int __init star_init(void)

  {

  int ret;

  dev_t dev;


 printk(KERN_ALERT "hello tom!\n");

  if(star_major){

  dev=MKDEV(star_major,star_minor);

  ret=register_chrdev_region(dev,star_nr_devs,DEVICE_NAME);

  printk(KERN_ALERT "static!\n");

  }else{

  ret=alloc_chrdev_region(&dev,star_minor,star_nr_devs,DEVICE_NAME);

  star_major=MAJOR(dev);

  printk(KERN_ALERT "dynamic!\n");

  printk(KERN_ALERT "Device Major is %d!\n",star_major);

  }

  if(ret<0){

  printk(KERN_ALERT "star:can't get major %d\n",star_major);

  return ret;

  }

  printk(KERN_ALERT "set up cdev!");

  star_setup_cdev(&star_device,0);

  star_class=class_create(THIS_MODULE,CLASS_NAME);

  if(IS_ERR(star_class)){

  printk(KERN_ALERT "failed to register device class '%s'\n",CLASS_NAME);

  }

  //with a class ,the easiest way to instantiate a device is to call device_create()

  star_sysdevice=device_create(star_class,NULL,MKDEV(star_major,0),NULL,DEVICE_NAME);

  return 0;

  }

  static void __exit star_exit(void)

  {

  device_destroy(star_class,MKDEV(star_major,star_minor));

  class_unregister(star_class);

  class_destroy(star_class);

  cdev_del(&star_device.cdev);

  printk(KERN_ALERT "goodbye...\n");

  }

  module_init(star_init);

  module_exit(star_exit);

  Makefile

  ifneq ($(KERNELRELEASE),)

  obj-m:=star.o

  else

  KERNELDIR ?= /lib/modules/$(shell uname -r)/build

  PWD :=$(shell pwd)

  default:

  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

  endif

  編譯源代碼:

  root@ubuntu:~/embedded_linux/ldd3/practice# make

  make -C /lib/modules/3.8.0-29-generic/build M=/home/tom/embedded_linux/ldd3/practice modules

  make[1]: Entering directory `/usr/src/linux-headers-3.8.0-29-generic'

  CC [M] /home/tom/embedded_linux/ldd3/practice/star.o

  /home/tom/embedded_linux/ldd3/practice/star.c:58:1: warning: useless storage class specifier in empty declaration [enabled by default]

  /home/tom/embedded_linux/ldd3/practice/star.c: In function ‘star_read’:

  /home/tom/embedded_linux/ldd3/practice/star.c:72:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]

  /home/tom/embedded_linux/ldd3/practice/star.c:66:22: warning: unused variable ‘dev’ [-Wunused-variable]

  /home/tom/embedded_linux/ldd3/practice/star.c:81:1: warning: the frame size of 10032 bytes is larger than 1024 bytes [-Wframe-larger-than=]

  Building modules, stage 2.

  MODPOST 1 modules

  CC /home/tom/embedded_linux/ldd3/practice/star.mod.o

  LD [M] /home/tom/embedded_linux/ldd3/practice/star.ko

  make[1]: Leaving directory `/usr/src/linux-headers-3.8.0-29-generic'

  root@ubuntu:~/embedded_linux/ldd3/practice#

  安裝驅動模塊:

  root@ubuntu:~/embedded_linux/ldd3/practice# insmod star.ko

  root@ubuntu:~/embedded_linux/ldd3/practice# dmesg -c

  [ 3946.696548] hello tom!

  [ 3946.699892] dynamic!

  [ 3946.699894] Device Major is 249!

  [ 3946.699895] set up cdev!

Copyright © Windows教程網 All Rights Reserved