導航:首頁 > 版本升級 > 創建設備文件cdevadd

創建設備文件cdevadd

發布時間:2023-03-29 20:55:09

㈠ 如何手動創建一個設備節點,寫出主要命令及參數

linux下生成驅動設備節點文件的方法有3個:1、手動mknod;2、利用devfs;3、利用udev
在剛開始寫Linux設備驅動程序的時候,很多時候都是利用mknod命令手動創建設備節點,實際上Linux內核為我們提供了一組函數,可以用來在模塊載入的時候自動在/dev目錄下創建相應設備節點,並在卸載模塊時刪除該節點。
在2.6.17以前,在/dev目錄下生成設備文件很容易,
devfs_mk_bdev
devfs_mk_cdev
devfs_mk_symlink
devfs_mk_dir
devfs_remove
這幾個是純devfs的api,2.6.17以前可用,但後來devfs被sysfs+udev的形式取代,同時期sysfs文件系統可以用的api:
class_device_create_file,在2.6.26以後也不行了,現在,使用的是device_create ,從2.6.18開始可用
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, const char *fmt, ...)
從2.6.26起又多了一個參數drvdata: the data to be added to the device for callbacks
不會用可以給此參數賦NULL
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)

下面著重講解第三種方法udev
在驅動用加入對udev的支持主要做的就是:在驅動初始化的代碼里調用class_create(...)為該設備創建一個class,再為每個設備調用device_create(...)( 在2.6較早的內核中用class_device_create)創建對應的設備。
內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變數對應一個類,內核同時提供了class_create(…)函數,可以用它來創建一個類,這個類存放於sysfs下面,一旦創建好了這個類,再調用 device_create(…)函數來在/dev目錄下創建相應的設備節點。這樣,載入模塊的時候,用戶空間中的udev會自動響應 device_create(…)函數,去/sysfs下尋找對應的類從而創建設備節點。
struct class和class_create(…) 以及device_create(…)都包含在在/include/linux/device.h中,使用的時候一定要包含這個頭文件,否則編譯器會報錯。
struct class定義在頭文件include/linux/device.h中
class_create(…)在/drivers/base/class.c中實現
device_create(…)函數在/drivers/base/core.c中實現
class_destroy(...),device_destroy(...)也在/drivers/base/core.c中實現調用過程類似如下:
static struct class *spidev_class;

/*-------------------------------------------------------------------------*/

static int __devinit spidev_probe(struct spi_device *spi)
{
....

dev =device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num, spi->chip_select);
...
}

static int __devexit spidev_remove(struct spi_device *spi)
{
......
device_destroy(spidev_class, spidev->devt);
.....

return 0;
}

static struct spi_driver spidev_spi = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),

};

/*-------------------------------------------------------------------------*/

static int __init spidev_init(void)
{
....

spidev_class =class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
return PTR_ERR(spidev_class);
}
....
}
mole_init(spidev_init);

static void __exit spidev_exit(void)
{
......
class_destroy(spidev_class);
......
}
mole_exit(spidev_exit);

MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");

下面以一個簡單字元設備驅動來展示如何使用這幾個函數
#include <linux/mole.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

int HELLO_MAJOR = 0;
int HELLO_MINOR = 0;
int NUMBER_OF_DEVICES = 2;

struct class *my_class;
//struct cdev cdev;
//dev_t devno;

struct hello_dev {
struct device *dev;
dev_t chrdev;
struct cdev cdev;
};
static struct hello_dev *my_hello_dev = NULL;
struct file_operations hello_fops = {
.owner = THIS_MODULE
};

static int __init hello_init (void)
{
int err = 0;
struct device *dev;
my_hello_dev = kzalloc(sizeof(struct hello_dev), GFP_KERNEL);
if (NULL == my_hello_dev) {
printk("%s kzalloc failed!\n",__func__);
return -ENOMEM;
}
devno = MKDEV(HELLO_MAJOR, HELLO_MINOR);
if (HELLO_MAJOR)
err= register_chrdev_region(my_hello_dev->chrdev, 2, "memdev");
else
{
err = alloc_chrdev_region(&my_hello_dev->chrdev, 0, 2, "memdev");
HELLO_MAJOR = MAJOR(devno);
}
if (err) {
printk("%s alloc_chrdev_region failed!\n",__func__);
goto alloc_chrdev_err;
}
printk("MAJOR IS %d\n",HELLO_MAJOR);
cdev_init(&(my_hello_dev->cdev), &hello_fops);
my_hello_dev->cdev.owner = THIS_MODULE;
err = cdev_add(&(my_hello_dev->cdev), my_hello_dev->chrdev, 1);
if (err) {
printk("%s cdev_add failed!\n",__func__);
goto cdev_add_err;
}
printk (KERN_INFO "Character driver Registered\n");
my_class =class_create(THIS_MODULE,"hello_char_class"); //類名為hello_char_class
if(IS_ERR(my_class))
{
err = PTR_ERR(my_class);
printk("%s class_create failed!\n",__func__);
goto class_err;
}
dev = device_create(my_class,NULL,my_hello_dev->chrdev,NULL,"memdev%d",0); //設備名為memdev
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
gyro_err("%s device_create failed!\n",__func__);
goto device_err;
}
printk("hello mole initialization\n");
return 0;

device_err:
device_destroy(my_class, my_hello_dev->chrdev);
class_err:
cdev_del(my_hello_dev->chrdev);
cdev_add_err:
unregister_chrdev_region(my_hello_dev->chrdev, 1);
alloc_chrdev_err:
kfree(my_hello_dev);
return err;
}

static void __exit hello_exit (void)
{
cdev_del (&(my_hello_dev->cdev));
unregister_chrdev_region (my_hello_dev->chrdev,1);
device_destroy(my_class, devno); //delete device node under /dev//必須先刪除設備,再刪除class類
class_destroy(my_class); //delete class created by us
printk (KERN_INFO "char driver cleaned up\n");
}

mole_init (hello_init);
mole_exit (hello_exit);

MODULE_LICENSE ("GPL");
這樣,模塊載入後,就能在/dev目錄下找到memdev這個設備節點了。
例2:內核中的drivers/i2c/i2c-dev.c
在i2cdev_attach_adapter中調用device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
這樣在dev目錄就產生i2c-0 或i2c-1節點

接下來就是udev應用,udev是應用層的東西,udev需要內核sysfs和tmpfs的支持,sysfs為udev提供設備入口和uevent通道,tmpfs為udev設備文件提供存放空間
udev的源碼可以在去相關網站下載,然後就是對其在運行環境下的移植,指定交叉編譯環境,修改Makefile下的CROSS_COMPILE,如為mipsel-linux-,DESTDIR=xxx,或直接make CROSS_COMPILE=mipsel-linux-,DESTDIR=xxx 並install
把主要生成的udevd、udevstart拷貝rootfs下的/sbin/目錄內,udev的配置文件udev.conf和rules.d下的rules文件拷貝到rootfs下的/etc/目錄內
並在rootfs/etc/init.d/rcS中添加以下幾行:
echo 「Starting udevd...」
/sbin/udevd --daemon
/sbin/udevstart
(原rcS內容如下:
# mount filesystems
/bin/mount -t proc /proc /proc
/bin/mount -t sysfs sysfs /sys
/bin/mount -t tmpfs tmpfs /dev
# create necessary devices
/bin/mknod /dev/null c 1 3
/bin/mkdir /dev/pts
/bin/mount -t devpts devpts /dev/pts
/bin/mknod /dev/audio c 14 4
/bin/mknod /dev/ts c 10 16

這樣當系統啟動後,udevd和udevstart就會解析配置文件,並自動在/dev下創建設備節點文件

㈡ arm linux驅動程序和應用程序之間的一些問題

我不知道你用的那個版本的kernel,但是據我所知,ioctl的cmd參數的定義,不是你那麼簡單的....

需要用到ioctl的命令字定義的幾個宏定義...

自己定義是沒有用的,因為ioctl需要知道你的命令是io讀還是io寫..

比如在我的程序裡面我這樣定義命令字...

你自己查一下_IOW,_IO這兩個宏...

#include <linux/ioctl.h>//使用下面的宏

#define DEVICE_NAME "/dev/test_device"
#define TEST_MAGIC_NUM 'k'
#define PORT_SET _IOW(TEST_MAGIC_NUM,1,int)
#define PORT_GET _IO(TEST_MAGIC_NUM,2)
#define PORT_LOCK _IO(TEST_MAGIC_NUM,3)

你的應用程序中,也應該把這樣定義的命令字給包含進去...這兩個個宏的意義是,不要和系統已經使用ioctl的cmd重復...因為ioctl介面並不是僅僅給你使用的.你自己寫的命令字會把系統原有的給覆蓋...

㈢ Linux下codeblocks如何調用Linux中的設備注冊函數例如cdev_add()函數

struct cdev *my_cdev = cdev_alloc( );
my_cdev->ops = &my_fops;

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

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

struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};

㈣ 寫linux驅動的請幫我看看,我這個程序怎麼創建不了設備文件

參考答案 智者不惑,仁者不憂,勇者不懼。--孔子

㈤ 字元驅動設備中幾個重要的結構體(cdev,file

1. cdev結構體

[cpp]view plain

㈥ cdev結構代表著什麼

代表字元設備

㈦ 兩個注冊設備驅動的函數有什麼區別

register_chrdev的作用是向內核申請分配一個單獨渣脊核主設備號和范圍在 0 ~ 255 的次設如掘備號,野笑如果申請的主設備號為 0 則內核會動態分配一個;cdev_add是向內核添加一個cdev結構;完全兩碼事。 查看原帖>>

㈧ android gpio 怎麼分配

驅動程序初始化和退出
static int simple_major = 250;//默認的設備號碼,如果為0則嘗試自動分配

……

/*

* Set up the cdev structure for a device.

*/

static void simple_setup_cdev(struct cdev *dev, int minor,

struct file_operations *fops)//自編的函高爛數,注冊字元設備

{

int err, devno = MKDEV(simple_major, minor);//建立設備號

cdev_init(dev, fops);//初始化設備結構體struct cdev *dev

dev->owner = THIS_MODULE;

dev->ops = fops;//關衫野聯fops

err = cdev_add (dev, devno, 1);//注冊一個字元設備

/* Fail gracefully if need be */

if (err)//注冊失敗處理

printk (KERN_NOTICE "Error %d adding simple%d", err, minor);

}

/*

* Our various sub-devices.

*/

/* Device 0 uses remap_pfn_range */

static struct file_operations simple_remap_ops = { //定義設備的fops

.owner = THIS_MODULE,

.open = simple_open,

.release = simple_release,

.read = simple_read,

.write = simple_write,

.ioctl = simple_ioctl,

};/*

* We export two simple devices. There's no need for us to maintain any

* special housekeeping info, so we just deal with raw cdevs.

*/

static struct cdev SimpleDevs;/*

* Mole housekeeping.

*/

static struct class *my_class;

static int simple_init(void)

{
int result;

dev_t dev = MKDEV(simple_major, 0);//將設備號轉化為dev_t的結構

/* Figure out our device number. */

if (simple_major)

result = register_chrdev_region(dev, 1, "simple");//嘗試申請主設備號

else {

result = alloc_chrdev_region(&dev, 0, 1, "simple");//請求自動分配主設備號,起始值是0,總共分配1個或念喊,設備名simple

simple_major = MAJOR(dev);//將分配成功的設備號保存在simple_major變數中

}

if (result < 0) {//分配主設備號失敗

printk(KERN_WARNING "simple: unable to get major %d\n", simple_major);

return result;

}

if (simple_major == 0)//將返回值記錄為主設備號。需要麼?

simple_major = result;

/* Now set up two cdevs. */

simple_setup_cdev(&SimpleDevs, 0, &simple_remap_ops);//調用自編的函數注冊字元設備,有Bug沒有返回注冊是否成功。

printk("simple device installed, with major %d\n", simple_major);//Bug:列印前應該檢查注冊是否成功?

my_class= class_create(THIS_MODULE, "simple");//建立一個叫simple的內核class,目的是下一步創建設備節點文件

device_create(my_class, NULL, MKDEV(simple_major, 0),

NULL, "led");//創建設備節點文件

return 0;

}


static void simple_cleanup(void)

{

cdev_del(&SimpleDevs);//刪除字元設備

unregister_chrdev_region(MKDEV(simple_major, 0), 1);//注銷主設備號

device_destroy(my_class,MKDEV(simple_major,0));//刪除設備節點

printk("simple device uninstalled\n");

}mole_init(simple_init);

mole_exit(simple_cleanup);

㈨ 嵌入式linux設備驅動,無法打開設備文件

1. ls /dev/* 看看有沒有你的LED節點
2.cat /proc/devices 看看有沒有相關LED驅動信息。

===============================
static const struct file_operations fops_led =
{
.owner = THIS_MODULE,
//.open = open_led,
.unlocked_ioctl = unlocked_ioctl_led,
};

都屏蔽了open函數,內怎麼打開容?

㈩ 請問linux2.6內核驅動程序的自動創建設備節點的 class_create device_create 創建設備問題。

是這么回事,當你自己要寫一個字元設備或者看別人寫的是字元設備時內,要定義一個字元容設備的結構體struct cdev{/*裡面是一些字元設備的相關屬性,包括file_operations結構體,設備號等等*/},然後調用register_chrdev_region(),申請設備號,再用cdev_add()想內核注冊設備,這里,內核就知道你要注冊的就是字元設備了,同理,如果是塊設備的話用register_blkdev()來注冊塊設備,經過一系列的初始化後添加add_disk(),內核也就知道你添加的是塊設備了

閱讀全文

與創建設備文件cdevadd相關的資料

熱點內容
怎麼限制網路電視 瀏覽:888
nvr配置文件是什麼意思 瀏覽:600
農業農村部網站怎麼查 瀏覽:107
宏編程滑鼠玩cf如何調節好 瀏覽:465
天津廣電網路怎麼在電視操作退費 瀏覽:62
什麼網站可以在電視上使用 瀏覽:737
技嘉gaa55mds2升級 瀏覽:643
招財狗手機找密碼 瀏覽:213
如何打開pdf內嵌的文件 瀏覽:763
sap網路不行登陸不上怎麼解決 瀏覽:80
js動態循環寫html代碼 瀏覽:900
定時器怎麼對待編程 瀏覽:966
閔行區哪裡可以學數控編程 瀏覽:220
如何把電腦保存文件的路徑改為d盤 瀏覽:207
如何讓word文字橫向顯示出來 瀏覽:864
文件夾中的pdf不在了 瀏覽:936
資料庫統計軟體 瀏覽:984
win10文件後戳怎麼顯示 瀏覽:58
配置文件概要 瀏覽:706
c編程考試用什麼搜答案 瀏覽:670

友情鏈接