在2.6内核中可以通过用户空间的udev/mdev自动为设备建立节点,省去了手工建立节点的麻烦
1. 传统的手动建立设备节点方法
其实也不是很麻烦,写个建立节点的脚本就行,LDD3中有很多例子
-
#!/bin/sh
-
module="scullp"
-
device="scullp"
-
mode="664"
-
-
# Group: since distributions do it differently, look for wheel or use staff
-
if grep '^staff:' /etc/group > /dev/null; then
-
group="staff"
-
else
-
group="wheel"
-
fi
-
-
# remove stale nodes
-
rm -f /dev/${device}?
-
-
# invoke insmod with all arguments we got
-
# and use a pathname, as newer modutils don't look in . by default
-
/sbin/insmod -f ./$module.ko $* || exit 1
-
-
major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
-
-
mknod /dev/${device}0 c $major 0
-
mknod /dev/${device}1 c $major 1
-
mknod /dev/${device}2 c $major 2
-
mknod /dev/${device}3 c $major 3
-
ln -sf ${device}0 /dev/${device}
-
-
# give appropriate group/permissions
-
chgrp $group /dev/${device}[0-3]
-
chmod $mode /dev/${device}[0-3]
2. 使用udev/mdev机制自动建立节点
2.1 内核API
1.
-
#define class_create(owner, name) \
-
({ \
-
static struct lock_class_key __key; \
-
__class_create(owner, name, &__key); \
-
})
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
2.
点击(此处)折叠或打开
-
extern struct device *device_create(struct class *cls, struct device *parent,
-
dev_t devt, void *drvdata,
-
const char *fmt, ...)
-
__attribute__((format(printf, 5, 6)));
/**
* device_create - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
*
* This function can be used by char device classes. A struct device
* will be created in sysfs, registered to the specified class.
*
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct device is passed in, the newly created
* struct device will be a child of that device in sysfs.
* The pointer to the struct device will be returned from the call.
* Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
3
-
extern void class_destroy(struct class *cls);
/**
* class_destroy - destroys a struct class structure
* @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
*/
4
-
extern void device_destroy(struct class *cls, dev_t devt);
参数含义:
/**
* device_destroy - removes a device that was created with device_create()
* @class: pointer to the struct class that this device was registered with
* @devt: the dev_t of the device that was previously registered
*
* This call unregisters and cleans up a device that was created with a
* call to device_create().
*/
2.2 使用方法
加载驱动时
struct class *myclass ;
class_create(THIS_MODULE, “my_device_driver”);
device_create(myclass, NULL, MKDEV(major_num, minor_num), NULL, “my_device”);
卸载驱动时:
device_destroy(myclass, MKDEV(major_num, minor_num));
class_destroy(my_class);
2.3 例子
-
/*
-
* led.c
-
*/
-
#define DEBUG
-
-
#include <linux/miscdevice.h>
-
#include <linux/delay.h>
-
#include <asm/irq.h>
-
#include <mach/regs-gpio.h>
-
#include <mach/hardware.h>
-
#include <linux/kernel.h>
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/mm.h>
-
#include <linux/fs.h>
-
#include <linux/types.h>
-
#include <linux/delay.h>
-
#include <linux/moduleparam.h>
-
#include <linux/slab.h>
-
#include <linux/errno.h>
-
#include <linux/ioctl.h>
-
#include <linux/cdev.h>
-
#include <linux/string.h>
-
#include <linux/list.h>
-
#include <linux/pci.h>
-
#include <asm/uaccess.h>
-
#include <asm/atomic.h>
-
#include <asm/unistd.h>
-
-
#ifdef DEBUG
-
#define dbg(arg...) printk(KERN_DEBUG arg)
-
#else
-
#define dbg(arg...)
-
#endif
-
-
#define DEVICE_NAME "leds"
-
-
#define NUM_LEDS (4)
-
-
struct led_desc{
-
unsigned long pin;
-
unsigned long cfg;
-
char *name;
-
};
-
-
static struct led_desc leds[] = {
-
{S3C2410_GPB5, S3C2410_GPB5_OUTP, "LED1"},
-
{S3C2410_GPB6,S3C2410_GPB6_OUTP, "LED2"},
-
{S3C2410_GPB7,S3C2410_GPB7_OUTP, "LED3"},
-
{S3C2410_GPB8,S3C2410_GPB8_OUTP, "LED4"},
-
};
-
-
struct led_dev{
-
char *name;
-
unsigned long pin;
-
unsigned long cfg;
-
struct cdev cdev;
-
} *led_devp[NUM_LEDS];
-
-
struct class *led_class;
-
static dev_t led_dev_number;
-
-
static int mini2440_leds_open(struct inode *inode, struct file *filp)
-
{
-
-
struct led_dev *dev;
-
dev = container_of(inode->i_cdev,struct led_dev,cdev);
-
filp->private_data = dev;
-
printk(KERN_DEBUG "%s", __FUNCTION__);
-
return 0;
-
}
-
-
static int mini2440_leds_close(struct inode *node, struct file *filp)
-
{
-
printk(KERN_DEBUG "%s", __FUNCTION__);
-
return 0;
-
}
-
-
static int mini2440_leds_ioctl(struct inode *inode,struct file *filp,
-
unsigned int cmd, unsigned long arg)
-
{
-
struct led_dev *led_devp = filp->private_data;
-
switch(cmd) {
-
case 0:
-
case 1:
-
if (arg > 4) {
-
return -EINVAL;
-
}
-
s3c2410_gpio_setpin(led_devp->pin, !cmd);
-
return 0;
-
default:
-
return -EINVAL;
-
}
-
}
-
-
static struct file_operations led_fops = {
-
.owner = THIS_MODULE,
-
.open = mini2440_leds_open,
-
.release = mini2440_leds_close,
-
.ioctl = mini2440_leds_ioctl,
-
};
-
-
static int __init dev_init(void)
-
{
-
int ret;
-
int i;
-
/* 注册设备,动态分配设备号 */
-
if(alloc_chrdev_region(&led_dev_number, 0, NUM_LEDS, DEVICE_NAME) < 0){
-
printk(KERN_DEBUG "Can't register device.\n");
-
return -1;
-
}
-
/* 创建sysfs 目录 */
-
led_class = class_create(THIS_MODULE, DEVICE_NAME);
-
/* 配置gpio */
-
for (i = 0; i < 4; i++) {
-
led_devp[i] = kmalloc(sizeof(struct led_dev),GFP_KERNEL);
-
if(!led_devp[i]){
-
printk("Bad Kmalloc.\n");
-
return -ENOMEM;
-
}
-
led_devp[i]->pin = leds[i].pin;
-
led_devp[i]->cfg = leds[i].cfg;
-
led_devp[i]->name = leds[i].name;
-
s3c2410_gpio_cfgpin(led_devp[i]->pin, led_devp[i]->cfg);
-
s3c2410_gpio_setpin(led_devp[i]->pin, 0);
-
-
/* 绑定fops与cdev */
-
cdev_init(&led_devp[i]->cdev, &led_fops);
-
led_devp[i]->cdev.owner = THIS_MODULE;
-
/* 绑定设备号与cdev */
-
ret = cdev_add(&led_devp[i]->cdev, led_dev_number + i, 1);
-
if(ret){
-
printk("Bad cdev\n");
-
return ret;
-
}
-
-
/* sysfs */
-
device_create(led_class, NULL, MKDEV(MAJOR(led_dev_number),i ), led_devp[i],"led%d" , i);
-
}
-
printk (DEVICE_NAME"\tinitialized\n");
-
-
return 0;
-
}
-
-
static void __exit dev_exit(void)
-
{
-
int i;
-
unregister_chrdev_region(led_dev_number, NUM_LEDS);
-
-
for (i = 0; i < NUM_LEDS; ++i)
-
{
-
device_destroy(led_class, MKDEV(MAJOR(led_dev_number), i));
-
cdev_del(&led_devp[i]->cdev);
-
kfree(led_devp[i]);
-
}
-
-
class_destroy(led_class);
-
-
}
-
-
module_init(dev_init);
-
module_exit(dev_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("EnzoFang");
-
/*
-
* test_led.c
-
*/
-
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <sys/ioctl.h>
-
#include <fcntl.h>
-
#include <stdlib.h>
-
struct bit{
-
unsigned bit:1;
-
};
-
-
int main(int argc, char *argv[])
-
{
-
struct bit a;
-
a.bit = 0;
-
int fd0 = open("/dev/led0", O_RDWR);
-
int fd1 = open("/dev/led1", O_RDWR);
-
int fd2 = open("/dev/led2", O_RDWR);
-
int fd3 = open("/dev/led3", O_RDWR);
-
while(1){
-
a.bit = ~a.bit;
-
ioctl(fd0, a.bit);
-
sleep(1);
-
-
ioctl(fd1, a.bit);
-
sleep(1);
-
-
ioctl(fd2, a.bit);
-
sleep(1);
-
ioctl(fd3, a.bit);
-
sleep(1);
-
-
}
-
-
return 0;
-
}
结果:
在使用busybox制作根文件系统需要支持mdev,并且在rcS中有以下语句
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
才能在加载驱动时,自动生成节点
-
# cd leds/
-
# pwd
-
/sys/class/leds
-
# ls
-
led0 led1 led2 led3
阅读(749) | 评论(0) | 转发(0) |