LED驱动

LED驱动程序


文章目录

  • LED驱动程序
    • 1:目的
    • 2:引入知识:
    • 3:实现方式/流程:
    • 4:需要的接口函数:
      • 4.1 驱动实现
        • struct file_operations
        • register_chrdev()
        • class_create()
        • class_device_create()
        • copy_from_user()
        • ioremap()
        • module_init();
        • module_exit();
        • MODULE_LICENSE("GPL");
      • 4.2 应用程序
        • open("/dev/xyz",O_RDWR);
        • write(fd,&val,4);

1:目的

  • 目的
    可用的驱动程序模块–>>LED灯

2:引入知识:

  • 结构体 file_operations
    该结构体作为驱动程序的最基本的结构体,是连接系统调用函数sys_read,sys_read,sys_open等等操作与实际硬件的节点;透过对该结构体的填充,即在该结构体实现函数,完成系统函数对底层相应函数的调用;
  • 设备节点与驱动类
    设备节点即应用程序在调用某一函数时所需要指向的节点,应用程序通过调用某一设备节点打开驱动程序注册的相应的设备;
  • 入口修饰
    用来在加载驱动时使系统找到该驱动的入口函数,是由驱动在装载时自动完成。

3:实现方式/流程:

  • 声明一个file_operations结构体用于填充;实现各个函数;
  • 实现结构体所需要的填充的函数:如:read(),write(),open();
  • 在入口函数drv_init()中实现,注册字符设备驱动、注册驱动类、注册设备节点;
  • 在出口函数drv_exit()中实现,卸载设备驱动,卸载设备节点等;
  • 将实际地址映射成虚拟地址供系统使用;

4:需要的接口函数:

4.1 驱动实现

struct file_operations

/*
 * NOTE:
 * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
 * can be called without the big kernel lock held in all filesystems.
 * 文件操作结构体
 */
struct file_operations {
	struct module *owner;
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//读函数,sys_read会调用次函数
	
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//写函数,sys_write调用
	
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	//poll函数,实现poll机制是,poll函数调用的
	
	int (*open) (struct inode *, struct file *);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, struct dentry *, int datasync);
};

register_chrdev()

/**
 * register_chrdev() - Register a major number for character devices.
 * @major: major device number or 0 for dynamic allocation
 * @name: name of this range of devices
 * @fops: file operations associated with this devices
 *
 * If @major == 0 this functions will dynamically allocate a major and return its number.
 *
 * If @major > 0 this function will attempt to reserve a device with the given major number and will return zero on success.
 *
 * Returns a -ve errno on failure.
 * 
 * The name of this device has nothing to do with the name of the device in /dev. It only helps to keep track of the different owners of devices. If your module name has only one type of devices it's ok to use e.g. the name of the module here.
 *
 * This function registers a range of 256 minor numbers. The first minor number is 0.
 * 字符型驱动设备函数,该函数注册驱动程序,告诉内核
 */
int register_chrdev(unsigned int major, const char *name,
		    const struct file_operations *fops)
{
	struct char_device_struct *cd;
	struct cdev *cdev;
	char *s;
	int err = -ENOMEM;

	cd = __register_chrdev_region(major, 0, 256, name);
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	
	cdev = cdev_alloc();
	if (!cdev)
		goto out2;

	cdev->owner = fops->owner;
	cdev->ops = fops;
	kobject_set_name(&cdev->kobj, "%s", name);
	for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
		*s = '!';
		
	err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
	if (err)
		goto out;

	cd->cdev = cdev;

	return major ? 0 : cd->major;
out:
	kobject_put(&cdev->kobj);
out2:
	kfree(__unregister_chrdev_region(cd->major, 0, 256));
	return err;
}
  • unregister_chrdev()
int unregister_chrdev(unsigned int major, const char *name)
{
	struct char_device_struct *cd;
	cd = __unregister_chrdev_region(major, 0, 256);
	if (cd && cd->cdev)
		cdev_del(cd->cdev);
	kfree(cd);
	return 0;
}

class_create()

/**
 * class_create - create a struct class structure
 * @owner: pointer to the module that is to "own" this struct class
 * @name: pointer to a string for the name of this class.
 *
 * This is used to create a struct class pointer that can then be used
 * in calls to class_device_create().
 *
 * Note, the pointer created here is to be destroyed when finished by
 * making a call to class_destroy().
 */
struct class *class_create(struct module *owner, const char *name)
{
	struct class *cls;
	int retval;

	cls = kzalloc(sizeof(*cls), GFP_KERNEL);
	if (!cls) {
		retval = -ENOMEM;
		goto error;
	}

	cls->name = name;
	cls->owner = owner;
	cls->class_release = class_create_release;
	cls->release = class_device_create_release;

	retval = class_register(cls);
	if (retval)
		goto error;

	return cls;

error:
	kfree(cls);
	return ERR_PTR(retval);
}
  • class_destroy()
/*
 * 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().
 */
void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}

class_device_create()

/**
 * class_device_create - creates a class device and registers it with sysfs
 * @cls: pointer to the struct class that this device should be registered to.
 * @parent: pointer to the parent struct class_device of this new device, if any.
 * @devt: the dev_t for the char device to be added.
 * @device: a pointer to a struct device that is assiociated with this class device.
 * @fmt: string for the class device's name
 *
 * This function can be used by char device classes.  A struct
 * class_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 class_device is passed in, the newly
 * created struct class_device will be a child of that device in sysfs.
 * The pointer to the struct class_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().
 */
struct class_device *class_device_create(struct class *cls,
					 struct class_device *parent,
					 dev_t devt,
					 struct device *device,
					 const char *fmt, ...)
{
	va_list args;
	struct class_device *class_dev = NULL;
	int retval = -ENODEV;

	if (cls == NULL || IS_ERR(cls))
		goto error;

	class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
	if (!class_dev) {
		retval = -ENOMEM;
		goto error;
	}

	class_dev->devt = devt;
	class_dev->dev = device;
	class_dev->class = cls;
	class_dev->parent = parent;
	class_dev->release = class_device_create_release;
	class_dev->uevent = class_device_create_uevent;

	va_start(args, fmt);
	vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
	va_end(args);
	retval = class_device_register(class_dev);
	if (retval)
		goto error;

	return class_dev;

error:
	kfree(class_dev);
	return ERR_PTR(retval);
}

  • class_device_unregister() 删除设备节点
void class_device_unregister(struct class_device *class_dev)
{
	pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
		 class_dev->class_id);
	class_device_del(class_dev);
	class_device_put(class_dev);
}

copy_from_user()

#define copy_from_user(to, from, n)	__copy_from_user (to, from, n)
//将数据从user空间copy到驱动程序
  • copy_to_user()
#define copy_to_user(to, from, n) 	__copy_to_user(to, from, n)

ioremap()

/*
*地址映射
*/
static inline void __iomem * ioremap (unsigned long offset, unsigned long size)
{
	return __ioremap(offset, size, 0);
}
  • iounmap(addr)

module_init();

入口函数修饰

module_exit();

出口函数修饰

MODULE_LICENSE(“GPL”);

描述驱动程序的一些信息

4.2 应用程序

open("/dev/xyz",O_RDWR);

write(fd,&val,4);

你可能感兴趣的:(ARM学习)