• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
梦想照进灵魂
博客园    首页    新随笔    联系   管理    订阅  订阅
dev\proc\sys
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include "hello.h"

#define DEV_NAME "hello"

#define pr_inf(fmt, arg ...) \
    printk(KERN_ERR "\033[32m[Mark] %04d : %s " fmt "\033[0m\n", __LINE__, __FUNCTION__, ##arg)

/**
 *  global driver data ptr
 */
struct __exitdata hello_android_dev *ddata = NULL;

/**********************************************************
 *
 *  /dev/hello have this list file operations
 *
 *********************************************************/
static int hello_open(struct inode *inode, struct file *filp)
{
    pr_inf("open a file...");

    return 0;
}

static int hello_release(struct inode *inode, struct file *filp)
{
    pr_inf("close a file...\n");

    return 0;
}

static ssize_t hello_read(struct file *flip, char __user *buf,
        size_t count, loff_t *offset)
{
    pr_inf("reading...");

    if (down_interruptible(&(ddata->sem))) {
        return -ERESTARTSYS;
    }

    if (count < 20)
        copy_to_user(buf, ddata->val, count);

    pr_inf("--> %s", ddata->val);

    up(&(ddata->sem));

    return 0;
}

static ssize_t hello_write(struct file *flip, const char __user *buf,
        size_t count, loff_t *offset)
{
    pr_inf("writing...");

    if (down_interruptible(&(ddata->sem))) {
        return -ERESTARTSYS;
    }

    if (count < 20)
        copy_from_user(ddata->val, buf, count);

    pr_inf("<-- %s", buf);

    up(&(ddata->sem));

    return 0;
}

static struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
    .read = hello_read,
    .write = hello_write,
};


/**********************************************************
 *
 *  init this module driver data
 *
 *********************************************************/
int hello_ddata_init(void)
{
    char buf[] = "Raw data";

    ddata = kzalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
    if (!ddata) {
        pr_inf("fail to alloc mem...");
        return -ENOMEM;
    }
    ddata->dev_no = 0;

    sema_init(&(ddata->sem), 1);
    memcpy(ddata->val, buf, sizeof(buf));

    return 0;
}

/**********************************************************
 *
 *  register char device
 *  create file /dev/hello /sys/class/hello/
 *  create attr file in /sys/class/hello
 *  create proc file /proc/hello
 *
 *********************************************************/
int hello_reg_dev(void)
{
    int ret;

    /**
     *  you can read device use -- head /dev/hello &
     *  through syscall to wirte ddata->val
     *  c-code maybe good, but no echo "XX" > /dev/hello
     */
    cdev_init(&(ddata->dev), &hello_fops);
    ddata->dev.owner = THIS_MODULE;

    /**
     *  call __register_chrdev_region(major, baseminor, minorct, DEV_NAME),
     *  which while major == 0 do auto alloc a dev_no
     */
    ret = alloc_chrdev_region(&(ddata->dev_no), 0, 1, DEV_NAME);
    if (ddata->dev_no < 0) {
        pr_inf("fail to alloc region...");
        return -ENODEV;
    }

    pr_inf("dev no : %d %d", MAJOR(ddata->dev_no), MINOR(ddata->dev_no));

    /**
     *  add a char device to kenel
     */
    ret = cdev_add(&(ddata->dev), ddata->dev_no, 1);
    if (ret < 0)
        goto err_add_cdev;

    /**
     *  create dirent /sys/class/hello
     */
    ddata->class = class_create(THIS_MODULE, "mark");
    if (IS_ERR(ddata->class)) {
        ret = PTR_ERR(ddata->class);
        pr_inf("fail to create /sys/class/mark/");
        goto err_creat_class;
    }

    /**
     *  create file /dev/hello & dirent /sys/class/mark/hello
     */
    ddata->device = device_create(ddata->class, NULL, ddata->dev_no, "%s", DEV_NAME);
    if (IS_ERR(ddata->device)) {
        ret = PTR_ERR(ddata->device);
        pr_inf("fail to create /sys/class/hello/hello & /dev/hello");
        goto err_create_device;
    }

    return 0;

err_create_device:
    class_destroy(ddata->class);

err_creat_class:
    cdev_del(&(ddata->dev));

err_add_cdev:
    unregister_chrdev_region(ddata->dev_no, 1);

    return ret;
}

/**********************************************************
 *
 *  create the attr file to use attr method
 *
 *********************************************************/
static ssize_t hello_val_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    char val[20] = {0};

    if (down_interruptible(&(ddata->sem))) {
        return -ERESTARTSYS;
    }

    memcpy(val, ddata->val, 20);

    up(&(ddata->sem));

    pr_inf("--> %s", ddata->val);

    return snprintf(val, PAGE_SIZE, "%s\n", val);
}

static ssize_t hello_val_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
{
    if (down_interruptible(&(ddata->sem))) {
        return -ERESTARTSYS;
    }

    if (count < 20) {
        memset(ddata->val, 0, 20);
        memcpy(ddata->val, buf, count);
    }

    up(&(ddata->sem));

    pr_inf("<-- %s", count < 20 ? buf : "most store 20 char");

    return count;
}

static DEVICE_ATTR(hello, S_IRUGO | S_IWUGO, hello_val_show, hello_val_store);

/**
 *  create a attr file /sys/class/mark/hello/hello
 *  use cat & echo to write\read
 */
int hello_creat_attr(void)
{
    /**
     *  the MACRO -- DEVICE_ATTR define as :
     *  struct device_attribute dev_attr_##_name =
     *      __ATTR(_name, _mode, _show, _store)
     */
    return device_create_file(ddata->device, &dev_attr_hello);
}

/**********************************************************
 *
 *  module operations
 *
 *********************************************************/
static ssize_t hello_proc_read(char *page, char **start,
        off_t off, int count, int *eof, void *data)
{
    char val[20] = {0};

    if (off > 0) {
        *eof = 1;
        return 0;
    }

    if (down_interruptible(&(ddata->sem))) {
        return -ERESTARTSYS;
    }

    memcpy(val, ddata->val, sizeof(val));

    up(&(ddata->sem));

    pr_inf("--> %s", ddata->val);

    return snprintf(page, PAGE_SIZE, "%s\n", val);
}

static ssize_t hello_proc_write(struct file *flip,
        const char __user *buf, unsigned long len, void *data)
{
    int err = 0;
    char *page = NULL;

    if (len > PAGE_SIZE)
        return -EFAULT;

    page = (char *)__get_free_page(GFP_KERNEL);
    if (!page)
        return -ENOMEM;

    if (copy_from_user(page, buf, len)) {
        err = -EFAULT;
        goto out;
    }


    if (down_interruptible(&(ddata->sem))) {
        err =  -ERESTARTSYS;
        goto out;
    }

    memset(ddata->val, 0, 20);
    memcpy(ddata->val, page, len);

    up(&(ddata->sem));

    pr_inf("--> %s", ddata->val);

    return len;

out:
    free_page((unsigned long)page);

    return err;
}

int hello_build_proc(void)
{
    struct proc_dir_entry *entry;

    entry = create_proc_entry(DEV_NAME, 0777, NULL);
    if (entry) {
        entry->read_proc = hello_proc_read;
        entry->write_proc = hello_proc_write;
        return 0;
    }

    return -ENODEV;
}

/**********************************************************
 *
 *  module operations
 *
 *********************************************************/
static __init int hello_init(void)
{
    int ret;

    pr_inf("Driver init...\n\n");
    pr_inf("[ %s ] get pid is : %i", current->comm, current->pid);

    ret = hello_ddata_init();
    if (ret < 0)
        return ret;

    ret = hello_reg_dev();
    if (ret < 0)
        goto err_reg_dev;

    ret = hello_creat_attr();
    if (ret < 0)
        goto err_creat_attr;

    ret = hello_build_proc();
    if (ret < 0)
        goto err_build_proc;

    return 0;

err_build_proc:
err_creat_attr:
    if (ddata && ddata->class) {
        device_destroy(ddata->class, ddata->dev_no);
        class_destroy(ddata->class);
    }

    if (ddata->dev_no)
        unregister_chrdev_region(ddata->dev_no, 1);

    if (ddata)
        cdev_del(&(ddata->dev));

err_reg_dev:
    kfree(ddata);
    ddata = NULL;

    return ret;
}

static __exit void hello_exit(void)
{
    pr_inf("Driver destory...\n\n");

    remove_proc_entry(DEV_NAME, NULL);

    if (ddata && ddata->class) {
        device_destroy(ddata->class, ddata->dev_no);
        class_destroy(ddata->class);
    }

    if (ddata->dev_no)
        unregister_chrdev_region(ddata->dev_no, 1);

    if (ddata) {
        cdev_del(&(ddata->dev));
        kfree(ddata);
        ddata = NULL;
    }

    return;
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark");

module_init(hello_init);
module_exit(hello_exit);
 
#ifndef _HELLO_ANDROID_H_
#define _HELLO_ANDROID_H_

#include <linux/cdev.h>
#include <linux/semaphore.h>

#define HELLO_DEVICE_NODE_NAME  "hello"
#define HELLO_DEVICE_FILE_NAME  "hello"
#define HELLO_DEVICE_PROC_NAME  "hello"
#define HELLO_DEVICE_CLASS_NAME "hello"

struct hello_android_dev {
    char val[20];
    struct semaphore sem;
    struct cdev dev;
    dev_t dev_no;
    struct class *class;
    struct device *device;
};

#endif

 

posted on 2012-08-14 01:40  梦想照进灵魂  阅读(335)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3