刚看了华清远见的《Linux设备驱动开发详解》,突然就想动手慢慢的实践一番,就当作笔记吧,先来个简单的驱动,其实就是里面的例子,不过感觉写的还是很不错,自己也动手尝试一下:
- /*
- * file: gmemd.c
- * history:
- * 20111205: initial
- * 20111205: support async event to app level
- */
- #include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/cdev.h>
-
#include <linux/fs.h>
-
#include <linux/signal.h>
-
-
#include <asm/uaccess.h>
-
-
#define GMEMD_MAJOR 221
-
-
#define MEM_CLEAR 0x01
-
-
#define DEMO_NAME "demo_dev"
-
#define MEM_SIZE 1024
-
-
static int gmemd_major = GMEMD_MAJOR;
-
-
-
typedef struct demo_dev_st
-
{
-
struct cdev cdev;
-
unsigned char mem[MEM_SIZE];
-
struct fasync_struct *async_queue;
-
}demo_dev_t;
-
-
static struct demo_dev_st* __demo_devp=0;
-
-
-
static int __demo_open (struct inode *inode, struct file *filp)
-
{
-
filp->private_data = __demo_devp;
-
printk("==>trace: %s\n", __func__);
-
return 0;
-
}
-
-
-
-
static ssize_t __demo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
-
{
-
int ret = 0;
-
unsigned long pos = *ppos;
-
unsigned long count = size;
-
-
struct demo_dev_st* devp = filp->private_data;
-
-
printk("==>trace: %s, size=%d, pos=%d\n", __func__, size, pos);
-
-
#if 0
-
if (pos >= MEM_SIZE)
-
return count ? -ENXIO : 0;
-
if (count > MEM_SIZE - pos)
-
count = MEM_SIZE - pos;
-
#else
-
{
-
int i=0;
-
while (i<MEM_SIZE-1 && devp->mem[i]) i++;
-
if (i==MEM_SIZE-1)
-
{
-
devp->mem[i]=0;
-
}
-
count = i;
-
}
-
#endif
-
-
if (copy_to_user(buf, (void*)(devp->mem+pos), count))
-
{
-
ret = -EFAULT;
-
}
-
else
-
{
-
#if 0
-
*ppos += count;
-
#else
-
*ppos = 0;
-
#endif
-
ret = count;
-
}
-
return ret;
-
}
-
-
static ssize_t __demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
-
{
-
int ret = 0;
-
unsigned long pos = *ppos;
-
unsigned long count = size;
-
-
struct demo_dev_st* devp = filp->private_data;
-
-
printk("==>trace: %s, size=%d, pos=%d\n", __func__, size, pos);
-
-
if (pos >= MEM_SIZE)
-
return count ? -ENXIO : 0;
-
if (count > MEM_SIZE - pos)
-
count = MEM_SIZE - pos;
-
-
if (copy_from_user(devp->mem+pos,buf,count))
-
{
-
ret = -EFAULT;
-
}
-
else
-
{
-
#if 0
-
*ppos= count;
-
#else
-
*ppos= 0;
-
#endif
-
ret = count;
-
if (devp->async_queue)
-
kill_fasync(&devp->async_queue, SIGIO, POLL_IN);
-
}
-
return ret;
-
}
-
-
static int __demo_fasync(int fd, struct file *filp, int mode)
-
{
-
struct demo_dev_st* devp = filp->private_data;
-
printk("==>trace: %s\n", __func__);
-
-
return fasync_helper(fd, filp, mode, &devp->async_queue);
-
}
-
-
static loff_t __demo_llseek(struct file *filp, loff_t offset, int orig)
-
{
-
loff_t ret = 0;
-
-
struct demo_dev_st* devp = filp->private_data;
-
-
printk("==>trace: %s, orig=%d, offset=%d\n", __func__, orig, offset);
-
-
switch(orig)
-
{
-
case 0: /* offset from the 0 position of the file */
-
if (offset < 0 || (unsigned int)offset > MEM_SIZE)
-
{
-
ret = -EINVAL;
-
break;
-
}
-
ret = filp->f_pos = (unsigned int)offset;
-
break;
-
case 1: /* offset from the current position */
-
if ((filp->f_pos+offset)<0||(filp->f_pos+offset)>MEM_SIZE)
-
{
-
ret = -EINVAL;
-
break;
-
}
-
filp->f_pos += offset;
-
ret = filp->f_pos;
-
break;
-
default:
-
ret = -EINVAL;
-
break;
-
}
-
-
return ret;
-
}
-
-
-
static long __demo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-
{
-
long ret = 0;
-
-
struct demo_dev_st* devp = filp->private_data;
-
switch(cmd)
-
{
-
case MEM_CLEAR:
-
memset(devp->mem, 0, MEM_SIZE);
-
break;
-
default:
-
ret = -EINVAL;
-
break;
-
}
-
return ret;
-
}
-
-
static int __demo_release(struct inode *inode, struct file *filp)
-
{
-
struct demo_dev_st* devp = filp->private_data;
-
printk("==>trace: %s\n", __func__);
-
__demo_fasync(-1, filp, 0);
-
return 0;
-
}
-
-
-
static struct file_operations gmemd_fops =
-
{
-
.owner = THIS_MODULE,
-
.read = __demo_read,
-
.write = __demo_write,
-
.open = __demo_open,
-
.release = __demo_release,
-
.fasync = __demo_fasync,
-
.llseek = __demo_llseek,
-
.ioctl = __demo_ioctl,
-
};
-
-
static int __gmemd_init()
-
{
-
int ret = 0;
-
dev_t devno = MKDEV(gmemd_major, 0);
-
-
printk("==>trace: %s\n", __func__);
-
-
if (gmemd_major)
-
{
-
ret = register_chrdev_region(devno,1,DEMO_NAME);
-
}
-
else
-
{
-
ret = alloc_chrdev_region(&devno, 0, 1, DEMO_NAME);
-
gmemd_major = MAJOR(devno);
-
}
-
if (ret < 0)
-
return ret;
-
-
__demo_devp=kmalloc(sizeof(demo_dev_t),GFP_KERNEL); /* __get_free_pages */
-
-
if (!__demo_devp)
-
{
-
ret = -ENOMEM;
-
goto __err_exit;
-
}
-
memset(__demo_devp, 0, sizeof(demo_dev_t));
-
-
cdev_init(&__demo_devp->cdev , &gmemd_fops);
-
__demo_devp->cdev.owner = THIS_MODULE;
-
ret = cdev_add(&__demo_devp->cdev, devno, 1);
-
if (ret)
-
printk(KERN_INFO "error to cdev_add() ... \n");
-
-
return ret;
-
-
__err_exit:
-
unregister_chrdev_region(devno, 1);
-
-
return ret;
-
}
-
-
static void __gmemd_exit()
-
{
-
printk("==>trace: %s\n", __func__);
-
cdev_del(&__demo_devp->cdev);
-
kfree(__demo_devp);
-
__demo_devp=0;
-
unregister_chrdev_region(MKDEV(gmemd_major,0), 1);
-
}
-
-
module_init(__gmemd_init);
-
module_exit(__gmemd_exit);
-
-
MODULE_AUTHOR("vincent");
-
MODULE_DESCRIPTION("nothing to say...");
-
MODULE_LICENSE("GPL");
-
MODULE_ALIAS("test");
应用层测试用的APP:
- /*
-
* file: client.c
-
* history:
-
* 20111205: initial, for test async event in the app level
-
*/
-
-
#include <unistd.h>
-
#include <fcntl.h>
-
#include <signal.h>
-
#include <stdio.h>
-
#include <sys/stat.h>
-
-
#define DEMO_DEV "/dev/gmemd"
-
-
static int s_fd=-1;
-
-
-
static void __sig_handler(int signum)
-
{
-
#define MAX_BUF 1023
-
int count = 0;
-
char buf[MAX_BUF+1]= {0};
-
-
printf("==>signum:%d\n", signum);
-
-
if (s_fd!=-1)
-
{
-
while ((count=read(s_fd, buf, MAX_BUF))>=MAX_BUF)
-
{
-
printf("count:%d=>%s\n", count,(buf[MAX_BUF]=0,buf));
-
}
-
printf("count:%d=>%s\n", count,(buf[count]=0,buf));
-
}
-
}
-
-
int main(void)
-
{
-
int fd, oflags;
-
printf("wellcome to startup the client program!\n");
-
s_fd = fd = open (DEMO_DEV, O_RDWR, S_IRUSR|S_IWUSR);
-
if (fd==-1)
-
{
-
printf("open %s failed!\n", DEMO_DEV);
-
return -1;
-
}
-
else
-
{
-
printf("open %s successful!\n", DEMO_DEV);
-
signal(SIGIO, __sig_handler);
-
fcntl(fd, F_SETOWN, getpid());
-
oflags = fcntl(fd, F_GETFL);
-
fcntl(fd, F_SETFL, oflags|FASYNC);
-
while(1);
-
}
-
}
接下来就是Makefile:
- #Makefile
-
-
obj-m := gmemd.o
-
-
KDIR := /usr/src/linux-headers-2.6.24-16-generic
-
-
CC := gcc
-
-
default:
-
make -C $(KDIR) M=$(PWD) modules
-
-
client: client.o
-
$(CC) -Wall client.c -o client
编译之前发现自己的gcc没下载开发包,需要执行指令:
sudo apt-get install build-essential然后编译:
make
make client
再加载模块:
insmod gmemd.ko再查看加载的模块:
lsmod | grep gmemd再查看注册的设备信息:
cat /proc/devices再在/dev/目录下创建一个设备节点信息提供给应用层的访问:
mknod /dev/gmemd c 221 0查看设备节点信息:
ls -l /dev/gmemd再对设备节点对其读写:
echo "test" > /dev/gmemd
cat /dev/gmemd测试异步IO响应事件:
./client &
echo "test" > /dev/gmemd再查看里面printk打印出来的日志信息:
cat /var/log/messages最后删除设备节点和卸载模块:
rm /dev/gmemd
rmmod gmemd完成
附件:
gmemd.rar
阅读(1394) | 评论(0) | 转发(0) |