字符設備(一)

字符設備(順序讀寫,不帶緩衝)

塊設備(讀寫順序不固定,帶讀寫緩衝)常用sync命令(強行寫入硬件) 同步數據使數據真正寫進磁盤不然可能還在緩衝區

網絡設備:這傢伙破壞了linux一切皆文件規則。

字符設備框架:

硬件上有個字符設備,內核中就有個cdev結構與之對應

struct cdev {

struct kobject kobj;

struct module *owner;

const struct file_operations *ops;

struct list_head list;

dev_t dev;//設備號

unsigned int count;

};

每個cdev都有個設備號

設備號(32bits)=主設備號(高12bits)+次設備號(20bits)

主設備號:代表一個類型的設備

次設備號:用於區分設備的不同個體

主設備號的選取

->靜態分配

看現在內核中那些主設備號沒有被使用,選擇一個

查看 cat/proc/devoces已用的設備號

看內核源碼目錄下即Documentation\device.txt看看使用那些設備號

register_chedev_region(dev_t from,unsigned count,const char name)可以連續註冊多個字符設備號

from要註冊的起始設備號

count 連續註冊的設備個數

name名字


dev_t  __u32  ->  unsigned int  16位和32位移植兼容性才這麼設計的


#definrMINORBITS 20

MKDEV(ma(主設備號),mi(次設備號)) 他是個宏 其實源碼也就做了ma<<MINORBITS|mi)

unregister_chrdev_region(dev,nsigned count)卸載字符設備

 


->動態分配  但不是隨機分配

alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char name)

註釋:

/**

 * alloc_chrdev_region() - register a range of char device numbers

 * @dev: output parameter for first assigned number

 * @baseminor: first of the requested range of minor numbers

 * @count: the number of minor numbers required

 * @name: the name of the associated device or driver

 *

 * Allocates a range of char device numbers.  The major number will be

 * chosen dynamically, and returned (along with the first minor number)

 * in @dev.  Returns zero or a negative error code.

 */


 獲取主設備號:

 MAJOR(dev)   dev>>MINORBITS




cdev的操作函數

cdev_init()//初始化cdev

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

{

memset(cdev, 0, sizeof *cdev);

INIT_LIST_HEAD(&cdev->list);

kobject_init(&cdev->kobj, &ktype_cdev_default);

cdev->ops = fops;

}


cdev_add()//向內核註冊cdev


int cdev_add(struct cdev *p, dev_t dev, unsigned count)

{

p->dev = dev;

p->count = count;

return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);

}




struct file_operations {

struct module *owner;

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

int (*readdir) (struct file *, void *, filldir_t);

unsigned int (*poll) (struct file *, struct poll_table_struct *);

.....

};



_exit 要逆序消除 _init產生的影響

cdev_del()

unregister_chrdev_region(dev,nsigned count)

手工創建設備節點文件

mknod /dev/xxx c 248 0 

               主  次











arm-none-linux-gnueabi-gcc -o










簡單小示例:

#include <linux/init.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/cdev.h>



MODULE_LICENSE("Dua BSD/GPL");

MODULE_AUTHOR("Songmao");

MODULE_DESCRIPTION("cdev tast");


#define TCDEV_MAJOR 0

#define TCDEV_MINOR 0

#define TCDEV_NUM 1

#define TCDEV_NAME "mytcdev"

static int tcdev_major =TCDEV_MAJOR,tcdev_minor=TCDEV_MINOR;

module_param(tcdev_major,int,S_IRWXU);

module_param(tcdev_minor,int,S_IRWXU);


static int tcdev_open(struct inode * node,struct file * filep)

{

      printk(KERN_INFO "tcdev open\n");

 return 0;

}

static ssize_t tcdev_read(struct file *file, char __user *buf, size_t count, loff_t *fops)

{

      printk(KERN_INFO "tcdev read\n");

 return 0;

}

static ssize_t tcdev_write (struct file *file, char __user *buf, size_t count, loff_t *fops)

{

      printk(KERN_INFO "tcdev write\n");

 return 0;

}

static int tcdev_release(struct inode * node,struct file * filep)

{

      printk(KERN_INFO "tcdev write\n");

 return 0;

}


static struct file_operations tcdev_fops = {

    .owner=THIS_MODULE,

.open=tcdev_open,

.read=tcdev_read,

.write=tcdev_write,

.release=tcdev_release,

};

static struct cdev tcdev;




static int __init tcdev_init(void)

{

     int ret =-EFAULT;

dev_t tcdev_t;

tcdev_t=MKDEV(tcdev_major,tcdev_minor);

     printk(KERN_INFO "tcdev start ...\n");

if(tcdev_major==0){

         ret= alloc_chrdev_region(&tcdev_t,tcdev_minor,TCDEV_NUM,TCDEV_NAME);

if(ret<0){

printk(KERN_ERR"tcdev cdev num apply is fail\n");

goto tcdev_cdev_fail;

             

}

}

else{

  ret=register_chrdev_region(tcdev_t,TCDEV_NUM,TCDEV_NAME);

  if(ret<0){

  printk(KERN_ERR "tcdev cdev num apply is fail\n");

  goto tcdev_cdev_fail;

  }

  

}


     printk(KERN_INFO "tcdev cdev num apply is success,dev_t is %d\n",tcdev_t);

memset(&tcdev,0,sizeof(struct cdev));

cdev_init(&tcdev,&tcdev_fops);

ret=cdev_add(&tcdev,tcdev_t,TCDEV_NUM);

if(ret<0){

         printk(KERN_ERR"tcdev cdev cdev_add is fail\n");

goto tcdev_cdev_add_fail;

}

printk(KERN_INFO"tcdev cdev_add apply is success\n");

return 0;

tcdev_cdev_add_fail:

unregister_chrdev_region(&tcdev,TCDEV_NUM);

 

tcdev_cdev_fail:

return 0;

}


static void __exit tcdev_exit (void)

{

printk(KERN_INFO "tcdev stop ...\n");

cdev_del(&tcdev);

printk(KERN_INFO"tcdev del success\n");

 unregister_chrdev_region(&tcdev,TCDEV_NUM);

printk(KERN_INFO "tcdev dev_num del success\n");

return 0;

}

 

 


module_init(tcdev_init);

module_exit(tcdev_exit);


Makefile


#!/bin/bash


obj-m += testcdev.o



KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0


#當前目錄變量

PWD ?= $(shell pwd)


#make命名默認尋找第一個目標

#make -C就是指調用執行的路徑

#$(KDIR)Linux源碼目錄,作者這裏指的是/home/topeet/android4.0/iTop4412_Kernel_3.0

#$(PWD)當前目錄變量

#modules要執行的操作

all:

        make -C $(KDIR) M=$(PWD) modules

                

#make clean執行的操作是刪除後綴爲o的文件

clean:

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



#include <stdio.h>


#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/ioctl.h>

char buf[20];

/*argv[1] is cmd , argv[2] is io_arg*/

int main(int argc , char **argv){

        int fd;

        char *lednode = "/dev/tcdev";

        if((fd = open(lednode,O_RDWR|O_NDELAY))<0){

                printf("APP open %s failed!\n",lednode);

        }

        else{

                printf("APP open %s success!\n",lednode);

                read(fd,buf,20);

             return 0;          

        }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章