linux 字符设备控制

http://wenku.baidu.com/link?url=iaPDU86tk8Opw-wzPU9J65A2fW_VjWYlG30-PhVJW_w43uxWe29rDWsas2EA6ayqQIDby4C1B55ys5VSb6xFYK-PBoAVLht7oqs0gKCAQNu


1. 介绍

Linux2.6内核以前注册字符设备的函数接口是register_chrdev(),在2.6中其可继续使用。

register_chrdev大致作用:向内核注册cdev结构体,当在用户空间打开设备文件时内核可以根据设备号快速定位此设备文件的cdev->file_operations结构体,从而调用驱动底层的openclosereadwriteioctl等函数,当我们在用户空间open字符设备文件时,首先调用def_chr_fops->chrdev_open()函数(所有字符设备都调用此函数)chrdev_open会调用kobj_lookup函数找到设备的cdev->kobject,从而得到设备的cdev,进而获得file_operations。要想通过kobj_lookup找到相应的cdev,必需调用register_chrdev()函数。向内核注册。


globalmem设备是我们构造的一个虚拟设备,globalmem意味着“全局内存”,在globalmem字符设备驱动中会分配一片大小为GLOBALMEM_SIZE4KB)的内存空间,并在驱动中提供针对该片内存的读写、控制和定位函数,以供用户空间的进程能通过Linux系统调用访问这片内存。


2. kernel 代码

globalmem.c:

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/device.h>

#define GLOBALMEM_SIZE	0x1000	/*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define GLOBALMEM_MAJOR 150    /*预设的globalmem的主设备号*/

static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
struct globalmem_dev
{
  struct cdev cdev; /*cdev结构体*/
  unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
};

struct globalmem_dev *globalmem_devp; /*设备结构体指针*/

int globalmem_open(struct inode *inode, struct file *filp)
{
  filp->private_data = globalmem_devp;

      printk("globalmem open\n");
  return 0;
}
int globalmem_release(struct inode *inode, struct file *filp)
{
      printk("globalmem release\n");
  return 0;
}
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
{
  struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
  switch (cmd)
  {
    case MEM_CLEAR:
      printk("globalmem ioctl clear\n");
      memset(dev->mem, 0, GLOBALMEM_SIZE);
      //printk(KERN_INFO "globalmem is set to zero\n");
      break;

    default:
      return  - EINVAL;
  }
  return 0;
}

static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/

      printk("globalmem read\n");
  /*分析和获取有效的写长度*/
  if (p >= GLOBALMEM_SIZE)
 return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;


  /*内核空间->用户空间*/
  if (copy_to_user(buf, (void*)(dev->mem + p), count))
  {
    ret =  - EFAULT;
  }
  else
  {
    *ppos += count;
    ret = count;
    
    printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  }

  return ret;
}

static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  
      printk("globalmem write\n");
  /*分析和获取有效的写长度*/
  if (p >= GLOBALMEM_SIZE)
    return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;
    
  /*用户空间->内核空间*/
  if (copy_from_user(dev->mem + p, buf, count))
    ret = - EFAULT;
  else
  {
    *ppos += count;
    ret = count;
    printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  }
 return ret;
}

static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
  loff_t ret = 0;

      printk("globalmem llseek orig:%d\n",orig);
  switch (orig)
  {
    case 0:   /*相对文件开始位置偏移*/
      if (offset < 0)
      {
        ret =  - EINVAL;
        break;
      }
      if ((unsigned int)offset > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos = (unsigned int)offset;
      ret = filp->f_pos;
      break;
    case 1:   /*相对文件当前位置偏移*/
      if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      if ((filp->f_pos + offset) < 0)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos += offset;
      ret = filp->f_pos;
      break;
    default:
      ret =  - EINVAL;
      break;
  }
  return ret;
}
static const struct file_operations globalmem_fops =
{
  .owner = THIS_MODULE,
  .llseek = globalmem_llseek,
  .read = globalmem_read,
  .write = globalmem_write,
  .ioctl = globalmem_ioctl,
  .open = globalmem_open,
  .release = globalmem_release,
};
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
  int err, devno = MKDEV(globalmem_major, index);

  cdev_init(&dev->cdev, &globalmem_fops);
  dev->cdev.owner = THIS_MODULE;
  dev->cdev.ops = &globalmem_fops;
  err = cdev_add(&dev->cdev, devno, 1);
  if (err)
    printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

struct class *my_class;

int globalmem_init(void)
{
  int result;
  dev_t devno = MKDEV(globalmem_major, 0);

      printk("globalmem init\n");
  /* 申请设备号*/
  if (globalmem_major)
    result = register_chrdev_region(devno, 1, "globalmem");
  else  /* 动态申请设备号 */
  {
    result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
    globalmem_major = MAJOR(devno);
  }  
  if (result < 0)
    return result;
    
  /* 动态申请设备结构体的内存*/
  globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
  if (!globalmem_devp)    /*申请失败*/
  {
    result =  - ENOMEM;
    goto fail_malloc;
}
  memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
  globalmem_setup_cdev(globalmem_devp, 0);

//luke add st
my_class = class_create(THIS_MODULE,"my_class");
if(IS_ERR(my_class))
{
printk("error:fail in creating class\n");
return -1;
}
device_create(my_class,NULL,MKDEV(150,0),NULL,"globalmem");
//ed

  return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
  return result;
}

void globalmem_exit(void)
{
      printk("globalmem exit\n");
  cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
  kfree(globalmem_devp);     /*释放设备结构体内存*/

  //luke add
  device_destroy(my_class,MKDEV(150,0));
  class_destroy(my_class);
  //ed
  unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
}
MODULE_AUTHOR("Song Baohua");
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);

Makefile:

  1 ifneq ($(KERNELRELEASE),)
  2 obj-m := globalmem.o
  3 else
  4         KERNELDIR = /usr/src/linux-headers-2.6.32-45-generic/
  5         PWD := $(shell pwd)
  6 default:
  7         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
  8 clean:
  9         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c 
 10 endif

3. 查看信息

运行insmodglobalmem.ko命令加载模块,通过lsmod命令,发现globalmem模块已被加载。再通过cat/proc/devices命令查看,发现多出了主设备号为150myglobalmem字符设备驱动,如下所示: 


4. 验证

4.1 编写应用程序test.c用于测试

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
main()
{
	char str[1024], str2[1024];
	int fd, stop;
	int ret;
	fd = open("/dev/globalmem", O_RDWR, S_IRUSR | S_IWUSR);
	if (fd != -1 )
	{
		printf("Please input the string written to globalmem\n");
		scanf("%s", str);
		printf("The str is %s\n", str);
		ioctl(fd, 1, NULL);
		ret = write(fd, str, strlen(str));
		printf("The ret is %d\n", ret);
		lseek(fd, 0, SEEK_SET);
scanf("%d", &stop);
		read(fd, str2, 100);
		printf("The globalmem is %s\n", str2);
		close(fd);
	}
	else
	{
		printf("Device open failure\n");
	}
}
编译:

gcc-o test test.c


运行:

$sudo ./test

Pleaseinput the string written to globalmem

qwertyuiop

Thestr is qwertyuiop

Theret is 10

0

Theglobalmem is qwertyuiop

可以发现"globalmem"设备可以正确的读写。


4.2 echo cat 验证

root@luke-desktop:/home/luke/globaltest# echo "hello world22" > /dev/globalmem

root@luke-desktop:/home/luke/globaltest# cat /dev/globalmem

hello world22

如果启动了sys文件系统,将发现多出/sys/module/globalmem目录


ps:

 本例中kernel通过device_create(...)自动创建了节点,也可以手动创建

sudo mknod /dev/globalmem c 150 0



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
linuxdriver_code_tool .....................\03 .....................\..\2.6内核升级工具 .....................\..\...............\device-mapper-1.00.19-2.i386.rpm .....................\..\...............\lvm2-2.00.25-1.01.i386.rpm .....................\..\...............\mkinitrd-4.2.0.3.tar.tar .....................\..\...............\module-init-tools-3.2.2.tar.bz2 .....................\..\...............\modutils-2.4.5-1.src.rpm .....................\04 .....................\..\内核模块参数范例 .....................\..\................\book.c .....................\..\内核模块导出符号 .....................\..\................\export_symb.c .....................\..\最简单的内核模块 .....................\..\................\hello.c .....................\05 .....................\..\udev源代码 .....................\..\..........\udev-114.tar.gz .....................\06 .....................\..\globalmem驱动 .....................\..\.............\globalmem.c .....................\..\linux内核container_of宏_Linux技术文章_Linux_操作系统.mht .....................\..\【转】container_of函数简介 - 嵌入式linux - 斯是陋室,惟吾德馨.htm .....................\..\【转】container_of函数简介 - 嵌入式linux - 斯是陋室,惟吾德馨_files .....................\..\..................................................................\bg_art_bottom.gif .....................\..\..................................................................\bg_art_left.gif .....................\..\..................................................................\bg_art_left_bottom.gif .....................\..\..................................................................\bg_art_left_top.gif .....................\..\..................................................................\bg_art_right.gif .....................\..\..................................................................\bg_art_right_bottom.gif .....................\..\..................................................................\bg_art_right_top.gif .....................\..\..................................................................\bg_art_top.gif .....................\..\..................................................................\bg_menu.gif .....................\..\..................................................................\comment.htm .....................\..\..................................................................\comment_files .....................\..\..................................................................\.............\base.css .....................\..\..................................................................\.............\index.css .....................\..\..................................................................\.............\num.png .....................\..\..................................................................\img_menu_left.gif .....................\..\..................................................................\index.css .....................\..\..................................................................\tophem1.gif .....................\..\..................................................................\userstar.gif .....................\..\包含2个globalmem设备的驱动 .....................\..\..........................\globalmem_two.c .....................\07 .....................\..\含并发控制的globalmem驱动 .....................\..\.........................\globalmem_lock.c .....................\08 .....................\..\globalfifo驱动 .....................\..\..............\globalfifo.c .....................\..\poll应用程序范例 .....................\..\................\pollmonitor.c .....................\09 .....................\..\异步通知应用程序范例 .....................\..\....................\asyncmonitor.c .....................\..\支持异步通知的globalfifo .....................\..\........................\globalfifo_async.c .....................\10 .....................\..\S3C2410实时钟驱动 .....................\..\.................\s3c2410-rtc.c .....................\..\秒设备驱动与应用程序 .....................\..\....................\second.c .....................\..\....................\second_test.c .....................\11 .....................\..\DMA范例 .....................\..\.......\3c505.c .....................\..\.......\3c505.h .....................\..\.......\dma.h .....................\..\静态映射范例 .....................\..\............\mach-smdk2440.c .....................\12 .....................\..\NVRAM驱动 .....................\..\.........\generic_nvram.c .....................\..\平台设备 .....................\..\........\devs.c .....................\..\看门狗驱动 .....................\..\..........\s3c2410_wdt.c .....................\..\触摸屏驱动 .....................\..\..........\作为input设备 .....................\..\..........\.............\s3c2410_ts.c .....................\..\..........\.............\s3c2410_ts.h .....................\..\..........\作为普通字符设备 .....................\..\..........\................\s3c2410-ts.c .....................\13 .....................\..\IDE驱动 .....................\..\.......\ide-disk.c .....................\..\.......\ide-h8300.c .....................\..\RAMDISK驱动 .....................\..\...........\rd.c .....................\14 .....................\..\S3C2410串口驱动 .....................\..\...............\regs-gpio.h .....................\..\...............\regs-serial.h .....................\..\...............\s3c2410.c .....................\..\串口核心层 .....................\..\..........\serial_core.c .....................\..\..........\serial_core.h .....................\15 .....................\..\S3C2410 I2C主机驱动

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值