1/*
2 * Copyright 2012, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ithamar R. Adema <ithamar@upgrade-android.com>
7 */
8
9
10#include <string.h>
11#include <stdlib.h>
12#include <stdio.h>
13#include <ctype.h>
14
15#include <drivers/device_manager.h>
16#include <drivers/KernelExport.h>
17#include <drivers/Drivers.h>
18#include <kernel/OS.h>
19
20
21//#define TRACE_NORFLASH
22#ifdef TRACE_NORFLASH
23#define TRACE(x...)	dprintf("nor: " x)
24#else
25#define TRACE(x...)
26#endif
27
28
29#define NORFLASH_DEVICE_MODULE_NAME	"drivers/disk/norflash/device_v1"
30#define NORFLASH_DRIVER_MODULE_NAME	"drivers/disk/norflash/driver_v1"
31
32
33#define NORFLASH_ADDR	0x00000000
34#define SIZE_IN_BLOCKS	256
35
36/* Hide the start of NOR since U-Boot lives there */
37#define HIDDEN_BLOCKS	2
38
39struct nor_driver_info {
40	device_node *node;
41	size_t blocksize;
42	size_t totalsize;
43
44	area_id id;
45	uint8 *mapped;
46};
47
48
49static device_manager_info *sDeviceManager;
50
51
52static status_t
53nor_init_device(void *_info, void **_cookie)
54{
55	TRACE("init_device\n");
56	nor_driver_info *info = (nor_driver_info*)_info;
57
58	info->mapped = NULL;
59	info->blocksize = 128 * 1024;
60	info->totalsize = (SIZE_IN_BLOCKS - HIDDEN_BLOCKS) * info->blocksize;
61
62	info->id = map_physical_memory("NORFlash", NORFLASH_ADDR, info->totalsize, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&info->mapped);
63	if (info->id < 0)
64		return info->id;
65
66	info->mapped += HIDDEN_BLOCKS * info->blocksize;
67
68
69	*_cookie = info;
70	return B_OK;
71}
72
73
74static void
75nor_uninit_device(void *_cookie)
76{
77	TRACE("uninit_device\n");
78	nor_driver_info *info = (nor_driver_info*)_cookie;
79	if (info)
80		delete_area(info->id);
81}
82
83
84static status_t
85nor_open(void *deviceCookie, const char *path, int openMode,
86	void **_cookie)
87{
88	TRACE("open(%s)\n", path);
89	*_cookie = deviceCookie;
90	return B_OK;
91}
92
93
94static status_t
95nor_close(void *_cookie)
96{
97	TRACE("close()\n");
98	return B_OK;
99}
100
101
102static status_t
103nor_free(void *_cookie)
104{
105	TRACE("free()\n");
106	return B_OK;
107}
108
109
110static status_t
111nor_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
112{
113	nor_driver_info *info = (nor_driver_info*)cookie;
114	TRACE("ioctl(%ld,%lu)\n", op, length);
115
116	switch (op) {
117		case B_GET_GEOMETRY:
118		{
119			device_geometry *deviceGeometry = (device_geometry*)buffer;
120			deviceGeometry->removable = false;
121			deviceGeometry->bytes_per_sector = info->blocksize;
122			deviceGeometry->sectors_per_track = info->totalsize / info->blocksize;
123			deviceGeometry->cylinder_count = 1;
124			deviceGeometry->head_count = 1;
125			deviceGeometry->device_type = B_DISK;
126			deviceGeometry->removable = false;
127			deviceGeometry->read_only = true;
128			deviceGeometry->write_once = false;
129			return B_OK;
130		}
131		break;
132
133		case B_GET_DEVICE_NAME:
134			strlcpy((char*)buffer, "NORFlash", length);
135			break;
136	}
137
138	return B_ERROR;
139}
140
141
142static status_t
143nor_read(void *_cookie, off_t position, void *data, size_t *numbytes)
144{
145	nor_driver_info *info = (nor_driver_info*)_cookie;
146	TRACE("read(%lld,%lu)\n", position, *numbytes);
147
148	position += HIDDEN_BLOCKS * info->blocksize;
149
150	if (position + *numbytes > info->totalsize)
151		*numbytes = info->totalsize - (position + *numbytes);
152
153	memcpy(data, info->mapped + position, *numbytes);
154
155	return B_OK;
156}
157
158
159static status_t
160nor_write(void *_cookie, off_t position, const void *data, size_t *numbytes)
161{
162	TRACE("write(%lld,%lu)\n", position, *numbytes);
163	*numbytes = 0;
164	return B_ERROR;
165}
166
167
168static float
169nor_supports_device(device_node *parent)
170{
171	const char *bus;
172	TRACE("supports_device\n");
173
174	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
175		return B_ERROR;
176
177	if (strcmp(bus, "generic"))
178		return 0.0;
179
180	return 1.0;
181}
182
183
184static status_t
185nor_register_device(device_node *node)
186{
187	TRACE("register_device\n");
188	// ready to register
189	device_attr attrs[] = {
190		{ NULL }
191	};
192
193	return sDeviceManager->register_node(node, NORFLASH_DRIVER_MODULE_NAME,
194		attrs, NULL, NULL);
195}
196
197
198static status_t
199nor_init_driver(device_node *node, void **cookie)
200{
201	TRACE("init_driver\n");
202
203	nor_driver_info *info = (nor_driver_info*)malloc(sizeof(nor_driver_info));
204	if (info == NULL)
205		return B_NO_MEMORY;
206
207	memset(info, 0, sizeof(*info));
208
209	info->node = node;
210
211	*cookie = info;
212	return B_OK;
213}
214
215
216static void
217nor_uninit_driver(void *_cookie)
218{
219	TRACE("uninit_driver\n");
220	nor_driver_info *info = (nor_driver_info*)_cookie;
221	free(info);
222}
223
224
225static status_t
226nor_register_child_devices(void *_cookie)
227{
228	TRACE("register_child_devices\n");
229	nor_driver_info *info = (nor_driver_info*)_cookie;
230	status_t status;
231
232	status = sDeviceManager->publish_device(info->node, "disk/nor/0/raw",
233		NORFLASH_DEVICE_MODULE_NAME);
234
235	return status;
236}
237
238
239struct device_module_info sNORFlashDiskDevice = {
240	{
241		NORFLASH_DEVICE_MODULE_NAME,
242		0,
243		NULL
244	},
245
246	nor_init_device,
247	nor_uninit_device,
248	NULL, //nor_remove,
249
250	nor_open,
251	nor_close,
252	nor_free,
253	nor_read,
254	nor_write,
255	NULL,	// nor_io,
256	nor_ioctl,
257
258	NULL,	// select
259	NULL,	// deselect
260};
261
262
263
264struct driver_module_info sNORFlashDiskDriver = {
265	{
266		NORFLASH_DRIVER_MODULE_NAME,
267		0,
268		NULL
269	},
270
271	nor_supports_device,
272	nor_register_device,
273	nor_init_driver,
274	nor_uninit_driver,
275	nor_register_child_devices,
276	NULL,	// rescan
277	NULL,	// removed
278};
279
280
281module_dependency module_dependencies[] = {
282	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager },
283	{ }
284};
285
286
287module_info *modules[] = {
288	(module_info*)&sNORFlashDiskDriver,
289	(module_info*)&sNORFlashDiskDevice,
290	NULL
291};
292