insmod命令加载字符设备驱动成功后,在/proc/devices文件内却并没有该驱动名字和主设备号信息

gongmin856 2013-05-05 08:06:10
insmod命令加载globalfifo字符设备驱动成功后,我从globalfifo_init函数打出的调试信息显示,系统分配给该设备的主设备号为253,次设备号为0,但在/proc/devices文件内却并没有该设备名字和主设备号信息.

以下是该设备驱动代码,请大家帮帮忙,看看是怎么回事啊?提前谢谢了!

#include<linux/cdev.h>
#include<linux/fs.h>
#include <linux/module.h>
#include<linux/sched.h>
#include<asm/uaccess.h>
#include<linux/slab.h>

#define GLOBALFIFO_SIZE (0x1000) /*全家内存最大值4KB*/
#define MEM_CLEAR (0x1) /*清零全局内存*/
#define GLOBALFIFO_MAJOR (0) /*预设的GloabalMem的主设备号*/

static int globalfifo_major = GLOBALFIFO_MAJOR;

/*global_mem设备结构体*/
struct globalfifo_dev{
struct cdev cdev; /*cdev结构体*/
unsigned int current_len;/*fifo有效数据长度*/
unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/
struct semaphore sem;/*并发控制用的信号量*/
wait_queue_head_t r_wait;/*阻塞读用的等待队列头*/
wait_queue_head_t w_wait;/*阻塞写用的等待队列头*/
};

struct globalfifo_dev *globalfifo_devp; /*设备结构体指针*/

int globalfifo_open(struct inode *inode, struct file *filp)
{
/*将设备结构体指针赋值给文件私有数据指针*/
filp->private_data = globalfifo_devp;
return 0;
}

int globalfifo_release(struct inode *inode, struct file *filp)
{
return 0;
}

static long globalfifo_ioctl(struct file *filep,unsigned int cmd, unsigned long arg)
{
struct globalfifo_dev *dev = filep->private_data;

switch(cmd) {
case MEM_CLEAR:
memset(dev->mem, 0x0, sizeof(dev->mem));
printk(KERN_INFO "globalmem is clear\n");
break;

default:
return -EINVAL;
}

return 0;
}

static ssize_t globalfifo_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 globalfifo_dev *dev = filp->private_data;
DECLARE_WAITQUEUE(wait, current);

down(&(dev->sem)); /*持有信号量*/

add_wait_queue(&dev->r_wait, &wait);

while(dev->current_len == 0)
{
if(filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}

__set_current_state(TASK_INTERRUPTIBLE); /*改变进程状态为睡眠*/

up(&dev->sem);

schedule();/*调度其他进程运行*/

if(signal_pending(current))
{
ret = -ERESTARTSYS;
goto out2;
}

down(&dev->sem);
}

if(p >= GLOBALFIFO_SIZE)
return 0;
if(count > (GLOBALFIFO_SIZE -p))
count = GLOBALFIFO_SIZE -p;

/*kernel space --> user's space*/
if(copy_to_user(buf, (void *)(dev->mem+p), count)) {
ret = -EFAULT;
goto out;
} else {
//*ppos += count;
memcpy(dev->mem, dev->mem + count, dev->current_len- count);
ret = count;
printk(KERN_INFO "read %u bytes from %lu\n", count, p);

wake_up_interruptible(&dev->w_wait); /*唤醒写等待队列*/
}

out:up(&dev->sem);
out2:remove_wait_queue(&dev->r_wait, &wait);/*移除等待队列*/
set_current_state(TASK_RUNNING);

return ret;
}

static ssize_t globalfifo_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 globalfifo_dev *dev = filp->private_data;

DECLARE_WAITQUEUE(wait, current);

down(&(dev->sem)); /*持有信号量*/

add_wait_queue(&dev->w_wait, &wait);

while(dev->current_len == GLOBALFIFO_SIZE)
{
if(filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}

__set_current_state(TASK_INTERRUPTIBLE); /*改变进程状态为睡眠*/

up(&dev->sem);

schedule();/*调度其他进程运行*/

if(signal_pending(current))
{
ret = -ERESTARTSYS;
goto out2;
}

down(&dev->sem);
}

if(p >= GLOBALFIFO_SIZE)
return 0;
if(count > (GLOBALFIFO_SIZE -p))
count = GLOBALFIFO_SIZE -p;

/* user's space --> kernel space */
if(copy_from_user(dev->mem + dev->current_len, buf, count)) {
ret = -EFAULT;
goto out;
} else {
//*ppos += count;
ret = count;
printk(KERN_INFO "write %u bytes,cur_len:%d\n", count, dev->current_len);

wake_up_interruptible(&dev->r_wait);
}

out:up(&dev->sem);
out2:remove_wait_queue(&dev->w_wait, &wait);/*移除等待队列*/
set_current_state(TASK_RUNNING);

return ret;
}

static loff_t globalfifo_lllseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch(orig) {
case 0:/*相对文件开始位置偏移*/
if ((offset < 0) ||((unsigned int)offset > GLOBALFIFO_SIZE)) {
ret = -EINVAL;
break;
}

filp->f_pos = (unsigned int)offset;
ret = filp->f_pos;
break;
case 1: /*根据文件当前位置偏移*/
if ((filp->f_pos + offset) > GLOBALFIFO_SIZE) {
ret = -EINVAL;
break;
}

filp->f_pos += (unsigned int)offset;
ret = filp->f_pos;
break;
default:
ret = -EINVAL;
break;
}

return ret;
}

static const struct file_operations globalfifo_filp = {
.owner = THIS_MODULE,
.llseek = globalfifo_lllseek,
.read = globalfifo_read,
.write = globalfifo_write,
.unlocked_ioctl = globalfifo_ioctl,
.open = globalfifo_open,
.release = globalfifo_release,
};

static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
{
int err;
int devno = MKDEV(globalfifo_major, index);

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

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

if (err)
printk(KERN_NOTICE "Error %d adding globalmem %d\n", err, index);
}

int globalfifo_init(void)
{
int result;
dev_t devno = MKDEV(globalfifo_major, 0);

/*申请设备号*/
if (globalfifo_major)
result = register_chrdev_region(devno, 1, "globalfifo");
else {/*动态申请设备号*/
result = alloc_chrdev_region(&devno, 0, 1, "globalfifo");

if(result < 0)
return result;
}

printk("devno:%d,%d\n",MAJOR(devno),MINOR(devno));

/*动态申请设备结构体的内存*/
globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
if (!globalfifo_devp) {
result = -ENOMEM;
goto fail_malloc;
}

memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));

globalfifo_setup_cdev(globalfifo_devp, 0);

sema_init(&(globalfifo_devp->sem), 1);/*初始化信号量*/

init_waitqueue_head(&(globalfifo_devp->w_wait));/*初始化写等待队列头*/
init_waitqueue_head(&(globalfifo_devp->r_wait));/*初始化读等待队列头*/

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

}

void globalfifo_exit(void)
{
cdev_del(&globalfifo_devp->cdev);/*注销cdev*/
kfree(globalfifo_devp);

unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);
}

module_init(globalfifo_init);
module_exit(globalfifo_exit);
module_param(globalfifo_major, int , S_IRUGO);

MODULE_AUTHOR("Barry song");
MODULE_LICENSE("Dual BSD/GPL");
...全文
676 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
水枂 2021-06-30
  • 打赏
  • 举报
回复 1

遇到了同样的问题,也是在return上面出问题了,感谢

Carl_CCC 2013-05-06
  • 打赏
  • 举报
回复
两个问题,1, 动态申请设备号的时候没有更新globalfifo_major的值 2 fail_malloc: unregister_chrdev_region(devno, 1); return result; 成功的话,在这之前需要return,不然申请后立刻退出, return 0;加这句就可以了 fail_malloc: unregister_chrdev_region(devno, 1); return result;
gongmin856 2013-05-06
  • 打赏
  • 举报
回复
果然是这个问题,万分感谢楼上的解答!
入式linux驱动开发流程 嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的。设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,完成以下功能: ◇ 驱动程序的注册和注销。 ◇ 设备的打开和释放。 ◇ 设备的读写操作。 ◇ 设备的控制操作。 ◇ 设备的中断和轮询处理。 Linux主要将设备分为三类:字符设备、块设备和网络设备。字符设备是指发送和接收数据以字符的形式进行,没有缓冲区的设备;块设备是指发送和接收数据以整个数据缓冲区的形式进行的设备;网络设备是指网络设备访问的BSD socket 接口。下面以字符设备为例,写出其驱动编写框架: 一、 编写驱动程序初始化函数 驱动程序的初始化在函数xxx_init()中完成,包括对硬件初始化、中断函数、向内核注册驱动程序等。 首先理解硬件结构,搞清楚其功能,接口寄存器以及CPU怎么访问控制这些寄存器等。 其次向内核注册驱动程序。设备驱动程序可以直接编译进内核,在系统启动的时候初始化,也可以在需要的时候以模块的方式动态加载到内核中去。每个字符设备或是块设备都是通过register_chrdev()函数注册,调用该函数后就可以向系统申请主设备,操作成功,设备名就会出现在/proc/devices里。 此外,在关闭设备时,需要先解除原先设备的注册,需要有清除函数,在xxx_exit()中通过unregister_chrdev()函数在实现,此后设备就会从/proc/devices里消失。 当驱动程序被编译成模块时,使用insmod加载模块,模块的初始化函数xxx_init()被调用,向内核注册驱动程序;使用rmmod卸载模块,模块的清除函数xxx_exit()被调用。 二、 构造file_operations结构中要用到的各个成员函数 Linux操作系统将所有的设备都看成文件,以操作文件的方式访问设备。应用程序不能直接操作硬件,使用统一的接口函数调用硬件驱动程序,这组接口被成为系统调用。每个系统调用中都有一个与之对应的函数(open、release、read、write、ioctl等),在字符驱动程序中,这些函数集合在一个file_operations类型的数据结构中。以一个键盘驱动程序为例: struct file_operations Key7279_fops = { .open = Key7279_Open, .ioctl = Key7279_Ioctl, .release = Key7279_Close, .read = Key7279_Read, }; 1、 设备的打开和释放 打开设备是由open()函数来完成,在大部分设备驱动中open完成如下工作: ◇ 递增计数器 ◇ 检查特定设备的特殊情况 ◇ 初始化设备 ◇ 识别次设备 释放设备由release()函数来完成。当一个进程释放设备时,其它进程还能继续使用该设备,只是该进程暂时停止对该设备的的使用,而当一个进程关闭设备时,其它进程必须重新打开此设备才能使用。Release完成如下工作: ◇ 递减计数 ◇ 在最后一次释放设备操作时关闭设备

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧