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
39 struct 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
49 static device_manager_info *sDeviceManager;
50
51
52 static status_t
nor_init_device(void * _info,void ** _cookie)53 nor_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
74 static void
nor_uninit_device(void * _cookie)75 nor_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
84 static status_t
nor_open(void * deviceCookie,const char * path,int openMode,void ** _cookie)85 nor_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
94 static status_t
nor_close(void * _cookie)95 nor_close(void *_cookie)
96 {
97 TRACE("close()\n");
98 return B_OK;
99 }
100
101
102 static status_t
nor_free(void * _cookie)103 nor_free(void *_cookie)
104 {
105 TRACE("free()\n");
106 return B_OK;
107 }
108
109
110 static status_t
nor_ioctl(void * cookie,uint32 op,void * buffer,size_t length)111 nor_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
142 static status_t
nor_read(void * _cookie,off_t position,void * data,size_t * numbytes)143 nor_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
159 static status_t
nor_write(void * _cookie,off_t position,const void * data,size_t * numbytes)160 nor_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
168 static float
nor_supports_device(device_node * parent)169 nor_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
184 static status_t
nor_register_device(device_node * node)185 nor_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
198 static status_t
nor_init_driver(device_node * node,void ** cookie)199 nor_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
216 static void
nor_uninit_driver(void * _cookie)217 nor_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
225 static status_t
nor_register_child_devices(void * _cookie)226 nor_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
239 struct 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
264 struct 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
281 module_dependency module_dependencies[] = {
282 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager },
283 { }
284 };
285
286
287 module_info *modules[] = {
288 (module_info*)&sNORFlashDiskDriver,
289 (module_info*)&sNORFlashDiskDevice,
290 NULL
291 };
292