编辑
2024-08-25
学习记录
0
请注意,本文编写于 243 天前,最后修改于 243 天前,其中某些信息可能已经过时。

目录

1.hello drv
2.hellodrvtrans
3template1gpiodrv
4template2platformdts
5template3_i2c
6template3_spi

1.hello drv

c++
#include <linux/mm.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/mman.h> #include <linux/random.h> #include <linux/init.h> #include <linux/raw.h> #include <linux/tty.h> #include <linux/capability.h> #include <linux/ptrace.h> #include <linux/device.h> #include <linux/highmem.h> #include <linux/backing-dev.h> #include <linux/shmem_fs.h> #include <linux/splice.h> #include <linux/pfn.h> #include <linux/export.h> #include <linux/io.h> #include <linux/uio.h> #include <linux/uaccess.h> static int major; static int hello_open (struct inode *node, struct file *filp) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return size; } static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return size; } static int hello_release (struct inode *node, struct file *filp) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } /* 1. create file_operations */ static const struct file_operations hello_drv = { .owner = THIS_MODULE, .read = hello_read, .write = hello_write, .open = hello_open, .release = hello_release, }; /* 2. register_chrdev */ /* 3. entry function */ static int hello_init(void) { major = register_chrdev(0, "100ask_hello", &hello_drv); return 0; } /* 4. exit function */ static void hello_exit(void) { unregister_chrdev(major, "100ask_hello"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");

2.hello_drv_trans

c++
#include "asm/cacheflush.h" #include <linux/mm.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/mman.h> #include <linux/random.h> #include <linux/init.h> #include <linux/raw.h> #include <linux/tty.h> #include <linux/capability.h> #include <linux/ptrace.h> #include <linux/device.h> #include <linux/highmem.h> #include <linux/backing-dev.h> #include <linux/shmem_fs.h> #include <linux/splice.h> #include <linux/pfn.h> #include <linux/export.h> #include <linux/io.h> #include <linux/uio.h> #include <linux/uaccess.h> static struct class *hello_class; static int major; static unsigned char hello_buf[100]; static int hello_open (struct inode *node, struct file *filp) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset) { unsigned long len = size > 100 ? 100 : size; printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); copy_to_user(buf, hello_buf, len); return len; } static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset) { unsigned long len = size > 100 ? 100 : size; printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); copy_from_user(hello_buf, buf, len); return len; } static int hello_release (struct inode *node, struct file *filp) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } /* 1. create file_operations */ static const struct file_operations hello_drv = { .owner = THIS_MODULE, .read = hello_read, .write = hello_write, .open = hello_open, .release = hello_release, }; /* 2. register_chrdev */ /* 3. entry function */ static int hello_init(void) { major = register_chrdev(0, "100ask_hello", &hello_drv); hello_class = class_create(THIS_MODULE, "hello_class"); if (IS_ERR(hello_class)) { printk("failed to allocate class\n"); return PTR_ERR(hello_class); } device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */ return 0; } /* 4. exit function */ static void hello_exit(void) { device_destroy(hello_class, MKDEV(major, 0)); class_destroy(hello_class); unregister_chrdev(major, "100ask_hello"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");

3template1_gpio_drv

c++
#include <linux/module.h> #include <linux/poll.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/timer.h> struct gpio_desc{ int gpio; int irq; char *name; int key; struct timer_list key_timer; } ; static struct gpio_desc gpios[2] = { {131, 0, "gpio_100ask_1", }, {132, 0, "gpio_100ask_2", }, }; /* 主设备号 */ static int major = 0; static struct class *gpio_class; /* 环形缓冲区 */ #define BUF_LEN 128 static int g_keys[BUF_LEN]; static int r, w; struct fasync_struct *button_fasync; #define NEXT_POS(x) ((x+1) % BUF_LEN) static int is_key_buf_empty(void) { return (r == w); } static int is_key_buf_full(void) { return (r == NEXT_POS(w)); } static void put_key(int key) { if (!is_key_buf_full()) { g_keys[w] = key; w = NEXT_POS(w); } } static int get_key(void) { int key = 0; if (!is_key_buf_empty()) { key = g_keys[r]; r = NEXT_POS(r); } return key; } static DECLARE_WAIT_QUEUE_HEAD(gpio_wait); // static void key_timer_expire(struct timer_list *t) static void key_timer_expire(unsigned long data) { /* data ==> gpio */ // struct gpio_desc *gpio_desc = from_timer(gpio_desc, t, key_timer); struct gpio_desc *gpio_desc = (struct gpio_desc *)data; int val; int key; val = gpio_get_value(gpio_desc->gpio); //printk("key_timer_expire key %d %d\n", gpio_desc->gpio, val); key = (gpio_desc->key) | (val<<8); put_key(key); wake_up_interruptible(&gpio_wait); kill_fasync(&button_fasync, SIGIO, POLL_IN); } /* 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); int err; int key; if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK)) return -EAGAIN; wait_event_interruptible(gpio_wait, !is_key_buf_empty()); key = get_key(); err = copy_to_user(buf, &key, 4); return 4; } static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { unsigned char ker_buf[2]; int err; if (size != 2) return -EINVAL; err = copy_from_user(ker_buf, buf, size); if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0])) return -EINVAL; gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]); return 2; } static unsigned int gpio_drv_poll(struct file *fp, poll_table * wait) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, &gpio_wait, wait); return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; } static int gpio_drv_fasync(int fd, struct file *file, int on) { if (fasync_helper(fd, file, on, &button_fasync) >= 0) return 0; else return -EIO; } /* 定义自己的file_operations结构体 */ static struct file_operations gpio_key_drv = { .owner = THIS_MODULE, .read = gpio_drv_read, .write = gpio_drv_write, .poll = gpio_drv_poll, .fasync = gpio_drv_fasync, }; static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_desc *gpio_desc = dev_id; printk("gpio_key_isr key %d irq happened\n", gpio_desc->gpio); mod_timer(&gpio_desc->key_timer, jiffies + HZ/5); return IRQ_HANDLED; } /* 在入口函数 */ static int __init gpio_drv_init(void) { int err; int i; int count = sizeof(gpios)/sizeof(gpios[0]); printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); for (i = 0; i < count; i++) { gpios[i].irq = gpio_to_irq(gpios[i].gpio); setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]); //timer_setup(&gpios[i].key_timer, key_timer_expire, 0); gpios[i].key_timer.expires = ~0; add_timer(&gpios[i].key_timer); err = request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpios[i]); } /* 注册file_operations */ major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv); /* /dev/gpio_desc */ gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class"); if (IS_ERR(gpio_class)) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "100ask_gpio_key"); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio"); /* /dev/100ask_gpio */ return err; } /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ static void __exit gpio_drv_exit(void) { int i; int count = sizeof(gpios)/sizeof(gpios[0]); printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); device_destroy(gpio_class, MKDEV(major, 0)); class_destroy(gpio_class); unregister_chrdev(major, "100ask_gpio_key"); for (i = 0; i < count; i++) { free_irq(gpios[i].irq, &gpios[i]); del_timer(&gpios[i].key_timer); } } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(gpio_drv_init); module_exit(gpio_drv_exit); MODULE_LICENSE("GPL");

4template2_platform_dts

c++
#include <linux/module.h> #include <linux/poll.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/timer.h> struct gpio_desc{ int gpio; int irq; char name[128]; int key; struct timer_list key_timer; } ; static struct gpio_desc *gpios; static int count; /* 主设备号 */ static int major = 0; static struct class *gpio_class; /* 环形缓冲区 */ #define BUF_LEN 128 static int g_keys[BUF_LEN]; static int r, w; struct fasync_struct *button_fasync; #define NEXT_POS(x) ((x+1) % BUF_LEN) static int is_key_buf_empty(void) { return (r == w); } static int is_key_buf_full(void) { return (r == NEXT_POS(w)); } static void put_key(int key) { if (!is_key_buf_full()) { g_keys[w] = key; w = NEXT_POS(w); } } static int get_key(void) { int key = 0; if (!is_key_buf_empty()) { key = g_keys[r]; r = NEXT_POS(r); } return key; } static DECLARE_WAIT_QUEUE_HEAD(gpio_wait); // static void key_timer_expire(struct timer_list *t) static void key_timer_expire(unsigned long data) { /* data ==> gpio */ // struct gpio_desc *gpio_desc = from_timer(gpio_desc, t, key_timer); struct gpio_desc *gpio_desc = (struct gpio_desc *)data; int val; int key; val = gpio_get_value(gpio_desc->gpio); //printk("key_timer_expire key %d %d\n", gpio_desc->gpio, val); key = (gpio_desc->key) | (val<<8); put_key(key); wake_up_interruptible(&gpio_wait); kill_fasync(&button_fasync, SIGIO, POLL_IN); } /* 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); int err; int key; if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK)) return -EAGAIN; wait_event_interruptible(gpio_wait, !is_key_buf_empty()); key = get_key(); err = copy_to_user(buf, &key, 4); return 4; } static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { unsigned char ker_buf[2]; int err; if (size != 2) return -EINVAL; err = copy_from_user(ker_buf, buf, size); if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0])) return -EINVAL; gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]); return 2; } static unsigned int gpio_drv_poll(struct file *fp, poll_table * wait) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, &gpio_wait, wait); return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; } static int gpio_drv_fasync(int fd, struct file *file, int on) { if (fasync_helper(fd, file, on, &button_fasync) >= 0) return 0; else return -EIO; } /* 定义自己的file_operations结构体 */ static struct file_operations gpio_key_drv = { .owner = THIS_MODULE, .read = gpio_drv_read, .write = gpio_drv_write, .poll = gpio_drv_poll, .fasync = gpio_drv_fasync, }; static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_desc *gpio_desc = dev_id; printk("gpio_key_isr key %d irq happened\n", gpio_desc->gpio); mod_timer(&gpio_desc->key_timer, jiffies + HZ/5); return IRQ_HANDLED; } /* 在入口函数 */ static int gpio_drv_probe(struct platform_device *pdev) { int err = 0; int i; struct device_node *np = pdev->dev.of_node; struct resource *res; printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); /* 从platfrom_device获得引脚信息 * 1. pdev来自c文件 * 2. pdev来自设备树 */ if (np) { /* pdev来自设备树 : 示例 reg_usb_ltemodule: regulator@1 { compatible = "100ask,gpiodemo"; gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>, <&gpio5 3 GPIO_ACTIVE_HIGH>; }; */ count = of_gpio_count(np); if (!count) return -EINVAL; gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL); for (i = 0; i < count; i++) { gpios[i].gpio = of_get_gpio(np, i); sprintf(gpios[i].name, "%s_pin_%d", np->name, i); } } else { /* pdev来自c文件 static struct resource omap16xx_gpio3_resources[] = { { .start = 115, .end = 115, .flags = IORESOURCE_IRQ, }, { .start = 118, .end = 118, .flags = IORESOURCE_IRQ, }, }; */ count = 0; while (1) { res = platform_get_resource(pdev, IORESOURCE_IRQ, count); if (res) { count++; } else { break; } } if (!count) return -EINVAL; gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL); for (i = 0; i < count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); gpios[i].gpio = res->start; sprintf(gpios[i].name, "%s_pin_%d", pdev->name, i); } } for (i = 0; i < count; i++) { gpios[i].irq = gpio_to_irq(gpios[i].gpio); setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]); //timer_setup(&gpios[i].key_timer, key_timer_expire, 0); gpios[i].key_timer.expires = ~0; add_timer(&gpios[i].key_timer); err = request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpios[i]); } /* 注册file_operations */ major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv); /* /dev/gpio_desc */ gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class"); if (IS_ERR(gpio_class)) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "100ask_gpio_key"); return PTR_ERR(gpio_class); } device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio"); /* /dev/100ask_gpio */ return err; } /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ static int gpio_drv_remove(struct platform_device *pdev) { int i; printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); device_destroy(gpio_class, MKDEV(major, 0)); class_destroy(gpio_class); unregister_chrdev(major, "100ask_gpio_key"); for (i = 0; i < count; i++) { free_irq(gpios[i].irq, &gpios[i]); del_timer(&gpios[i].key_timer); } return 0; } static const struct of_device_id gpio_dt_ids[] = { { .compatible = "100ask,gpiodemo", }, { /* sentinel */ } }; static struct platform_driver gpio_platform_driver = { .driver = { .name = "100ask_gpio_plat_drv", .of_match_table = gpio_dt_ids, }, .probe = gpio_drv_probe, .remove = gpio_drv_remove, }; static int __init gpio_drv_init(void) { /* 注册platform_driver */ return platform_driver_register(&gpio_platform_driver); } static void __exit gpio_drv_exit(void) { /* 反注册platform_driver */ platform_driver_unregister(&gpio_platform_driver); } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(gpio_drv_init); module_exit(gpio_drv_exit); MODULE_LICENSE("GPL");

5template3_i2c

c++
#include "linux/i2c.h" #include <linux/module.h> #include <linux/poll.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/timer.h> /* 主设备号 */ static int major = 0; static struct class *my_i2c_class; struct i2c_client *g_client; static DECLARE_WAIT_QUEUE_HEAD(gpio_wait); struct fasync_struct *i2c_fasync; /* 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t i2c_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { int err; struct i2c_msg msgs[2]; /* 初始化i2c_msg */ err = i2c_transfer(g_client->adapter, msgs, 2); /* copy_to_user */ return 0; } static ssize_t i2c_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { int err; /* copy_from_user */ struct i2c_msg msgs[2]; /* 初始化i2c_msg */ err = i2c_transfer(g_client->adapter, msgs, 2); return 0; } static unsigned int i2c_drv_poll(struct file *fp, poll_table * wait) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, &gpio_wait, wait); //return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; return 0; } static int i2c_drv_fasync(int fd, struct file *file, int on) { if (fasync_helper(fd, file, on, &i2c_fasync) >= 0) return 0; else return -EIO; } /* 定义自己的file_operations结构体 */ static struct file_operations i2c_drv_fops = { .owner = THIS_MODULE, .read = i2c_drv_read, .write = i2c_drv_write, .poll = i2c_drv_poll, .fasync = i2c_drv_fasync, }; static int i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) { // struct device_node *np = client->dev.of_node; // struct i2c_adapter *adapter = client->adapter; /* 记录client */ g_client = client; /* 注册字符设备 */ /* 注册file_operations */ major = register_chrdev(0, "100ask_i2c", &i2c_drv_fops); /* /dev/gpio_desc */ my_i2c_class = class_create(THIS_MODULE, "100ask_i2c_class"); if (IS_ERR(my_i2c_class)) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "100ask_i2c"); return PTR_ERR(my_i2c_class); } device_create(my_i2c_class, NULL, MKDEV(major, 0), NULL, "myi2c"); /* /dev/myi2c */ return 0; } static int i2c_drv_remove(struct i2c_client *client) { /* 反注册字符设备 */ device_destroy(my_i2c_class, MKDEV(major, 0)); class_destroy(my_i2c_class); unregister_chrdev(major, "100ask_i2c"); return 0; } static const struct of_device_id myi2c_dt_match[] = { { .compatible = "100ask,i2cdev" }, {}, }; static struct i2c_driver my_i2c_driver = { .driver = { .name = "100ask_i2c_drv", .owner = THIS_MODULE, .of_match_table = myi2c_dt_match, }, .probe = i2c_drv_probe, .remove = i2c_drv_remove, }; static int __init i2c_drv_init(void) { /* 注册i2c_driver */ return i2c_add_driver(&my_i2c_driver); } static void __exit i2c_drv_exit(void) { /* 反注册i2c_driver */ i2c_del_driver(&my_i2c_driver); } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(i2c_drv_init); module_exit(i2c_drv_exit); MODULE_LICENSE("GPL");

6template3_spi

c++
#include <linux/spi/spi.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/timer.h> /* 主设备号 */ static int major = 0; static struct class *my_spi_class; static struct spi_device *g_spi; static DECLARE_WAIT_QUEUE_HEAD(gpio_wait); struct fasync_struct *spi_fasync; /* 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t spi_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { // int err; // struct spi_transfer msgs[2]; /* 初始化 spi_transfer */ // static inline int // spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, // unsigned int num_xfers); /* copy_to_user */ return 0; } static ssize_t spi_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { //int err; /* copy_from_user */ // struct spi_transfer msgs[2]; /* 初始化 spi_transfer */ // static inline int // spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, // unsigned int num_xfers); return 0; } static unsigned int spi_drv_poll(struct file *fp, poll_table * wait) { //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, &gpio_wait, wait); //return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; return 0; } static int spi_drv_fasync(int fd, struct file *file, int on) { if (fasync_helper(fd, file, on, &spi_fasync) >= 0) return 0; else return -EIO; } /* 定义自己的file_operations结构体 */ static struct file_operations spi_drv_fops = { .owner = THIS_MODULE, .read = spi_drv_read, .write = spi_drv_write, .poll = spi_drv_poll, .fasync = spi_drv_fasync, }; static int spi_drv_probe(struct spi_device *spi) { // struct device_node *np = client->dev.of_node; /* 记录spi_device */ g_spi = spi; /* 注册字符设备 */ /* 注册file_operations */ major = register_chrdev(0, "100ask_spi", &spi_drv_fops); /* /dev/gpio_desc */ my_spi_class = class_create(THIS_MODULE, "100ask_spi_class"); if (IS_ERR(my_spi_class)) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "100ask_spi"); return PTR_ERR(my_spi_class); } device_create(my_spi_class, NULL, MKDEV(major, 0), NULL, "myspi"); /* /dev/myspi */ return 0; } static int spi_drv_remove(struct spi_device *spi) { /* 反注册字符设备 */ device_destroy(my_spi_class, MKDEV(major, 0)); class_destroy(my_spi_class); unregister_chrdev(major, "100ask_spi"); return 0; } static const struct of_device_id myspi_dt_match[] = { { .compatible = "100ask,spidev" }, {}, }; static struct spi_driver my_spi_driver = { .driver = { .name = "100ask_spi_drv", .owner = THIS_MODULE, .of_match_table = myspi_dt_match, }, .probe = spi_drv_probe, .remove = spi_drv_remove, }; static int __init spi_drv_init(void) { /* 注册spi_driver */ return spi_register_driver(&my_spi_driver); } static void __exit spi_drv_exit(void) { /* 反注册spi_driver */ spi_unregister_driver(&my_spi_driver); } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(spi_drv_init); module_exit(spi_drv_exit); MODULE_LICENSE("GPL");

本文作者:zzw

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 License 许可协议。转载请注明出处!