linux驱动实践(四)--linux下读写寄存器

原创 2012年12月23日 23:22:01

        arm裸机下读写寄存器很容易,各个寄存器和内存的地址是单一地址空间,他们是用相同的指令进行读写操作的.而在linux下就要复杂很多,因为linux支持多个体系架构的CPU。比如arm和x86就不一样,具体的差别我暂时也说不上来,这个涉及到CPU体系的设计。目前我只关心:linux为了支持多个硬件体系,在IO访问上做了自己的接口。可以通过IO内存和IO端口这两种方式进行IO访问。在LED的例子上给出这两种方式的具体实现:

        1.利用IO Port的方式:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/ioport.h>

#include <mach/regs-gpio.h>
#include <asm/system.h>		/* cli(), *_flags */
#include <asm/uaccess.h>	/* copy_*_user */
#include <asm/io.h>

#define LED_NUM			4

struct led_dev
{
	struct cdev dev;
	unsigned port;
	unsigned long offset;
};

struct led_dev led[4];
dev_t dev = 0;
static struct resource *led_resource;


int led_open(struct inode *inode, struct file *filp)
{
	struct led_dev *led; /* device information */

	led = container_of(inode->i_cdev, struct led_dev, dev);
	filp->private_data = led; /* for other methods */

	return 0;          /* success */
}

int led_release(struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	return 0;
}

ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	char data;
	struct led_dev *led;
	u32 value;
	printk(KERN_INFO "debug by baikal: led dev write\n");
	
	led = (struct led_dev *)filp->private_data;
	copy_from_user(&data,buf,count);
	if(data == '0')
	{	
		printk(KERN_INFO "debug by baikal: led off\n");	
		value = inl((unsigned)(S3C2410_GPBDAT));
		outl(value | 1<<led->offset,(unsigned)(S3C2410_GPBDAT));	
		//value = ioread32(led->base);
		//iowrite32( value | 1<<led->offset, led->base);		
	}
	else
	{
		printk(KERN_INFO "debug by baikal: led on\n");
		value = inl((unsigned)(S3C2410_GPBDAT));
		outl(value & ~(1<<led->offset),(unsigned)(S3C2410_GPBDAT));	
		//value = ioread32(led->base);
		//iowrite32( value & ~(1<<led->offset), led->base);
	}
}

struct file_operations led_fops = {
	.owner =    THIS_MODULE,
	.read =     led_read,
	.write =    led_write,
	//.ioctl =    led_ioctl,
	.open =     led_open,
	.release =  led_release,
};

static int led_init(void)
{	
	int result, i;
	


	result = alloc_chrdev_region(&dev, 0, LED_NUM,"LED");
	if (result < 0) {
		printk(KERN_WARNING "LED: can't get major %d\n", MAJOR(dev));
		return result;
	}
	led_resource = request_region(0x56000014,0x4,"led");
	if(led_resource == NULL)
	{
		printk(KERN_ERR " Unable to register LED I/O addresses\n");
		return -1;
	}
	for(i = 0; i < LED_NUM; i++)
	{
		cdev_init( &led[i].dev, &led_fops);
		//led[i].port = ioport_map(0x56000014,0x4);
		//led[i].base = ioremap(0x56000014,0x4);
		led[i].offset = i + 5;   //leds  GPB5\6\7\8
		led[i].dev.owner = THIS_MODULE;
		led[i].dev.ops = &led_fops;
		result = cdev_add(&led[i].dev,MKDEV(MAJOR(dev),i),1);
		if(result < 0)
		{
			printk(KERN_ERR "LED: can't add led%d\n",i);
			return result;
		}
	}

	return 0;
}

static void led_exit(void)
{
	int i;
	release_region(0x56000014,0x4);
	for( i = 0; i < LED_NUM; i++)
	{
		//iounmap(led[i].base);

		cdev_del(&led[i].dev);	
	}
	unregister_chrdev_region(dev, LED_NUM);

}


module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("Baikal");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple LED Driver");

        2.利用IO Mem的方式:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/ioport.h>

#include <asm/system.h>		/* cli(), *_flags */
#include <asm/uaccess.h>	/* copy_*_user */
#include <asm/io.h>

#define LED_NUM			4

struct led_dev
{
	struct cdev dev;
	void __iomem *base;
	unsigned long offset;
};

struct led_dev led[4];
dev_t dev = 0;


int led_open(struct inode *inode, struct file *filp)
{
	struct led_dev *led; /* device information */

	led = container_of(inode->i_cdev, struct led_dev, dev);
	filp->private_data = led; /* for other methods */

	return 0;          /* success */
}

int led_release(struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	return 0;
}

ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	char data;
	struct led_dev *led;
	u32 value;
	printk(KERN_INFO "debug by baikal: led dev write\n");
	
	led = (struct led_dev *)filp->private_data;
	copy_from_user(&data,buf,count);
	if(data == '0')
	{	
		printk(KERN_INFO "debug by baikal: led off\n");		
		value = ioread32(led->base);
		iowrite32( value | 1<<led->offset, led->base);		
	}
	else
	{
		printk(KERN_INFO "debug by baikal: led on\n");
		value = ioread32(led->base);
		iowrite32( value & ~(1<<led->offset), led->base);
	}
}

struct file_operations led_fops = {
	.owner =    THIS_MODULE,
	.read =     led_read,
	.write =    led_write,
	//.ioctl =    led_ioctl,
	.open =     led_open,
	.release =  led_release,
};

static int led_init(void)
{	
	int result, i;
	


	result = alloc_chrdev_region(&dev, 0, LED_NUM,"LED");
	if (result < 0) {
		printk(KERN_WARNING "LED: can't get major %d\n", MAJOR(dev));
		return result;
	}
	
	for(i = 0; i < LED_NUM; i++)
	{
		cdev_init( &led[i].dev, &led_fops);
		request_mem_region(0x56000014,0x4,"led");
		led[i].base = ioremap(0x56000014,0x4);
		led[i].offset = i + 5;   //leds  GPB5\6\7\8
		led[i].dev.owner = THIS_MODULE;
		led[i].dev.ops = &led_fops;
		result = cdev_add(&led[i].dev,MKDEV(MAJOR(dev),i),1);
		if(result < 0)
		{
			printk(KERN_ERR "LED: can't add led%d\n",i);
			return result;
		}
	}

	return 0;
}

static void led_exit(void)
{
	int i;		
	release_mem_region(0x56000014,0x4);
	for( i = 0; i < LED_NUM; i++)
	{
		iounmap(led[i].base);

		cdev_del(&led[i].dev);	
	}
	unregister_chrdev_region(dev, LED_NUM);

}


module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("Baikal");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple LED Driver");

        目前,对于具体体系上的linux在移植过程中如何实现这两种方式的方法还不清楚,现在只是会用。等以后有机会了再慢慢理清楚。

Linux在应用层读写寄存器的方法

可以通过操作/dev/mem设备文件,以及mmap函数,将寄存器的地址映射到用户空间,直接在应用层对寄存器进行操作,示例如下:...

Linux调试备忘录1-- Linux kernel启动后,如何在用户命令行查看和修改寄存器值

Linux kernel启动后,如何在用户命令行查看和修改寄存器值? 我们知道Linux kernel启动后,由于memory map的管理,我们是无法...

Linux在应用层通过mmap映射后,读写寄存器

可以通过操作/dev/mem设备文件,以及mmap函数,将寄存器的地址映射到用户空间,直接在应用层对寄存器进行操作,示例如下: [cpp] view plaincopy ...
  • yi412
  • yi412
  • 2015年08月08日 10:33
  • 1523

驱动中读写硬件寄存器的方式

1.驱动中读写硬件寄存器的方式 比如想控制某寄存器。先查找datasheet中该寄存器的物理地址。 然后调用ioremap()函数。该函数返回一个虚拟地址。内核空间 可以直接访问它。 比如我们...

内核驱动中改写寄存器值

在Kernel Model的驱动程序中向给定的寄存器地址、内存地址或IO端口地址等16进制的地址写入指定的值。 主要依靠的是MSDN中提供的MmMapIoSpace函数进行的。该函数将一个十六进制的...

嵌入式 Linux应用程序如何读取(修改)芯片寄存器的值 -学习路上

这一问题来自项目中一个实际的需求: 我需要在Linux启动之后,确认我指定的芯片寄存器是否与我在uboot的配置一致。 举个例子: 寄存器地址:0x20000010负责对DDR2的时序配置,...

【从零开始,从内核驱动驱动到用户空间调用】编写第一个linux驱动,通过端口访问I/O寄存器。

目的: 通过I/O端口方式访问RTC的秒寄存器; 过程: 由于本人从来没看过linux方面的书籍,也只是会在终端用些常用的命令而已,这次老大叫我学着通过I/O端口方式直接去读写寄存器。于是我在goog...

自己制作Linux驱动调试工具之查看寄存器

写驱动的朋友都应该知道,有些时候驱动程序编译没有出错,运行也没有出现错误,但是运行却达不到我们想要的效果,这个时候调试真的让你束手无策了,这时候我们就可以想办法直接查看跟硬件相关寄存器的值,但是Lin...

Linux内核外设IO寄存器与IO mem读写函数总结

学习时间:2014/5/21   外设IO寄存器地址独立编址的CPU,这时外设IO寄存器应该称为IO端口,访问IO寄存器可以ioport_map()将其映射到虚拟地址空间,但是实际上这只是给开发人...
  • txxm127
  • txxm127
  • 2014年05月21日 16:38
  • 1598

linux中readl()和writel()函数---用于读写寄存器

 readX/writeX() are used to access memory mapped devices. On some  * architectures the memory ma...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux驱动实践(四)--linux下读写寄存器
举报原因:
原因补充:

(最多只允许输入30个字)