/* * Copyright 2012, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * Ithamar R. Adema */ #include #include #include #include #include #include #include #include //#define TRACE_NORFLASH #ifdef TRACE_NORFLASH #define TRACE(x...) dprintf("nor: " x) #else #define TRACE(x...) #endif #define NORFLASH_DEVICE_MODULE_NAME "drivers/disk/norflash/device_v1" #define NORFLASH_DRIVER_MODULE_NAME "drivers/disk/norflash/driver_v1" #define NORFLASH_ADDR 0x00000000 #define SIZE_IN_BLOCKS 256 /* Hide the start of NOR since U-Boot lives there */ #define HIDDEN_BLOCKS 2 struct nor_driver_info { device_node *node; size_t blocksize; size_t totalsize; area_id id; uint8 *mapped; }; static device_manager_info *sDeviceManager; static status_t nor_init_device(void *_info, void **_cookie) { TRACE("init_device\n"); nor_driver_info *info = (nor_driver_info*)_info; info->mapped = NULL; info->blocksize = 128 * 1024; info->totalsize = (SIZE_IN_BLOCKS - HIDDEN_BLOCKS) * info->blocksize; info->id = map_physical_memory("NORFlash", NORFLASH_ADDR, info->totalsize, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&info->mapped); if (info->id < 0) return info->id; info->mapped += HIDDEN_BLOCKS * info->blocksize; *_cookie = info; return B_OK; } static void nor_uninit_device(void *_cookie) { TRACE("uninit_device\n"); nor_driver_info *info = (nor_driver_info*)_cookie; if (info) delete_area(info->id); } static status_t nor_open(void *deviceCookie, const char *path, int openMode, void **_cookie) { TRACE("open(%s)\n", path); *_cookie = deviceCookie; return B_OK; } static status_t nor_close(void *_cookie) { TRACE("close()\n"); return B_OK; } static status_t nor_free(void *_cookie) { TRACE("free()\n"); return B_OK; } static status_t nor_ioctl(void *cookie, uint32 op, void *buffer, size_t length) { nor_driver_info *info = (nor_driver_info*)cookie; TRACE("ioctl(%ld,%lu)\n", op, length); switch (op) { case B_GET_GEOMETRY: { device_geometry *deviceGeometry = (device_geometry*)buffer; deviceGeometry->removable = false; deviceGeometry->bytes_per_sector = info->blocksize; deviceGeometry->sectors_per_track = info->totalsize / info->blocksize; deviceGeometry->cylinder_count = 1; deviceGeometry->head_count = 1; deviceGeometry->device_type = B_DISK; deviceGeometry->removable = false; deviceGeometry->read_only = true; deviceGeometry->write_once = false; return B_OK; } break; case B_GET_DEVICE_NAME: strlcpy((char*)buffer, "NORFlash", length); break; } return B_ERROR; } static status_t nor_read(void *_cookie, off_t position, void *data, size_t *numbytes) { nor_driver_info *info = (nor_driver_info*)_cookie; TRACE("read(%lld,%lu)\n", position, *numbytes); position += HIDDEN_BLOCKS * info->blocksize; if (position + *numbytes > info->totalsize) *numbytes = info->totalsize - (position + *numbytes); memcpy(data, info->mapped + position, *numbytes); return B_OK; } static status_t nor_write(void *_cookie, off_t position, const void *data, size_t *numbytes) { TRACE("write(%lld,%lu)\n", position, *numbytes); *numbytes = 0; return B_ERROR; } static float nor_supports_device(device_node *parent) { const char *bus; TRACE("supports_device\n"); if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) return B_ERROR; if (strcmp(bus, "generic")) return 0.0; return 1.0; } static status_t nor_register_device(device_node *node) { TRACE("register_device\n"); // ready to register device_attr attrs[] = { { NULL } }; return sDeviceManager->register_node(node, NORFLASH_DRIVER_MODULE_NAME, attrs, NULL, NULL); } static status_t nor_init_driver(device_node *node, void **cookie) { TRACE("init_driver\n"); nor_driver_info *info = (nor_driver_info*)malloc(sizeof(nor_driver_info)); if (info == NULL) return B_NO_MEMORY; memset(info, 0, sizeof(*info)); info->node = node; *cookie = info; return B_OK; } static void nor_uninit_driver(void *_cookie) { TRACE("uninit_driver\n"); nor_driver_info *info = (nor_driver_info*)_cookie; free(info); } static status_t nor_register_child_devices(void *_cookie) { TRACE("register_child_devices\n"); nor_driver_info *info = (nor_driver_info*)_cookie; status_t status; status = sDeviceManager->publish_device(info->node, "disk/nor/0/raw", NORFLASH_DEVICE_MODULE_NAME); return status; } struct device_module_info sNORFlashDiskDevice = { { NORFLASH_DEVICE_MODULE_NAME, 0, NULL }, nor_init_device, nor_uninit_device, NULL, //nor_remove, nor_open, nor_close, nor_free, nor_read, nor_write, NULL, // nor_io, nor_ioctl, NULL, // select NULL, // deselect }; struct driver_module_info sNORFlashDiskDriver = { { NORFLASH_DRIVER_MODULE_NAME, 0, NULL }, nor_supports_device, nor_register_device, nor_init_driver, nor_uninit_driver, nor_register_child_devices, NULL, // rescan NULL, // removed }; module_dependency module_dependencies[] = { { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager }, { } }; module_info *modules[] = { (module_info*)&sNORFlashDiskDriver, (module_info*)&sNORFlashDiskDevice, NULL };