mini 2440 LED 드라이버 의 완전 분석
mini 2440 에서 제공 하 는 커 널 은 LED 드라이버 를 가지 고 있 지만 이 드라이버 는 여러 가지 장치 로 작 성 된 것 으로 초보 자 에 게 적합 하지 않 습 니 다. 저 자 는 LDD 3 제3 장 내용 에 따라 코드 를 수정 하여 일부 초보 자 들 에 게 도움 이 되 기 를 바 랍 니 다.
전재 출처 설명:
http://blog.csdn.net/alleincao/article/details/7362558
드라이버:
#include <mach/regs-gpio.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>	//  mdev  
#define DEVICE_NAME "leds"
unsigned int gpio_major_number=0;
struct cdev gpio_dev;
struct class *gpio_class;
dev_t dev_nr;
static unsigned long led_table [] = {
	S3C2410_GPB(5),
	S3C2410_GPB(6),
	S3C2410_GPB(7),
	S3C2410_GPB(8),
};
static unsigned int led_cfg_table [] = {
	S3C2410_GPIO_OUTPUT,
	S3C2410_GPIO_OUTPUT,
	S3C2410_GPIO_OUTPUT,
	S3C2410_GPIO_OUTPUT,
};
static int sbc2440_leds_ioctl(
	struct inode *inode, 
	struct file *file, 
	unsigned int cmd, 
	unsigned long arg)
{
	switch(cmd) {
	case 0:
	case 1:
		if (arg > 4) {
			return -EINVAL;
		}
		s3c2410_gpio_setpin(led_table[arg], !cmd);
		return 0;
	default:
		return -EINVAL;
	}
}
static struct file_operations gpio_fops = {
	.owner	=	THIS_MODULE,
	.ioctl	=	sbc2440_leds_ioctl,
};
static int __init dev_init(void)
{
	int ret,i;
	for (i = 0; i < 4; i++) {		//     
		s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
		s3c2410_gpio_setpin(led_table[i], 0);
	}
	ret = alloc_chrdev_region(&dev_nr,0,1,DEVICE_NAME);	//       
	gpio_major_number = MAJOR(dev_nr);
	printk(KERN_INFO "Major Num ->%d
",gpio_major_number);
	if (ret<0) 
	{
		printk(KERN_WARNING "gpio:can't get major number %d/n",gpio_major_number);
		return ret;
	}
	cdev_init(&gpio_dev,&gpio_fops);		//             
	gpio_dev.owner = THIS_MODULE;
//	gpio_dev.ops   = &gpio_fops;
	ret = cdev_add(&gpio_dev,dev_nr,1);
	if (ret) 
	{
		unregister_chrdev_region(dev_nr,1);
		printk(KERN_NOTICE "Error %d adding gpio device/n",ret);
		return ret;
	}
	
	gpio_class = class_create(THIS_MODULE, "gpio_class");	//mdev  ,          
	if(IS_ERR(gpio_class)) 
	{
		printk("Err: failed in creating class./n");
		return -1;
	}
	/* register your own device in sysfs, and this will cause mdev to create corresponding device node */
	device_create(gpio_class,NULL,dev_nr, NULL, "gpio_dev%d" ,0);//      gpio_dev0
	return 0;
}
static void __exit dev_exit(void)
{
	cdev_del(&gpio_dev);
	device_destroy(gpio_class,dev_nr);
	class_destroy(gpio_class);
	unregister_chrdev_region(dev_nr,1);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Allein.Cao");  테스트 프로그램:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
        int on;
        int led_no;
        int fd;
        if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
            on < 0 || on > 1 || led_no < 0 || led_no > 3) {
                fprintf(stderr, "Usage: leds led_no 0|1
");
                exit(1);
        }
        fd = open("/dev/gpio_dev0", 0);	//      ,          
        if (fd < 0) {
                perror("open device leds");
                exit(1);
        }
        ioctl(fd, on, led_no);
        close(fd);
        return 0;
}  구동 분석
여기 서 이 프로그램 에서 이해 하기 어 려 운 몇 가지 함수 에 대해 설명 하 겠 습 니 다.
우선, 우 리 는 몇 개의 매크로 를 본다.
S3C2410_GPB(_nr)
S3C2410_GPIO_OUTPUT
S3C2410_GPIO_OFFSET(pin) 
S3C2410_GPIO_BASE(pin)   1、/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
#define S3C2410_GPIO_NEXT(__gpio) \
	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
#ifndef __ASSEMBLY__
enum s3c_gpio_number {
	S3C2410_GPIO_A_START = 0,
	S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
	S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
	S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
	S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
	S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
	S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
	S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
};
#endif /* __ASSEMBLY__ */
/* S3C2410 GPIO number definitions. */
#define S3C2410_GPA(_nr)	(S3C2410_GPIO_A_START + (_nr))
#define S3C2410_GPB(_nr)	(S3C2410_GPIO_B_START + (_nr))
#define S3C2410_GPC(_nr)	(S3C2410_GPIO_C_START + (_nr))
#define S3C2410_GPD(_nr)	(S3C2410_GPIO_D_START + (_nr))
#define S3C2410_GPE(_nr)	(S3C2410_GPIO_E_START + (_nr))
#define S3C2410_GPF(_nr)	(S3C2410_GPIO_F_START + (_nr))
#define S3C2410_GPG(_nr)	(S3C2410_GPIO_G_START + (_nr))
#define S3C2410_GPH(_nr)	(S3C2410_GPIO_H_START + (_nr))  계산: S3C 2410GPB(5) = 37;
2、/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
/* general configuration options */
#define S3C2410_GPIO_LEAVE   (0xFFFFFFFF)
#define S3C2410_GPIO_INPUT   (0xFFFFFFF0)	/* not available on A */
#define S3C2410_GPIO_OUTPUT  (0xFFFFFFF1)	
#define S3C2410_GPIO_IRQ     (0xFFFFFFF2)	/* not available for all */
#define S3C2410_GPIO_SFN2    (0xFFFFFFF2)	/* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3    (0xFFFFFFF3)	/* not available on A */
#ifdef CONFIG_CPU_S3C2400
#define S3C24XX_GPIO_BASE(x)  S3C2400_GPIO_BASE(x)
#define S3C24XX_MISCCR        S3C2400_MISCCR
#else
#define S3C24XX_GPIO_BASE(x)  S3C2410_GPIO_BASE(x)
#define S3C24XX_MISCCR	      S3C24XX_GPIOREG2(0x80)
#endif /* CONFIG_CPU_S3C2400 */
...................................................
#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)  //S3C24XX_VA_GPIO  GPIO     0x56000000         
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31) //      ,       다음은 관건 적 인 2 개의 함수 분석 (GPB 5 를 예 로 들 면)
리드 설정 (출력 으로 설정)
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
	void __iomem *base = S3C24XX_GPIO_BASE(pin);// GPB5  ,  GPBCON    
	unsigned long mask;
	unsigned long con;
	unsigned long flags;
	if (pin < S3C2410_GPIO_BANKB) {
		mask = 1 << S3C2410_GPIO_OFFSET(pin);
	} else {
		mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;//    , GPBCON ,     2   
	}
	switch (function) {
	case S3C2410_GPIO_LEAVE:
		mask = 0;
		function = 0;
		break;
	case S3C2410_GPIO_INPUT:
	case S3C2410_GPIO_OUTPUT:
	case S3C2410_GPIO_SFN2:
	case S3C2410_GPIO_SFN3:
		if (pin < S3C2410_GPIO_BANKB) {
			function -= 1;
			function &= 1;
			function <<= S3C2410_GPIO_OFFSET(pin);
		} else {
			function &= 3;//        ,   1
			function <<= S3C2410_GPIO_OFFSET(pin)*2;
		}
	}
	/* modify the specified register wwith IRQs off */
	local_irq_save(flags);         //   
	con  = __raw_readl(base + 0x00);  //      
	con &= ~mask;                     //      
	con |= function;
	__raw_writel(con, base + 0x00);   //  
	local_irq_restore(flags);      //    
}  void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
	void __iomem *base = S3C24XX_GPIO_BASE(pin);
	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
	unsigned long flags;
	unsigned long dat;
	local_irq_save(flags);
	dat = __raw_readl(base + 0x04);// GPBDAT  ,     1      
	dat &= ~(1 << offs);
	dat |= to << offs;
	__raw_writel(dat, base + 0x04);
	local_irq_restore(flags);
}
                이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Docker를 사용한 React 및 .NET Core 6.0 샘플 프로젝트 - 1부이 기사에서는 Entity Framework Core Code First 접근 방식을 사용하는 ASP.NET Core 6.0 WEP API의 CRUD(만들기, 읽기, 업데이트 및 삭제) 작업에 대해 설명합니다. 웹 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.