MMIO wrapper functions for the Linux userspace /dev/mem
device.
#include <periphery/mmio.h>
/* Primary Functions */
mmio_t *mmio_new(void);
int mmio_open(mmio_t *mmio, uintptr_t base, size_t size);
int mmio_open_advanced(mmio_t *mmio, uintptr_t base, size_t size, const char *path);
void *mmio_ptr(mmio_t *mmio);
int mmio_read32(mmio_t *mmio, uintptr_t offset, uint32_t *value);
int mmio_read16(mmio_t *mmio, uintptr_t offset, uint16_t *value);
int mmio_read8(mmio_t *mmio, uintptr_t offset, uint8_t *value);
int mmio_read(mmio_t *mmio, uintptr_t offset, uint8_t *buf, size_t len);
int mmio_write32(mmio_t *mmio, uintptr_t offset, uint32_t value);
int mmio_write16(mmio_t *mmio, uintptr_t offset, uint16_t value);
int mmio_write8(mmio_t *mmio, uintptr_t offset, uint8_t value);
int mmio_write(mmio_t *mmio, uintptr_t offset, const uint8_t *buf, size_t len);
int mmio_close(mmio_t *mmio);
void mmio_free(mmio_t *mmio);
/* Miscellaneous */
uintptr_t mmio_base(mmio_t *mmio);
size_t mmio_size(mmio_t *mmio);
int mmio_tostring(mmio_t *mmio, char *str, size_t len);
/* Error Handling */
int mmio_errno(mmio_t *mmio);
const char *mmio_errmsg(mmio_t *mmio);
mmio_t *mmio_new(void);
Allocate a MMIO handle.
Returns a valid handle on success, or NULL on failure.
int mmio_open(mmio_t *mmio, uintptr_t base, size_t size);
Map the region of physical memory specified by the base
physical address and size
size in bytes, using the default /dev/mem
memory character device.
mmio
should be a valid pointer to an allocated MMIO handle structure. Neither base
nor size
need be aligned to a page boundary.
Returns 0 on success, or a negative MMIO error code on failure.
int mmio_open_advanced(mmio_t *mmio, uintptr_t base, size_t size, const char *path);
Map the region of physical memory specified by the base
physical address and size
size in bytes, using the specified memory character device. This open function can be used with sandboxed memory character devices, e.g. /dev/gpiomem
.
mmio
should be a valid pointer to an allocated MMIO handle structure. Neither base
nor size
need be aligned to a page boundary.
Returns 0 on success, or a negative MMIO error code on failure.
void *mmio_ptr(mmio_t *mmio);
Return the pointer to the mapped physical memory.
This function is a simple accessor to the MMIO handle structure and always succeeds.
int mmio_read32(mmio_t *mmio, uintptr_t offset, uint32_t *value);
int mmio_read16(mmio_t *mmio, uintptr_t offset, uint16_t *value);
int mmio_read8(mmio_t *mmio, uintptr_t offset, uint8_t *value);
int mmio_read(mmio_t *mmio, uintptr_t offset, uint8_t *buf, size_t len);
Read 32-bits, 16-bits, 8-bits, or an array of bytes, respectively, from mapped physical memory, starting at the specified byte offset, relative to the base address the MMIO handle was opened with.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
Returns 0 on success, or a negative MMIO error code on failure.
int mmio_write32(mmio_t *mmio, uintptr_t offset, uint32_t value);
int mmio_write16(mmio_t *mmio, uintptr_t offset, uint16_t value);
int mmio_write8(mmio_t *mmio, uintptr_t offset, uint8_t value);
int mmio_write(mmio_t *mmio, uintptr_t offset, const uint8_t *buf, size_t len);
Write 32-bits, 16-bits, 8-bits, or an array of bytes, respectively, to mapped physical memory, starting at the specified byte offset, relative to the base address the MMIO handle was opened with.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
Returns 0 on success, or a negative MMIO error code on failure.
int mmio_close(mmio_t *mmio);
Unmap mapped physical memory.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
Returns 0 on success, or a negative MMIO error code on failure.
void mmio_free(mmio_t *mmio);
Free a MMIO handle.
uintptr_t mmio_base(mmio_t *mmio);
Return the base address the MMIO handle was opened with.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
This function is a simple accessor to the MMIO handle structure and always succeeds.
size_t mmio_size(mmio_t *mmio);
Return the size the MMIO handle was opened with.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
This function is a simple accessor to the MMIO handle structure and always succeeds.
int mmio_tostring(mmio_t *mmio, char *str, size_t len);
Return a string representation of the MMIO handle.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
This function behaves and returns like snprintf()
.
int mmio_errno(mmio_t *mmio);
Return the libc errno of the last failure that occurred.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
const char *mmio_errmsg(mmio_t *mmio);
Return a human readable error message of the last failure that occurred.
mmio
should be a valid pointer to an MMIO handle opened with one of the mmio_open*()
functions.
The periphery MMIO functions return 0 on success or one of the negative error codes below on failure.
The libc errno of the failure in an underlying libc library call can be obtained with the mmio_errno()
helper function. A human readable error message can be obtained with the mmio_errmsg()
helper function.
Error Code | Description |
---|---|
MMIO_ERROR_ARG |
Invalid arguments |
MMIO_ERROR_OPEN |
Opening MMIO |
MMIO_ERROR_CLOSE |
Closing MMIO |
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "mmio.h"
struct am335x_rtcss_registers {
uint32_t seconds; /* 0x00 */
uint32_t minutes; /* 0x04 */
uint32_t hours; /* 0x08 */
/* ... */
};
int main(void) {
mmio_t *mmio;
uint32_t mac_id0_lo, mac_id0_hi;
volatile struct am335x_rtcss_registers *regs;
mmio = mmio_new();
/* Open control module */
if (mmio_open(mmio, 0x44E10000, 0x1000) < 0) {
fprintf(stderr, "mmio_open(): %s\n", mmio_errmsg(mmio));
exit(1);
}
/* Read lower 2 bytes of MAC address */
if (mmio_read32(mmio, 0x630, &mac_id0_lo) < 0) {
fprintf(stderr, "mmio_read32(): %s\n", mmio_errmsg(mmio));
exit(1);
}
/* Read upper 4 bytes of MAC address */
if (mmio_read32(mmio, 0x634, &mac_id0_hi) < 0) {
fprintf(stderr, "mmio_read32(): %s\n", mmio_errmsg(mmio));
exit(1);
}
printf("MAC address: %04x%08x\n", mac_id0_lo, mac_id0_hi);
mmio_close(mmio);
/* Open RTC subsystem */
if (mmio_open(mmio, 0x44E3E000, 0x1000) < 0) {
fprintf(stderr, "mmio_open(): %s\n", mmio_errmsg(mmio));
exit(1);
}
regs = mmio_ptr(mmio);
/* Read current RTC time */
printf("hours: %02x minutes: %02x seconds %02x\n", regs->hours, regs->minutes, regs->seconds);
mmio_close(mmio);
mmio_free(mmio);
return 0;
}