Linux下读写寄存器

简介: arm裸机下读写寄存器很容易,各个寄存器和内存的地址是单一地址空间,他们是用相同的指令进行读写操作的.而在linux下就要复杂很多,因为linux支持多个体系架构的CPU。比如arm和x86就不一样,具体的差别我暂时也说不上来,这个涉及到CPU体系的设计。

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在移植过程中如何实现这两种方式的方法还不清楚,现在只是会用。等以后有机会了再慢慢理清楚。

目录
相关文章
|
28天前
|
Linux API C++
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
18 1
|
3月前
|
Linux
Linux在文件特定偏移量处读写pread和pwrite
系统调用 pread()和 pwrite()完成与 read()和 write()相类似的工作,只是前两者会在 offset 参数所指定的位置进行文件 I/O 操作,而非始于文件的当前偏移量处,且它们不会改变文件的当前偏移量。
43 0
Linux在文件特定偏移量处读写pread和pwrite
|
3月前
|
Linux
Linux io多块读写readv函数和writev函数
fd参数是被操作的目标文件描述符。iov参数的类型是iovec结构数组,该结构体描述一块内存区。iovcnt参数是iov数组的长度,即有多少块内存数据需要从fd读出或写到fd。readv和writev在成功时返回读出/写入fd的字节数,失败则返回-1并设置errno。readv函数将数据从文件描述符读到分散的内存块中,即分散读;writev函数则将多块分散的内存数据一并写入文件描述符中,即集中写。
19 0
|
3月前
|
Linux
【Linux C 几种锁的性能对比】 1.读写锁 2.互斥锁 3.自旋锁 4.信号量 5.rcu
【Linux C 几种锁的性能对比】 1.读写锁 2.互斥锁 3.自旋锁 4.信号量 5.rcu
|
4月前
|
Linux
Linux线程同步(try锁和读写锁)
Linux线程同步(try锁和读写锁)
28 0
|
2月前
|
Linux
Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量详解
Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量详解
72 0
Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量详解
|
6月前
|
移动开发 Linux Windows
linux系统中QT进行文本读写操作的方法
linux系统中QT进行文本读写操作的方法
45 0
|
8月前
|
Linux
Linux文件读写操作全面解析
在Linux系统中,文件读写操作是非常常见和重要的任务。无论是读取配置文件、处理日志文件还是进行数据持久化,文件读写都是必不可少的。本文将全面解析Linux下文件读写的各个方面,包括打开文件、读取文件内容、写入文件内容以及错误处理。我们将详细介绍相关的系统调用和C标准库函数,并提供丰富的代码示例。
468 0
|
9月前
|
Linux
Linux驱动操作地址(寄存器)的一些方式
Linux驱动操作地址(寄存器)的一些方式
109 0
|
9月前
|
Linux 编译器
Linux系统应用编程---线程同步基础(互斥量、死锁、读写锁)
Linux系统应用编程---线程同步基础(互斥量、死锁、读写锁)
86 0