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