If you want to access hardware registers in Linux userspace you can use the following example to explore access. However if I recommend creating a Linux Device Driver if you want to do this properly.
Note that this is an advance Linux topic, so please do NOT try this first in a production system.
Example:
Full man can be found at
http://linux.die.net/man/3/
Example:
/*
* Maps real memory address to a virtual address. The virtual address
* then could be used to read/write the real memory as if it was
accessed
* directly.
* Adapted by Janaka Subhawickrama. Copyright 2007.
* GPL software.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
//Virtual address that is associated with the physical address
static char *regmap_addr = NULL;
//The following is the physical address of memory mapped registers of
the CPU
#define REGISTRY_MAP_ADDRESS_OFFSET
#define REGISTRY_MAP_SIZE
#define GPIO2_DATA_DIR_REG_OFFSET
#define GPIO2_DATA_REG_OFFSET
#define GPIO2_DONE_PIN
#define GPIO2_FAULT_PIN
#define GPIO2_PROGB_PIN
int main(int argc, char *argv[])
{
int devmem; // this is the "/dev/mem" descriptor
//Registers of the CPU I am using is 32bit
volatile unsigned int uiGet;
volatile unsigned int *ptmp = NULL;
//On embedded systems you may have to mknod /dev/mem
printf("\nOpening /dev/mem");
devmem = open("/dev/mem", O_RDWR | O_SYNC);
if (devmem < 0)
{
printf("\
strerror(errno));
return -1;
}
printf("\nMapping Memory mapped registers at %08X with size %08X",
REGISTRY_MAP_SIZE, REGISTRY_MAP_ADDRESS_OFFSET);
regmap_addr = (char *)mmap( 0, REGISTRY_MAP_SIZE, PROT_READ|
PROT_WRITE, MAP_SHARED, devmem, REGISTRY_MAP_ADDRESS_OFFSET);
if (regmap_addr == (char *)MAP_FAILED)
{
printf("\
close(devmem);
return -1;
}
//Now you can write to CPU registers as if you were from a boot
loader
//Setup directions of GPIO pins
*(volatile unsigned int *)(regmap_addr + GPIO2_DATA_DIR_REG_OFFSET) =
GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
//Turn some GPIO Pins on
*(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) =
GPIO2_FAULT_PIN | GPIO2_PROGB_PIN;
//Get some values of GPIO lines
uiGet = *(volatile unsigned int *)(regmap_addr +
GPIO2_DATA_REG_OFFSET);
printf("\nGPIO register %08X", uiGet);
//Cleanup
munmap((void *)REGISTRY_MAP_ADDRESS_OFFSET, REGISTRY_MAP_SIZE);
close(devmem);
return 0;
}
More comments and caveats can be found at:
https://groups.google.com/forum/#!msg/comp.os.linux.embedded/kOKNHeMGg58/pTY-jLMFu_gJ
I picked this book up as an experience embedded software engineer who wanted to explore and learn about Linux device drivers. With a background in real-time embedded software development(with some RTOS experience) and years of Linux/nix user/developer experience this book nicely matched my learning path.
Layout of the book:
The chapters are layed out in a logical and incremental fashion where introductory chapters stick to the big picture stuff while later on chapters delve deep in to the internals.
Contents and Examples:
Book takes the approach of explaining the subjects in concise manner with examples and interesting incite. However the code examples in many cases are incomplete, and duly so. I say this because the lot of examples, in their entirety, are provided on their web/ftp site.
Currentness and compatibility:
The book uses x86 as its platform and for its examples. I found some minor differences in API interfaces on other platforms(i.e.:PPC). Also some of the latest kernels have altered some of the APIs slightly.
For who:
In my opinion this book is for software engineers/developers who has experience in C and Makefiles. Any embedded development experience will help understand why things are done the way they are and the deeper issues of concurrency and timing.
Conclusion:
This book is the benchmark for Linux device driver books. It is well set out and a easy read. To get the maximum out of the book you will need to play around with the examples/ideas that are covered in this book.