㈠ 如何手動創建一個設備節點,寫出主要命令及參數
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
structcdev{
structkobjectkobj;//內嵌的kobject對象
structmole*owner;//所屬模板
conststructfile_operations*ops;//文件操作的結構體
structlist_headlist;
dev_tdev;//設備號
unsignedintcount;
};
1.1 cdev的相關操作
[cpp]view plain
voidcdev_init(structcdev*,conststructfile_operations*);//初始化使其和文件操作結構相連接
structcdev橡沖巧*cdev_alloc(void);//為cdev分配內存
intcdev_add(structcdev*,dev_t,unsigned);//向內核注冊一個設備
voidcdev_del(structcdev*);//從內梁鍵核刪除一個設備
1.2 設備號的分配
1.21 主次設備號和dev_t的相互轉換
由dev_t號獲取主次設備號
[cpp]view plain
MAJOR(dev_tdev)
MINOR(dev_tdev)
由主次設備號獲得dev_t
[cpp]view plain
MKDEV(intmajor,intminor)
1.22 獲取及注銷設備號
[cpp]view plain
<spanstyle="font-size:14px;">intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name);//手動注冊
intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name);//由內核分配
voinregion_chrdev_region(dev_tfrom,unsignedcount);//注銷設判納備號</span>
㈥ 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(),內核也就知道你添加的是塊設備了