1/*
2 * Copyright 2007, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5#include <Drivers.h>
6#include <KernelExport.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/types.h>
10
11#define DRIVER_NAME "mem"
12#define DEVICE_NAME "misc/mem"
13
14#define DEVMNT "/dev/"
15
16/* also publish /dev/mem */
17#define PUBLISH_DEV_MEM
18
19static status_t mem_open(const char*, uint32, void**);
20static status_t mem_close(void*);
21static status_t mem_free(void*);
22static status_t mem_read(void*, off_t, void*, size_t*);
23static status_t mem_write(void*, off_t, const void*, size_t*);
24
25static area_id mem_map_target(off_t position, size_t length, uint32 protection,
26	void **virtualAddress);
27
28static const char* mem_name[] = {
29	DEVICE_NAME,
30#ifdef PUBLISH_DEV_MEM
31	DRIVER_NAME,
32#endif
33	NULL
34};
35
36
37device_hooks mem_hooks = {
38	mem_open,
39	mem_close,
40	mem_free,
41	NULL, /*mem_control,*/
42	mem_read,
43	mem_write,
44};
45
46int32 api_version = B_CUR_DRIVER_API_VERSION;
47
48status_t
49init_hardware(void)
50{
51	return B_OK;
52}
53
54
55status_t
56init_driver(void)
57{
58	return B_OK;
59}
60
61
62void
63uninit_driver(void)
64{
65}
66
67
68const char**
69publish_devices(void)
70{
71	return mem_name;
72}
73
74
75device_hooks*
76find_device(const char* name)
77{
78	return &mem_hooks;
79}
80
81
82status_t
83mem_open(const char* name, uint32 flags, void** cookie)
84{
85	// not really needed.
86	*cookie = NULL;
87	return B_OK;
88}
89
90
91status_t
92mem_close(void* cookie)
93{
94	return B_OK;
95}
96
97
98status_t
99mem_free(void* cookie)
100{
101	return B_OK;
102}
103
104
105status_t
106mem_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
107{
108	void *virtualAddress;
109	area_id area;
110
111	/* check permissions */
112	if (getuid() != 0 && geteuid() != 0) {
113		*numBytes = 0;
114		return EPERM;
115	}
116
117	area = mem_map_target(position, *numBytes, B_READ_AREA, &virtualAddress);
118	if (area < 0) {
119		*numBytes = 0;
120		return area;
121	}
122
123	memcpy(buffer, virtualAddress, *numBytes);
124	delete_area(area);
125	return B_OK;
126}
127
128
129status_t
130mem_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
131{
132	void *virtualAddress;
133	area_id area;
134
135	/* check permissions */
136	if (getuid() != 0 && geteuid() != 0) {
137		*numBytes = 0;
138		return EPERM;
139	}
140
141	area = mem_map_target(position, *numBytes, B_WRITE_AREA, &virtualAddress);
142	if (area < 0) {
143		*numBytes = 0;
144		return area;
145	}
146
147	memcpy(virtualAddress, buffer, *numBytes);
148	delete_area(area);
149	return B_OK;
150}
151
152
153area_id
154mem_map_target(off_t position, size_t length, uint32 protection,
155	void **virtualAddress)
156{
157	area_id area;
158	phys_addr_t physicalAddress;
159	size_t offset;
160	size_t size;
161
162	/* SIZE_MAX actually but 2G should be enough anyway */
163	if (length > SSIZE_MAX - B_PAGE_SIZE)
164		return EINVAL;
165
166	/* the first page address */
167	physicalAddress = (phys_addr_t)position & ~((off_t)B_PAGE_SIZE - 1);
168
169	/* offset of target into it */
170	offset = position - (off_t)physicalAddress;
171
172	/* size of the whole mapping (page rounded) */
173	size = (offset + length + B_PAGE_SIZE - 1) & ~((size_t)B_PAGE_SIZE - 1);
174	area = map_physical_memory("mem_driver_temp", physicalAddress, size,
175		B_ANY_KERNEL_ADDRESS, protection, virtualAddress);
176	if (area < 0)
177		return area;
178
179	*virtualAddress += offset;
180	return area;
181}
182