Linux下如何加载一个字符驱动(GPIO)

加载一个IO口的字符驱动,并验证之:

1、在“内核/drivers/char”路径下增加gpio_ctrl.c文件,该文件主要作用是申请设备号、注册设备节点等,并在该路径下的makefile中编写编译选项,将gpio_ctrl.c嵌入内核;

2、调用“内核/quich.sh”文件重新编译内核,生成的新内核文件位于“内核/arch/

</pre>arm/boot<span style="font-family:宋体;">”中,文件名见</span><span style="font-family:Calibri;">quich.sh</span><span style="font-family:宋体;">中的定义,此处为</span><span style="font-family:Calibri;">zImage;</span></p><p>3、将内核文件拷贝到<span style="font-family:Calibri;">tftp</span><span style="font-family:宋体;">根目录下,即“</span><span style="font-family:Calibri;">/tftproot</span><span style="font-family:宋体;">”,以供</span><span style="font-family:Calibri;">uboot</span><span style="font-family:宋体;">下载;</span></p><p> </p><p>验证:</p><p>1、编写<span style="font-family:Calibri;">gpio_test.c</span><span style="font-family:宋体;">文件,并编写相应</span><span style="font-family:Calibri;">makefile</span><span style="font-family:宋体;">,生成可执行文件</span><span style="font-family:Calibri;">gpio0421</span><span style="font-family:宋体;">;</span></p><p>2、将<span style="font-family:Calibri;">gpio0421</span><span style="font-family:宋体;">拷贝到文件系统目录下,</span></p><p>即“<span style="font-family:Calibri;">\mnt\sda4\Imx6q_my\05_filesystem\distro-fsl-image\home\root</span><span style="font-family:宋体;">”;</span></p><p> </p><p>上述完成后,将板子重上电,<span style="font-family:Calibri;">uboot</span><span style="font-family:宋体;">自动加载。完成后,</span></p><p>1、在串口工具中“<span style="font-family:Calibri;">ls /dev</span><span style="font-family:宋体;">”查看,应有</span><span style="font-family:Calibri;">gpio_ctrl</span><span style="font-family:宋体;">的设备节点;</span></p><p>cd<span style="font-family:宋体;">到</span><span style="font-family:Calibri;">/home/root</span><span style="font-family:宋体;">目录,直接执行</span><span style="font-family:Calibri;">gpio0421</span><span style="font-family:宋体;">,观察其打印信息即可;</span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;"></span></p><p><span style="font-family:宋体;">gpio_test.c:</span></p><p><span style="font-family:宋体;"></span><pre name="code" class="cpp">#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define GPIO_CTRL_CMD_L 0x00
#define GPIO_CTRL_CMD_H 0x01

#define PSTN_MODE_RST 0 // 要操作的GPIO

int main(int argc, char *argv[])
{
	int fd;
    int index;

    if (argc < 2) {
        printf("Usage: \n %s < H|L >\n", argv[0]);
        return -1;
    }
    
    fd = open("/dev/gpio_ctrl", O_RDWR);
    if (fd < 0) {
        printf("open gpio_ctrl failed.\n");
        return -1;
    }

    index = PSTN_MODE_RST;

    if ((!strcmp(argv[1], "H")) || (!strcmp(argv[1], "h")))
    {
		ioctl(fd, GPIO_CTRL_CMD_H, &index);
		printf("Ctrl High\n");
	}	
    else if ((!strcmp(argv[1], "L")) || (!strcmp(argv[1], "l")))
    {
		ioctl(fd, GPIO_CTRL_CMD_L, &index);
		printf("Ctrl Low\n");
	}
	printf("close the /dev/gpio_ctrl\n");
    close(fd);

	return 0;
}

makefile:

TARGET=gpio0421

CC=arm-linux-gnueabihf-gcc -c -g -I./
#LINK=gcc
LINK=arm-linux-gnueabihf-gcc
C_SOURCE=$(wildcard *.c)
C_OBJS=$(C_SOURCE:%.c=%.o)

$(TARGET): $(C_OBJS)
	@echo Linking $@ from $^..
	$(LINK) -o $@ $^

$(C_OBJS): %.o: %.c 
	@echo $(C_OBJS)
	@echo Compiling $@ from $<..
	$(CC) -o $@ $<

PHONY:clean

clean:
	rm -rf $(C_OBJS) $(TARGET)


gpio_ctrl.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h> //cdev
#include <linux/fs.h> //file_operations
#include <linux/uaccess.h> //copy_* 
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/bcd.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <asm/gpio.h>
#include <linux/gpio.h>
//#include <arch/arm/mach-imx/hardware.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("yangyufeng");
MODULE_DESCRIPTION("A simple char driver: GPIO CTROL");
MODULE_VERSION("1.0");

#define IMX_GPIO_NR(bank, nr)  (((bank) - 1) * 32 + (nr))
#define PSTN_MODE_RST  IMX_GPIO_NR(2, 5)

#define debug_print(x...) printk(x)

#define GPIO_CTRL_CMD_L 0x00
#define GPIO_CTRL_CMD_H 0x01

int i;

struct gpio_info {
    int gpio;
    char *name;
};

static struct gpio_info gpio_name[] = {
    {
    	.gpio = PSTN_MODE_RST,
    	.name = "pstn module GPIO2_05"
    },
};

dev_t 				gpio_ctrl_devno;
struct cdev 		*gpio_ctrl_cdev;
static struct class *gpio_ctrl_class = NULL;

static int     	gpio_ctrl_open(struct inode *inode, struct file *filp);
static int     	gpio_ctrl_release(struct inode *inode, struct file *filp);
static ssize_t 	gpio_ctrl_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
static ssize_t  gpio_ctrl_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
static int 		gpio_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

struct file_operations gpio_ctrl_fops = {
    .owner   = THIS_MODULE,
    .read    = gpio_ctrl_read,
    .write   = gpio_ctrl_write,
    .open    = gpio_ctrl_open,
    .release = gpio_ctrl_release,
    .unlocked_ioctl = gpio_ctrl_ioctl,
};

static int isl12026_i2c_eeprom_init(void)
{
	int ret = 0;
	
	ret = alloc_chrdev_region(&gpio_ctrl_devno, 0, 1, "gpio_control");
	if(ret<0)
		printk(KERN_ALERT"Error: Can not register device number\n");
	else
		printk(KERN_ALERT"Major:%d  Minor:%d\n",MAJOR(gpio_ctrl_devno),MINOR(gpio_ctrl_devno));

	gpio_ctrl_cdev 		  = cdev_alloc(); // 分配字符设备对象
	gpio_ctrl_cdev->ops   = &gpio_ctrl_fops;
	gpio_ctrl_cdev->owner = THIS_MODULE;

	ret = cdev_add(gpio_ctrl_cdev, gpio_ctrl_devno, 1); //注册字符设备
	if(ret) {
		printk(KERN_ALERT"Error %d adding chdrv",ret);
	}

	// 自动生成设备节点
	gpio_ctrl_class = class_create(THIS_MODULE, "gpio_ctrl"); //创建一个子类
	device_create(gpio_ctrl_class, NULL, gpio_ctrl_devno, NULL, "gpio_ctrl");

	// ---------------操作GPIO--------------------
	//申请GPIO资源
	for (i = 0; i < ARRAY_SIZE(gpio_name); i++) {
        gpio_request(gpio_name[i].gpio, gpio_name[i].name);
    }    
    // ---------------操作GPIO--------------------

	return 0;
}

static void isl12026_i2c_eeprom_cleanup(void)
{
	// ---------------操作GPIO--------------------
	for (i = 0; i < ARRAY_SIZE(gpio_name); i++) {
        gpio_free(gpio_name[i].gpio); 
    }
    // ---------------操作GPIO--------------------

	device_destroy(gpio_ctrl_class, gpio_ctrl_devno); //delete device node under /dev
    class_destroy(gpio_ctrl_class); //delete class created

	unregister_chrdev_region(gpio_ctrl_devno, 1);
}

static int gpio_ctrl_open(struct inode* inode, struct file* file)
{
	printk("gpio open\n");
	return 0;
}

static int gpio_ctrl_release(struct inode* inode, struct file* file)
{
	printk("gpio release\n");
	return 0;
}

static ssize_t gpio_ctrl_read(struct file* file, char* buf, size_t count, loff_t* f_pos)
{
	printk("gpio read\n");
	return 0;
}

static ssize_t gpio_ctrl_write(struct file* file, const char* buf, size_t count, loff_t* f_pos)
{
	printk("gpio write\n");
	return 0;
}

static int gpio_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int index = 0;
	int no_use = 0;
	no_use = copy_from_user(&index, (int *)arg, sizeof(index));

	switch (cmd) 
	{
		case GPIO_CTRL_CMD_L:
			printk("gpio ctrl LOW\n");
			gpio_direction_output(gpio_name[index].gpio, 0);
			break;
		case GPIO_CTRL_CMD_H:
			printk("gpio ctrl HIGH\n");
			gpio_direction_output(gpio_name[index].gpio, 1);
		default:
			return -1;
	}

	return 0;
}

module_init(isl12026_i2c_eeprom_init);
module_exit(isl12026_i2c_eeprom_cleanup);

/**************************************************************************/
/* End of file                                                            */
/**************************************************************************/

makefile

#
# Makefile for the kernel character device drivers.
#

obj-y				+= mem.o random.o
obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
obj-y				+= misc.o
obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE)	+= virtio_console.o
obj-$(CONFIG_RAW_DRIVER)	+= raw.o
obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
obj-$(CONFIG_MSM_SMD_PKT)	+= msm_smd_pkt.o
obj-$(CONFIG_MSPEC)		+= mspec.o
obj-$(CONFIG_MMTIMER)		+= mmtimer.o
obj-$(CONFIG_UV_MMTIMER)	+= uv_mmtimer.o
obj-$(CONFIG_IBM_BSR)		+= bsr.o
obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o
obj-$(CONFIG_FSL_OTP)		+= fsl_otp.o
obj-$(CONFIG_THERMAL_PRINTER) += jx_2r_01.o
obj-$(CONFIG_THERMAL_PRINTER) += jx_2r_01_dev.o
obj-$(CONFIG_THERMAL_PRINTER) += gpio_ctrl.o


obj-$(CONFIG_PRINTER)		+= lp.o

obj-$(CONFIG_APM_EMULATION)	+= apm-emulation.o

obj-$(CONFIG_DTLK)		+= dtlk.o
obj-$(CONFIG_APPLICOM)		+= applicom.o
obj-$(CONFIG_SONYPI)		+= sonypi.o
obj-$(CONFIG_RTC)		+= rtc.o
obj-$(CONFIG_HPET)		+= hpet.o
obj-$(CONFIG_GEN_RTC)		+= genrtc.o
obj-$(CONFIG_EFI_RTC)		+= efirtc.o
obj-$(CONFIG_DS1302)		+= ds1302.o
obj-$(CONFIG_XILINX_HWICAP)	+= xilinx_hwicap/
ifeq ($(CONFIG_GENERIC_NVRAM),y)
  obj-$(CONFIG_NVRAM)	+= generic_nvram.o
else
  obj-$(CONFIG_NVRAM)	+= nvram.o
endif
obj-$(CONFIG_TOSHIBA)		+= toshiba.o
obj-$(CONFIG_I8K)		+= i8k.o
obj-$(CONFIG_DS1620)		+= ds1620.o
obj-$(CONFIG_HW_RANDOM)		+= hw_random/
obj-$(CONFIG_PPDEV)		+= ppdev.o
obj-$(CONFIG_NWBUTTON)		+= nwbutton.o
obj-$(CONFIG_NWFLASH)		+= nwflash.o
obj-$(CONFIG_SCx200_GPIO)	+= scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO)	+= pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO)		+= nsc_gpio.o
obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o
obj-$(CONFIG_TELCLOCK)		+= tlclk.o

obj-$(CONFIG_MWAVE)		+= mwave/
obj-y				+= agp/
obj-$(CONFIG_PCMCIA)		+= pcmcia/

obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
obj-$(CONFIG_TCG_TPM)		+= tpm/

obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o

obj-$(CONFIG_JS_RTC)		+= js-rtc.o
js-rtc-y = rtc.o

obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
obj-$(CONFIG_HAVE_IMX_AMP)      += imx_amp/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值