If you can bear some of my old C code, here is an example of performing the mapping in C
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <limits.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <termios.h>
#include <ctype.h>
#define FALSE (0)
#define TRUE (!FALSE)
#define NULL_FD ((int)0)
#define MAP_NAME_LEN (20)
#define NO_MASK (UINT_MAX)
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */
#define PADS_BASE (BCM2708_PERI_BASE + 0x100000) /* PADS */
#define PADS0 (11 * 4)
#define PADS1 (12 * 4)
#define PADS2 (13 * 4)
#define PADS_CURRENT_MASK (0x00000007)
typedef struct raw_memory {
void *accessor; // Base location for memory access
unsigned int offset; // Offset into base for the starting point
unsigned int length;
char name[MAP_NAME_LEN + 1];
} raw_memory;
int memFile = NULL_FD;
raw_memory rawMemPads= {MAP_FAILED, 0, 0, "PADS"};
void RegWrite(raw_memory *base, unsigned int address, unsigned int mask, unsigned int value);
unsigned int RegRead(raw_memory *base, unsigned int address);
BOOL MapMemory(raw_memory *base, int device, unsigned int startAddress, size_t size);
void UnmapMemory(raw_memory *base);
void RegWrite(raw_memory *base, unsigned int address, unsigned int mask, unsigned int value) {
if (base->accessor == MAP_FAILED) {
printf("RegWrite failed due to an unmapped base (%s)!\n", base->name);
} else if (address >= base->length) {
printf("RegWrite failed due to address out of bounds (%s, 0x%08X)!\n", base->name, address);
} else {
if (mask != NO_MASK) {
unsigned int read = RegRead(base, address);
value &= mask;
value |= (~mask) & read;
}
*((unsigned int *)(base->accessor + base->offset + address)) = value;
}
}
BOOL MapMemory(raw_memory *base, int device, unsigned int startAddress, size_t size) {
// Unmap first if already allocated
if (base->accessor != MAP_FAILED) {
UnmapMemory(base);
}
// Align start address to the page size (we can only map page aligned blocks)
base->offset = (unsigned int)(startAddress / getpagesize()) * getpagesize();
// Compute the necessary size to cover the alignment
base->length = (unsigned int)size;
size += (size_t)(startAddress - base->offset);
// Map the memory from the device to a local address
base->accessor = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, device, base->offset);
if (base->accessor == MAP_FAILED) {
return FALSE;
} else {
// Calculate the offset needed by read / write functions to get startAddress as 0
base->offset = startAddress - base->offset;
return TRUE;
}
}
void UnmapMemory(raw_memory *base) {
if (base->accessor != MAP_FAILED) {
munmap(base->accessor, base->offset + base->length);
base->accessor = MAP_FAILED;
} else {
}
}
int main(void) {
// Enable raw memory access
if (memFile == NULL_FD) memFile = open("/dev/mem", O_RDWR | O_SYNC);
if (memFile == NULL_FD) {
printf("Failed to open /dev/mem (are we root?) !\n");
return 1;
}
// Map GPIO memory
if (!MapMemory(&rawMemPads, memFile, PADS_BASE, 1024)) {
printf("Failed to map GPIO device memory !\n");
return 2;
}
// Actual work here
RegWrite(&rawMem, PADS0, PADS_CURRENT_MASK, 7); // Sets GPIO 0-27 to 16mA
RegWrite(&rawMem, PADS1, PADS_CURRENT_MASK, 4); // Sets GPIO 28-45 to 10mA
RegWrite(&rawMem, PADS2, PADS_CURRENT_MASK, 0); // Sets GPIO 46-53 to 2mA
// Any other code here
//
// Unmap the GPIO memory
if (rawMemPads.accessor != MAP_FAILED) {
UnmapMemory(&rawMemPads);
}
// Disable raw memory access
if (memFile != NULL_FD) {
close(memFile);
memFile = NULL_FD;
}
return 0;
}
Excuse the length, it is a long bit of setup so that the main bit of code for doing masked writes is short, also it allows for out-of-alignment pages, which is not really an issue here (I had this problem previously with a different embedded register map).
Note that you will need to run the binary as root or the mapping will fail as permission denied to /dev/mem