-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathcon_mem.c
107 lines (89 loc) · 2.86 KB
/
con_mem.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* Copyright (c) 2013 Sergey Ryazanov <ryazanov.s.a@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "atheepmgr.h"
struct mem_priv {
int devmem_fd;
off_t io_addr;
void *io_map;
};
static uint32_t mem_reg_read(struct atheepmgr *aem, uint32_t reg)
{
struct mem_priv *mpd = aem->con_priv;
return *((volatile uint32_t *)(mpd->io_map + reg));
}
static void mem_reg_write(struct atheepmgr *aem, uint32_t reg, uint32_t val)
{
struct mem_priv *mpd = aem->con_priv;
*((volatile uint32_t *)(mpd->io_map + reg)) = val;
}
static void mem_reg_rmw(struct atheepmgr *aem, uint32_t reg, uint32_t set,
uint32_t clr)
{
struct mem_priv *mpd = aem->con_priv;
uint32_t tmp;
tmp = *((volatile uint32_t *)(mpd->io_map + reg));
tmp &= ~clr;
tmp |= set;
*((volatile uint32_t *)(mpd->io_map + reg)) = tmp;
}
static int mem_init(struct atheepmgr *aem, const char *arg_str)
{
struct mem_priv *mpd = aem->con_priv;
static const size_t mem_size = 0x40000; /* TODO: use autodetection */
char *endp;
errno = 0;
mpd->io_addr = strtoul(arg_str, &endp, 16);
if (!mpd->io_addr || *endp != '\0' || errno || mpd->io_addr % 4 != 0) {
fprintf(stderr, "conmem: invalid I/O memory start address -- %s\n",
arg_str);
return -EINVAL;
}
mpd->devmem_fd = open("/dev/mem", O_RDWR);
if (mpd->devmem_fd < 0) {
fprintf(stderr, "conmem: opening /dev/mem failed: %s\n",
strerror(errno));
return -errno;
}
mpd->io_map = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FILE, mpd->devmem_fd, mpd->io_addr);
if (MAP_FAILED == mpd->io_map) {
fprintf(stderr, "conmem: mmap of device at 0x%08lx for 0x%08lx bytes failed: %s\n",
(unsigned long)mpd->io_addr,
(unsigned long)mem_size, strerror(errno));
close(mpd->devmem_fd);
return -errno;
}
return 0;
}
static void mem_clean(struct atheepmgr *aem)
{
struct mem_priv *mpd = aem->con_priv;
close(mpd->devmem_fd);
}
const struct connector con_mem = {
.name = "Mem",
.priv_data_sz = sizeof(struct mem_priv),
.caps = CON_CAP_HW,
.init = mem_init,
.clean = mem_clean,
.reg_read = mem_reg_read,
.reg_write = mem_reg_write,
.reg_rmw = mem_reg_rmw,
};