1. 程式人生 > >linux裝置驅動(3)字元驅動 -led

linux裝置驅動(3)字元驅動 -led

本文基於mini2440

/*
*  kernel : linux-2.6.22.6
*  gcc     : arm-linux-gcc -3.4.5
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

#include <linux/device.h>    /* class_device ... */

/**
* mini2440 LED資源   低電平有效
*
* LED1    GPB5  
* LED2    GPB6
* LED3    GPB7
* LED4    GPB8
*/

#define GPB_ADDR			0x56000010


static volatile unsigned int *gpbcon;
static volatile unsigned int *gpbdat;

static int major;
static struct class *third_drv_cls;
static struct class_device *third_drv_cls_dev;

static int third_drv_led_open (struct inode *inode, struct file *file)
{
	// 設定對應引腳為輸出
	*gpbcon |= (0x1 << (5*2)) | (0x1 << (6*2)) | (0x1 << (7*2)) | (0x1 << (8*2));
	
	return 0;
}

static int third_drv_led_write (struct file *file, const char __user *usrbuf,
									size_t len, loff_t *offset)
{
	int val[8];
	int cmd, ops;

	if (copy_from_user(&val, usrbuf, 8))
			return -EFAULT;

	cmd = val[0];  
	ops = val[1];

	if(cmd == 0)    // close
	{
		switch(ops)
		{
			case 0:
				*gpbdat |= (1 << 5);
				break;

			case 1:
				*gpbdat |= (1 << 6);
				break;

			case 2:
				*gpbdat |= (1 << 7);
				break;

			case 3:
				*gpbdat |= (1 << 8);
				break;

			default:
				break;
		}
	}
	else if(cmd == 1)  // open
	{
		switch(ops)
		{
			case 0:
				*gpbdat &= ~(1 << 5);	
				break;

			case 1:
				*gpbdat &= ~(1 << 6);		
				break;

			case 2:
				*gpbdat &= ~(1 << 7);		
				break;

			case 3:
				*gpbdat &= ~(1 << 8);		
				break;

			default:
				break;
		}
	}
	else
	{
		// do nothing .
	}
	
	return 0;
}

static struct file_operations third_drv_led_fops = 
{
	.owner      = THIS_MODULE,
	.open       = third_drv_led_open,
	.write      = third_drv_led_write,
};

static int third_drv_init(void)
{
	major = register_chrdev(0, "led_drv", &third_drv_led_fops);

	third_drv_cls = class_create(THIS_MODULE, "led_drv");

	third_drv_cls_dev = class_device_create(third_drv_cls, NULL,
		MKDEV(major, 0), NULL, "myleds");

	// 地址重新對映
	gpbcon = (volatile unsigned int*)ioremap(GPB_ADDR, 4);
	gpbdat = gpbcon + 1;
	
	return 0;
}

static void third_drv_exit(void)
{
	iounmap(gpbcon);
	class_device_unregister(third_drv_cls_dev);
	class_destroy(third_drv_cls);
	
	unregister_chrdev(major, "led_drv");
}


module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Flinn 
[email protected]
"); MODULE_DESCRIPTION("led driver for mini2440");

測試程式參考我的另一個博文:

執行命令./driver_test_tool /dev/myleds -o 0 0 第一個0 表示熄滅, 第二個0表示第一個燈