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 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 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 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 95 nor_close(void *_cookie) 96 { 97 TRACE("close()\n"); 98 return B_OK; 99 } 100 101 102 static status_t 103 nor_free(void *_cookie) 104 { 105 TRACE("free()\n"); 106 return B_OK; 107 } 108 109 110 static status_t 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 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 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 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 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 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 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 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