#驱动drv.c
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include "led.h"
#define LED_NUM (2)
#define LED_CHRDEV_NAME ("led_chrdev")
#define LED_MAJOR (255)
struct led_dev{
dev_t dev_no;
unsigned int minor;
struct cdev cdev;
struct class *cls;
struct device *dev;
struct resource *res;
unsigned int pin;
char cls_name[20];
char gpio_name[20];
};
struct led_dev *p_led_dev;
static int led_open(struct inode *inode, struct file *filp)
{
struct led_dev *t_led_dev = container_of(inode->i_cdev, struct led_dev, cdev);
filp->private_data = t_led_dev;
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
return 0;
}
static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
int led_num;
struct led_dev *t_led_dev = filp->private_data;
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
if ( _IOC_TYPE(cmd) != LED_MAGIC) // 判断幻数
{
printk("_IOC_TYPE err.\n");
return -ENOTTY;
}
led_num = MINOR(t_led_dev->dev_no);
switch(cmd)
{
case LEDON:
if (led_num == 0)
{
printk("led%d on.\n", led_num);
gpio_set_value(p_led_dev->pin, 1);
printk("pin is %d on.\n", p_led_dev->pin);
}
else if(led_num == 1)
{
printk("led%d on.\n", led_num);
gpio_set_value(p_led_dev->pin, 1);
printk("pin is %d on.\n", p_led_dev->pin);
}
break;
case LEDOFF:
if (led_num == 0)
{
printk("led%d off.\n", led_num);
gpio_set_value(p_led_dev->pin, 0);
printk("pin is %d off.\n", p_led_dev->pin);
}
else if(led_num == 1)
{
printk("led%d off.\n", led_num);
gpio_set_value(p_led_dev->pin, 0);
printk("pin is %d off.\n", p_led_dev->pin);
}
break;
default:
printk("cmd id error.\n");
}
return 0;
}
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.unlocked_ioctl = led_ioctl,
};
static int led_probe(struct platform_device *pdev)
{
int ret;
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
p_led_dev = kzalloc(sizeof(struct led_dev), GFP_KERNEL);
if ( IS_ERR(p_led_dev) )
{
printk("kzalloc error.\n");
ret = PTR_ERR(p_led_dev);
goto kzalloc_err;
}
p_led_dev->dev_no = MKDEV(LED_MAJOR, pdev->id);
ret = register_chrdev_region(p_led_dev->dev_no, 1, LED_CHRDEV_NAME);
if ( ret < 0 )
{
printk("register_chrdev_region failed.\n");
goto alloc_chrdev_region_err;
}
p_led_dev->minor = MINOR(p_led_dev->dev_no); // 次设备号
p_led_dev->pin = *(unsigned int *)(pdev->dev.platform_data);
cdev_init(&p_led_dev->cdev, &led_ops);
ret = cdev_add(&p_led_dev->cdev, p_led_dev->dev_no, LED_NUM);
if ( ret < 0 )
{
printk("cdev_add error.\n");
goto cdev_add_err;
}
sprintf(p_led_dev->cls_name, "led_cls%d", pdev->id);
p_led_dev->cls = class_create(THIS_MODULE, p_led_dev->cls_name);
if ( IS_ERR(p_led_dev->cls) )
{
printk("class_create failed.\n");
ret = PTR_ERR(p_led_dev->cls);
goto class_create_err;
}
p_led_dev->dev = device_create(p_led_dev->cls, NULL, p_led_dev->dev_no, NULL, "led_device%d", pdev->id);
if ( IS_ERR(p_led_dev->dev) )
{
printk("device_create failed.\n");
ret = PTR_ERR(p_led_dev->dev);
goto device_create_err;
}
p_led_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if ( IS_ERR(p_led_dev->res) )
{
printk("platform_set_drvdata failed.\n");
ret = PTR_ERR(p_led_dev->res);
goto platform_set_drvdata_err;
}
ret = gpio_is_valid(p_led_dev->pin);
if (ret == 0)
{
printk("gpio is not valid.\n");
goto gpio_is_valid_err;
}
sprintf(p_led_dev->gpio_name, "led_gpio%d", pdev->id);
ret = gpio_request(p_led_dev->pin, p_led_dev->gpio_name);
if (ret < 0)
{
printk("gpio_request failed.\n");
goto gpio_request_err;
}
ret = gpio_direction_output(p_led_dev->pin, 0); // 将引脚设置为输出,并初始化为低电平
if ( ret < 0 )
{
printk("gpio_direction_output failed.\n");
goto gpio_direction_output_err;
}
platform_set_drvdata(pdev, (void *)p_led_dev);
return 0;
gpio_direction_output_err:
gpio_free(p_led_dev->pin);
gpio_request_err:
gpio_is_valid_err:
platform_set_drvdata_err:
device_destroy(p_led_dev->cls, p_led_dev->dev_no);
device_create_err:
class_destroy(p_led_dev->cls);
class_create_err:
cdev_del(&p_led_dev->cdev);
cdev_add_err:
unregister_chrdev_region(p_led_dev->dev_no, 1);
alloc_chrdev_region_err:
kfree(p_led_dev);
kzalloc_err:
return ret;
}
static int led_remove(struct platform_device *pdev)
{
struct led_dev *t_led_dev = platform_get_drvdata(pdev);
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
gpio_free(t_led_dev->pin);
device_destroy(t_led_dev->cls, t_led_dev->dev_no);
class_destroy(t_led_dev->cls);
cdev_del(&t_led_dev->cdev);
unregister_chrdev_region(t_led_dev->dev_no, 1);
kfree(t_led_dev);
return 0;
}
static struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "335x_led",
.owner = THIS_MODULE,
},
};
module_platform_driver(led_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("使用平台设备的LED驱动");
#设备dev.c
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
unsigned int led1_pin = (1*32+0); // GPIO1_7
unsigned int led2_pin = (1*32+1); // GPIO1_6
void led_dev_release(struct device *dev)
{
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
}
// LED1 GPIO1_7
struct resource led1_resource[] = {
[0] = DEFINE_RES_MEM(0x44E1081C, 4), // CONF_GPMC_AD7
[1] = DEFINE_RES_MEM(0x4804C134, 4), // GPIO1_OE
[2] = DEFINE_RES_MEM(0x4804C13C, 4), // GPIO1_DATAOUT
};
// LED2 GPIO1_6
struct resource led2_resource[] = {
[0] = DEFINE_RES_MEM(0x44E10818, 4), // CONF_GPMC_AD6
[1] = DEFINE_RES_MEM(0x4804C134, 4), // GPIO1_OE
[2] = DEFINE_RES_MEM(0x4804C13C, 4), // GPIO1_DATAOUT
};
struct platform_device led1_dev =
{
.name = "335x_led",
.id = 0,
.num_resources = ARRAY_SIZE(led1_resource),
.resource = led1_resource,
.dev = {
.release = led_dev_release,
.platform_data = &led1_pin, // void *型,用来向驱动传递更多的信息,这里传递的是管脚号
},
};
struct platform_device led2_dev =
{
.name = "335x_led",
.id = 1,
.num_resources = ARRAY_SIZE(led2_resource),
.resource = led2_resource,
.dev = {
.release = led_dev_release,
.platform_data = &led2_pin,
},
};
static int __init led_dev_init(void)
{
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
platform_device_register(&led1_dev);
platform_device_register(&led2_dev);
return 0;
}
static void __exit led_dev_exit(void)
{
printk("%s -- %d.\n", __FUNCTION__, __LINE__);
platform_device_unregister(&led1_dev);
platform_device_unregister(&led2_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
#led.h
#ifndef _LED_H_
#define _LED_H_
typedef struct led_node
{
int which;
int status;
}led_node_t;
#define LED_MAGIC 'q'
#define LEDON _IOW(LED_MAGIC, 0, struct led_node)
#define LEDOFF _IOW(LED_MAGIC, 1, struct led_node)
#endif /* led.h */
#test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "led.h"
#define LED_NUM (2)
const char *led_pathname[LED_NUM] = {
"/dev/led_device0",
"/dev/led_device1",
};
int main()
{
int i, fd_led[LED_NUM];
for (i=0; i<LED_NUM; i++)
{
fd_led[i] = open(led_pathname[i], O_RDWR, 0666);
if (fd_led[i] < 0)
{
printf("open led%d failed\n", i);
return -1;
}
}
for(i=0; i<LED_NUM; i++)
{
ioctl(fd_led[i], LEDON); // 点亮LED
sleep(1);
ioctl(fd_led[i], LEDOFF); // 关闭LED
sleep(1);
}
for(i=0; i<LED_NUM; i++)
{
close(fd_led[i]);
}
return 0;
}
#运行结果
/mnt # insmod drv.ko
/mnt # insmod dev.ko
led_dev_init -- 57.
led_probe -- 115.
led_probe -- 115.
/mnt # ./app
led_open -- 36.
led_open -- 36.
led_ioctl -- 54.
led0 on.
pin is 33 on.
led_ioctl -- 54.
led0 off.
pin is 33 off.
led_ioctl -- 54.
led1 on.
pin is 33 on.
led_ioctl -- 54.
led1 off.
pin is 33 off.
led_release -- 43.
led_release -- 43.
为什么运行结果都是33号led亮,是资源被覆盖了吗?求解,如果使设备0获取32,设备1获取33.
https://blog.csdn.net/sinat_30545941/article/details/85943787