您的位置:首页 > 其它

模拟有名管道驱动

2015-09-09 22:04 204 查看
```
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/slab.h>         // kmalloc kfree
#define PIPE_UDEV
//#define PIPE_KMALLOC
//#define PIPE_DEBUG_MSG
#define PIPE_IOC_BUFFER_CLEAR       _IO ('P', 1)
#define PIPE_IOC_BUFFER_LENGTH      _IOR ('P', 2, unsigned int)
#define PIPE_IOC_BUFFER_AVAIL       _IOR ('P', 3, unsigned int)
#define MAX_STRING_LENGTH           1024
char msg[MAX_STRING_LENGTH + 1];
#if !defined ( PIPE_KMALLOC )                   // 没有定义PIPE_KMALLOC,使用数组模拟管道
#define PIPE_BUFFER_SIZE            4096
#define PIPE_BUFFER_MASK            0x0FFF
//#define PIPE_BUFFER_VALUE(x)      ( (x) & PIPE_BUFFER_MASK )
#define PIPE_BUFFER_EMPTY(pipe)     ( (pipe)->head == (((pipe)->tail + 1) & PIPE_BUFFER_MASK) )
#define PIPE_BUFFER_FULL(pipe)      ( (pipe)->head == (((pipe)->tail + 2) & PIPE_BUFFER_MASK) ) // 避免与队空情况相同,队满间隔为2
#define DATA_TYPE                   char
//#define COPY_DATA_TYPE(pDest,pSrc)    ( *(pDset) = *(pSrc) )
struct my_pipe {
int head, tail;
DATA_TYPE buffer[PIPE_BUFFER_SIZE];
}pipe;
void init_pipe (struct my_pipe * pipe)
{
pipe->head = 0;         // head指向队首元素
pipe->tail = -1;        // tail指向队尾元素
}
void clear_pipe (struct my_pipe * pipe)
{
pipe->head = 0;         // head指向队首元素
pipe->tail = -1;        // tail指向队尾元素
}
int push_pipe (struct my_pipe * pipe, DATA_TYPE * data) // 入队
{
if (PIPE_BUFFER_FULL(pipe))     return -1;  // 满队列
pipe->tail = ((pipe->tail + 1) & PIPE_BUFFER_MASK); // 新元素位置
pipe->buffer[pipe->tail] = *data;
return 0;
}
int pop_pipe (struct my_pipe * pipe)                    // 出队
{
if (PIPE_BUFFER_EMPTY(pipe))    return -1;  // 空队列
pipe->head = ((pipe->head + 1) & PIPE_BUFFER_MASK);
return 0;
}
int top_pipe (struct my_pipe * pipe, DATA_TYPE * dest)  // 获取队首元素
{
if (PIPE_BUFFER_EMPTY(pipe))    return -1;  // 空队列
*dest = pipe->buffer[pipe->head];
return 0;
}
int length_pipe (struct my_pipe * pipe)
{
if (PIPE_BUFFER_EMPTY(pipe))    return 0;
if (pipe->head <= pipe->tail)   return (pipe->tail - pipe->head + 1);
else    return (pipe->tail - pipe->head + 1 + PIPE_BUFFER_SIZE);
}
int avail_pipe (struct my_pipe * pipe)
{
if (PIPE_BUFFER_EMPTY(pipe))    return PIPE_BUFFER_SIZE;
if (pipe->head <= pipe->tail)   return PIPE_BUFFER_SIZE - (pipe->tail - pipe->head + 1);
else    return PIPE_BUFFER_SIZE - (pipe->tail - pipe->head + 1 + PIPE_BUFFER_SIZE);
}
#endif // !PIPE_KMALLOC
#ifdef PIPE_UDEV
static struct class * zone_pipe_class = NULL;
static struct device * zone_pipe_device = NULL;
#endif // PIPE_UDEV
static struct cdev * zone_pipe = NULL;          // 字符设备指针(管道)
static dev_t zone_pipe_devno;                   // 设备号
static ulong zone_pipe_major = 0;               // 主设备号
static ulong zone_pipe_minor = 0;               // 次设备号
//module_param (zone_pipe_devno, ulong, 0660);
module_param (zone_pipe_major, ulong, 0660);
static int zone_pipe_open (struct inode * inode, struct file * filp)
{
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_open ...\n");
#endif // PIPE_DEBUG_MSG
#if !defined ( PIPE_KMALLOC )
init_pipe (&pipe);
#endif // !PIPE_KMALLOC
return 0;
}
static int zone_pipe_release (struct inode * inode, struct file * filp)
{
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_release ...\n");
#endif // PIPE_DEBUG_MSG
return 0;
}
static ssize_t zone_pipe_write (struct file * filp, const char __user * buf, size_t count, loff_t * f_pos)
{
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_write ...\n");
#endif // PIPE_DEBUG_MSG
int ret, len, cnt, i, num;
#if !defined ( PIPE_KMALLOC )
for (cnt=0, num=count; num; num-=cnt) { // 写完
cnt = (num <= MAX_STRING_LENGTH) ? num : MAX_STRING_LENGTH;
len = cnt - copy_from_user (msg, buf, cnt);
for (i=0; i<len; ++i)
if ( (ret = push_pipe (&pipe, &msg[i])))    {   // 满队列
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "\t pipe full ...\n");
#endif // PIPE_DEBUG_MSG
return (count - num + i);
}
if (len != cnt) {   // 地址出错
return (count - num + len);
}
}
#endif // !PIPE_KMALLOC
return count;
}
static ssize_t zone_pipe_read (struct file * filp, const char __user * buf, size_t count, loff_t * f_pos)
{
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_read ...\n");
#endif // PIPE_DEBUG_MSG
int ret, len, cnt, i, num;
#if !defined ( PIPE_KMALLOC )
char ch;
for (cnt=0, num=count; num; num-=cnt) { // 写完
cnt = (num <= MAX_STRING_LENGTH) ? num : MAX_STRING_LENGTH;
for (i=0; i<cnt; ++i) {
if ( (ret = top_pipe (&pipe, &ch)) < 0) {   // 空队列
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "\t pipe empty ...\n");
#endif // PIPE_DEBUG_MSG
cnt = i;
break;
}
msg[i] = ch;
pop_pipe (&pipe);
}
len = cnt - copy_to_user (buf, msg, cnt);
if (ret < 0) {
return (count - num + len);
}
if (len != cnt) {   // 地址出错
return (count - num + len);
}
}
#endif // !PIPE_KMALLOC
return count;
}
static long zone_pipe_ioctl (struct file * filp, unsigned int cmd, unsigned long arg)
{
int ret = 1, length;
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_ioctl ...\n");
#endif // PIPE_DEBUG_MSG
if (_IOC_DIR (cmd) & _IOC_READ) {
ret = access_ok (VERIFY_WRITE, (void __user *)arg, _IOC_SIZE (cmd));
} else {
ret = access_ok (VERIFY_READ, (void __user *)arg, _IOC_SIZE (cmd));
}
if (!ret) {
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "_IOC_DIR error ...\n");
#endif // PIPE_DEBUG_MSG
return -EFAULT;
}
switch (cmd) {
case PIPE_IOC_BUFFER_LENGTH:
#if !defined ( PIPE_KMALLOC )
length = length_pipe (&pipe);
ret = put_user (length, (int *)arg);
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "\t pipe length = %d ...\n", length);
#endif // PIPE_DEBUG_MSG
#endif // !PIPE_KMALLOC
break;
case PIPE_IOC_BUFFER_AVAIL:
#if !defined ( PIPE_KMALLOC )
length = avail_pipe (&pipe);
ret = put_user (length, (int *)arg);
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "\t pipe avail = %d ...\n", length);
#endif // PIPE_DEBUG_MSG
#endif // !PIPE_KMALLOC
break;
case PIPE_IOC_BUFFER_CLEAR:
#if !defined ( PIPE_KMALLOC )
clear_pipe (&pipe);
#endif // !PIPE_KMALLOC
break;
default:
break;
}
return 0;
}
static struct file_operations zone_pipe_fops = {
.owner          = THIS_MODULE,
.open           = zone_pipe_open,
.release        = zone_pipe_release,
.write          = zone_pipe_write,
.read           = zone_pipe_read,
.unlocked_ioctl         = zone_pipe_ioctl
};
static int __init zone_pipe_init (void)
{
int ret;
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_init ...\n");
#endif // PIPE_DEBUG_MSG
if (zone_pipe_major) {          // 设置了主设备号模块参数
ret = register_chrdev_region (&zone_pipe_devno, 1, "zone_pipe_devno");
} else {
zone_pipe_devno = MKDEV (zone_pipe_major, zone_pipe_minor);
ret = alloc_chrdev_region (&zone_pipe_devno, 0, 1, "zone_pipe_devno");
}
if (ret < 0) {                  // 申请设备号出错
printk (KERN_INFO "zone_pipe_init : Register devno error ...\n");
return -EFAULT;
}
zone_pipe_major = MAJOR (zone_pipe_devno);      // 主设备号
zone_pipe_minor = MINOR (zone_pipe_devno);      // 次设备号
#ifdef PIPE_DEBUG_MSG               // 打印主设备号,次设备号
printk (KERN_INFO "zone_pipe_devno %lu %lu\n", zone_pipe_major, zone_pipe_minor);
#endif // PIPE_DEBUG_MSG
zone_pipe = cdev_alloc ();                      // 分配空间
//cdev_init (zone_pipe, &zone_pipe_fops);       // 结构体需要初始化
zone_pipe->ops = &zone_pipe_fops;               // 指针需要设置ops指针
zone_pipe->owner = THIS_MODULE;
if (cdev_add (zone_pipe, zone_pipe_devno, 1) < 0) { // 加入字符设备内核链表
printk (KERN_INFO "zone_pipe_init : Add cdev kernel_list error ...\n");
return -EFAULT;
}
#ifdef PIPE_UDEV
zone_pipe_class = class_create (THIS_MODULE, "zone_pipe_class");
if (IS_ERR (zone_pipe_class)) {
printk (KERN_INFO "zone_pipe_init : class_create error ...\n");
cdev_del (zone_pipe);
unregister_chrdev_region (zone_pipe_devno, 1);
return -EFAULT;
}
zone_pipe_device = device_create (zone_pipe_class, NULL, zone_pipe_devno, NULL, "zone_pipe_device");
#endif // PIPE_UDEV
return 0;
}
static void __exit zone_pipe_exit (void)
{
cdev_del (zone_pipe);
unregister_chrdev_region (zone_pipe_devno, 1);
zone_pipe_devno = 0;
#ifdef PIPE_UDEV
device_destroy (zone_pipe_class, zone_pipe_devno);
class_destroy (zone_pipe_class);
#endif // PIPE_UDEV
#ifdef PIPE_DEBUG_MSG
printk (KERN_INFO "zone_pipe_exit ...\n");
#endif // PIPE_DEBUG_MSG
}
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("wilson1068@163.com");
module_init (zone_pipe_init);
module_exit (zone_pipe_exit);


“`
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: