宋宝华linux内核驱动代码,宋宝华 《Linux设备驱动开发详解》示例代码之fifo字符设备驱动...

驱动代码如下:

scull.c

#include

#include

#include

#include

#include

#include

#include

#include

#defineSCULL_MAJOR252

#define SCULL_NAME"scull"

#define MAX_DATA0x10

staticint scull_major = SCULL_MAJOR;

struct scull_dev {

struct cdev cdev;

unsigned char data[MAX_DATA];

struct semaphore sem;

unsigned int current_len;

wait_queue_head_t r_wait;

wait_queue_head_t w_wait;

};

MODULE_LICENSE("GPL");

MODULE_AUTHOR("BG2BKK");

structscull_dev *scull_devp;

intscull_open(struct inode *inode, struct file *filp)

{

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

filp->private_data = dev;

printk(KERN_ALERT "open the scull device\n");

return 0;

}

intscull_release(struct inode *inode, struct file *filp)

{

printk(KERN_ALERT "close the scull device\n");

return 0;

}

ssize_tscull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)

{

struct scull_dev *dev = filp->private_data;

int ret = 0;

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(count > dev->current_len)

count = dev->current_len;

if(copy_to_user(buf, dev->data,count)){

ret = -EFAULT;

goto out;

} else {

memcpy(dev->data, dev->data + count, dev->current_len - count);

dev->current_len -= count;

printk(KERN_ALERT "read %u bytes; current_len:%d\n",count, dev->current_len);

wake_up_interruptible(&dev->w_wait);

ret = count;

}

out:

up(&dev->sem);

out2:

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

set_current_state(TASK_RUNNING);

return ret;

}

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)

{

struct scull_dev *dev = filp->private_data;

int ret = 0;

DECLARE_WAITQUEUE(wait, current);

down(&dev->sem);

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

while(dev->current_len == MAX_DATA){

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(count > MAX_DATA - dev->current_len){

count = MAX_DATA - dev->current_len;

}

if(copy_from_user(dev->data + dev->current_len, buf, count)){

ret = -EFAULT;

goto out;

}

else {

dev->current_len += count;

printk(KERN_ALERT "written %d bytes, current_len:%d\n",count, dev->current_len);

wake_up_interruptible(&dev->r_wait);

ret = count;

}

out:

up(&dev->sem);

out2:

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

set_current_state(TASK_RUNNING);

return ret;

}

staticunsigned int scull_poll(struct file *filp, poll_table *wait)

{

unsigned int mask = 0;

struct scull_dev *dev = filp->private_data;

down(&dev->sem);

poll_wait(filp, &dev->r_wait, wait);

poll_wait(filp, &dev->w_wait, wait);

if(dev->current_len != 0)

mask |= POLLIN | POLLRDNORM;

if(dev->current_len != MAX_DATA)

mask |= POLLOUT | POLLWRNORM;

up(&dev->sem);

return mask;

}

static const structfile_operations scull_fops = {

.owner=THIS_MODULE,

.open=scull_open,

.release=scull_release,

.write=scull_write,

.read=scull_read,

.poll=scull_poll,

};

staticvoidscull_setup_cdev(struct scull_dev *dev, int index)

{

int err, devno = MKDEV(scull_major, index);

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

dev->cdev.owner = THIS_MODULE;

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

if(err)

printk(KERN_NOTICE "ERROR %d adding scull_dev %d", err, index);

}

intscull_init(void)

{

int result;

dev_tdevno = MKDEV(scull_major,0);

if(scull_major)

result = register_chrdev_region(devno, 1, "scull");

else {

result = alloc_chrdev_region(&devno, 0, 1, "scull");

scull_major = MAJOR(devno);

}

if(result < 0)

return result;

scull_devp = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);

if(!scull_devp){

result = -ENOMEM;

goto fail_malloc;

}

memset(scull_devp, 0 , sizeof(struct scull_dev));

scull_setup_cdev(scull_devp, 0);

init_MUTEX(&scull_devp->sem);

init_waitqueue_head(&scull_devp->r_wait);

init_waitqueue_head(&scull_devp->w_wait);

printk(KERN_ALERT "init scull device\n");

return 0;

fail_malloc:

unregister_chrdev_region(devno, 1);

return result;

}

voidscull_cleanup(void)

{

cdev_del(&scull_devp->cdev);

kfree(scull_devp);

unregister_chrdev_region(MKDEV(scull_major, 0), 1);

printk(KERN_ALERT "clean scull device\n");

}

module_init(scull_init);

module_exit(scull_cleanup);测试代码

/*************************************************************************

*fileName: test.c

*description: test the myscull.c

*author: Hzc

*create time: 2007-04-20

*modify info: -

*************************************************************************/

#include

#include

#include

#include

#include

#include

#define BUFFER_LEN 20

#define FIFO_CLEAR 0x01

#define device"/dev/scull"

int main()

{

int num;

fd_set rfds, wfds;

int fd = open(device, O_RDONLY| O_NONBLOCK);

if(fd != 0){

while(1){

FD_ZERO(&rfds);

FD_ZERO(&wfds);

FD_SET(fd, &rfds);

FD_SET(fd, &wfds);

select(fd+1, &rfds, &wfds, NULL, NULL);

if(FD_ISSET(fd, &rfds))

printf("poll monitor: can be read\n");

if(FD_ISSET(fd, &wfds))

printf("poll monitor: can be written\n");

}

} else{

printf("Device " device "open failer");

}

}

Makefile

KERNEL_DIR := /lib/modules/$(shell uname -r)/build

PWD:= $(shell pwd)

obj-m := scull.o

default:

$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules

test: test.c

gcc $< -o $@.o -g

clean:

rm -rf *.o *.ko *~ *.order *.symvers *.markers *.mod.c

测试脚本

1 load_scull.sh

#!/bin/sh

/sbin/insmod scull.ko

mknod /dev/scull c 252 0

2 unload_scull.sh

#!/bin/sh

/sbin/rmmod scull.ko

rm /dev/scull -f

3 test.sh

#!/bin/sh

make clean

make

make test

sudo ./unload_scull

sudo ./load_scull

sudo ./test.o

测试时,执行./test.o,终端一直输出poll monitor: can be write,

在另一终端,以根用户模式,echo hello > /dev/scull,可以看到输出poll monitor: can be read和poll monitor: can be write

多echo hello > /dev/scull几次后,由于scull设备缓冲区仅16B,不再能写入,此时只输出poll monitor: can be read

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值