linux的字符设备控制,Linux设备驱动之字符设备

源码

/*

* 虚拟字符设备globalmem实例:

*  在globalmem字符设备驱动中会分配一片大小为 GLOBALMEM_SIZE(4KB)

*  的内存空间,并在驱动中提供针对该片内存的读写、控制和定位函数,以供用户空间的进程能通过

*  Linux系统调用访问这片内存。

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define DEV_NAME "globalmem" /* /dev中显示的设备名 */

#define DEV_MAJOR 0 /* 指定主设备号,为0则动态获取 */

/* ioctl用的控制字 */

#define GLOBALMEM_MAGIC 'M'

#define MEM_CLEAR _IO(GLOBALMEM_MAGIC, 0)

/*--------------------------------------------------------------------- local vars */

/*globalmem设备结构体*/

typedef struct {

struct cdev cdev; /* 字符设备cdev结构体*/

#define MEM_SIZE 0x1000 /*全局内存最大4K字节*/

unsigned char mem[MEM_SIZE]; /*全局内存*/

struct semaphore sem; /*并发控制用的信号量*/

} globalmem_dev_t;

static int globalmem_major = DEV_MAJOR;

static globalmem_dev_t *globalmem_devp; /*设备结构体指针*/

/*--------------------------------------------------------------------- file operations */

/*文件打开函数*/

static int globalmem_open(struct inode *inodep, struct file *filep)

{

/* 获取dev指针 */

globalmem_dev_t *dev = container_of(inodep->i_cdev, globalmem_dev_t, cdev);

filep->private_data = dev;

return 0;

}

/*文件释放函数*/

static int globalmem_release(struct inode *inodep, struct file *filep)

{

return 0;

}

/*读函数*/

static ssize_t globalmem_read(struct file *filep, char __user *buf, size_t len, loff_t *ppos)

{

globalmem_dev_t *dev = filep->private_data;

unsigned long p = *ppos;

int ret = 0;

/*分析和获取有效的长度*/

if (p > MEM_SIZE) {

printk(KERN_EMERG "%s: overflow!\n", __func__);

return - ENOMEM;

}

if (len > MEM_SIZE - p) {

len = MEM_SIZE - p;

}

if (down_interruptible(&dev->sem)) /* 获得信号量*/

return  - ERESTARTSYS;

/*内核空间->用户空间*/

if (copy_to_user(buf, (void*)(dev->mem + p), len)) {

ret = - EFAULT;

}else{

*ppos += len;

printk(KERN_INFO "%s: read %d bytes from %d\n", DEV_NAME, (int)len, (int)p);

ret = len;

}

up(&dev->sem); /* 释放信号量*/

return ret;

}

/*写函数*/

static ssize_t globalmem_write(struct file *filep, const char __user *buf, size_t len, loff_t *ppos)

{

globalmem_dev_t *dev = filep->private_data;

int ret = 0;

unsigned long p = *ppos;

if (p > MEM_SIZE) {

printk(KERN_EMERG "%s: overflow!\n", __func__);

return - ENOMEM;

}

if (len > MEM_SIZE - p) {

len = MEM_SIZE - p;

}

if (down_interruptible(&dev->sem)) /* 获得信号量*/

return  - ERESTARTSYS;

/*用户空间->内核空间*/

if (copy_from_user(dev->mem + p, buf, len)) {

ret =  - EFAULT;

}else{

*ppos += len;

printk(KERN_INFO "%s: written %d bytes from %d\n", DEV_NAME, (int)len, (int)p);

ret = len;

}

up(&dev->sem); /* 释放信号量*/

return ret;

}

/* seek文件定位函数 */

static loff_t globalmem_llseek(struct file *filep, loff_t offset, int start)

{

globalmem_dev_t *dev = filep->private_data;

int ret = 0;

if (down_interruptible(&dev->sem)) /* 获得信号量*/

return  - ERESTARTSYS;

switch (start) {

case SEEK_SET:

if (offset < 0 || offset > MEM_SIZE) {

printk(KERN_EMERG "%s: overflow!\n", __func__);

return - ENOMEM;

}

ret = filep->f_pos = offset;

break;

case SEEK_CUR:

if ((filep->f_pos + offset) < 0 || (filep->f_pos + offset) > MEM_SIZE) {

printk(KERN_EMERG "%s: overflow!\n", __func__);

return - ENOMEM;

}

ret = filep->f_pos += offset;

break;

default:

return - EINVAL;

break;

}

up(&dev->sem); /* 释放信号量*/

printk(KERN_INFO "%s: set cur to %d.\n", DEV_NAME, ret);

return ret;

}

/* ioctl设备控制函数 */

static long globalmem_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)

{

globalmem_dev_t *dev = filep->private_data;

switch (cmd) {

case MEM_CLEAR:

if (down_interruptible(&dev->sem)) /* 获得信号量*/

return  - ERESTARTSYS;

memset(dev->mem, 0, MEM_SIZE);

up(&dev->sem); /* 释放信号量*/

printk(KERN_INFO "%s: clear.\n", DEV_NAME);

break;

default:

return - EINVAL;

}

return 0;

}

/*文件操作结构体*/

static const struct file_operations globalmem_fops = {

.owner = THIS_MODULE,

.open         = globalmem_open,

.release      = globalmem_release,

.read         = globalmem_read,

.write        = globalmem_write,

.llseek       = globalmem_llseek,

.compat_ioctl = globalmem_ioctl

};

/*---------------------------------------------------------------------*/

/*初始化并注册cdev*/

static int globalmem_setup(globalmem_dev_t *dev, int minor)

{

int ret = 0;

dev_t devno = MKDEV(globalmem_major, minor);

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

dev->cdev.owner = THIS_MODULE;

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

if (ret) {

printk(KERN_NOTICE "%s: Error %d dev %d.\n", DEV_NAME, ret, minor);

}

return ret;

}

/*设备驱动模块加载函数*/

static int __init globalmem_init(void)

{

int ret = 0;

dev_t devno;

/* 申请设备号*/

if(globalmem_major){

devno = MKDEV(globalmem_major, 0);

ret = register_chrdev_region(devno, 2, DEV_NAME);

}else{ /* 动态申请设备号 */

ret = alloc_chrdev_region(&devno, 0, 2, DEV_NAME);

globalmem_major = MAJOR(devno);

}

if (ret < 0) {

return ret;

}

/* 动态申请设备结构体的内存,创建两个设备 */

globalmem_devp = kmalloc(2*sizeof(globalmem_dev_t), GFP_KERNEL);

if (!globalmem_devp) {

unregister_chrdev_region(devno, 2);

return - ENOMEM;

}

ret |= globalmem_setup(&globalmem_devp[0], 0); /* globalmem0 */

ret |= globalmem_setup(&globalmem_devp[1], 1); /* globalmem1 */

if(ret)

return ret;

init_MUTEX(&globalmem_devp[0].sem); /*初始化信号量*/

init_MUTEX(&globalmem_devp[1].sem);

printk(KERN_INFO "globalmem: up %d,%d.\n", MAJOR(devno), MINOR(devno));

return 0;

}

/*模块卸载函数*/

static void __exit globalmem_exit(void)

{

cdev_del(&globalmem_devp[0].cdev);

cdev_del(&globalmem_devp[1].cdev);

kfree(globalmem_devp);

unregister_chrdev_region(MKDEV(globalmem_major, 0), 2);

printk(KERN_INFO "globalmem: down.\n");

}

/* 定义参数 */

module_param(globalmem_major, int, S_IRUGO);

module_init(globalmem_init);

module_exit(globalmem_exit);

/* 模块描述及声明 */

MODULE_AUTHOR("Archie Xie ");

MODULE_LICENSE("Dual BSD/GPL");

MODULE_DESCRIPTION("A char device module just for demo.");

MODULE_ALIAS("cdev gmem");

MODULE_VERSION("1.0");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值