blob: 0ce4254455f749ca70f99f64e2e1f73f8160548f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <ddktl/device.h>
#include <fbl/alloc_checker.h>
#include <fbl/macros.h>
#include <fbl/unique_ptr.h>
#include <zircon/device/ram-nand.h>
#include <zircon/types.h>
#include "device.h"
#include "ram-nand-ctl.h"
namespace {
class RamNandCtl;
using RamNandCtlDeviceType = ddk::Device<RamNandCtl, ddk::Ioctlable>;
class RamNandCtl : public RamNandCtlDeviceType {
public:
explicit RamNandCtl(zx_device_t* parent) : RamNandCtlDeviceType(parent) {}
zx_status_t Bind() { return DdkAdd("nand-ctl"); }
void DdkRelease() { delete this; }
zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len,
void* out_buf, size_t out_len, size_t* out_actual);
private:
zx_status_t CreateDevice(const NandParams& params, void* out_buf, size_t* out_actual);
DISALLOW_COPY_ASSIGN_AND_MOVE(RamNandCtl);
};
zx_status_t RamNandCtl::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len,
void* out_buf, size_t out_len, size_t* out_actual) {
if (out_len < sizeof(ram_nand_name_t)) {
return ZX_ERR_INVALID_ARGS;
}
switch (op) {
case IOCTL_RAM_NAND_CREATE: {
if (in_len != sizeof(nand_info_t)) {
return ZX_ERR_INVALID_ARGS;
}
const NandParams* params = static_cast<const NandParams*>(in_buf);
return CreateDevice(*params, out_buf, out_actual);
}
default:
return ZX_ERR_NOT_SUPPORTED;
}
}
zx_status_t RamNandCtl::CreateDevice(const NandParams& params, void* out_buf,
size_t* out_actual) {
fbl::AllocChecker checker;
fbl::unique_ptr<RamNandDevice> device(new (&checker) RamNandDevice(zxdev(), params));
if (!checker.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = device->Bind();
if (status != ZX_OK) {
return status;
}
*out_actual = strlen(device->name());
strcpy(static_cast<char*>(out_buf), device->name());
// devmgr is now in charge of the device.
__UNUSED RamNandDevice* dummy = device.release();
return ZX_OK;
}
} // namespace
zx_status_t ram_nand_driver_bind(void* ctx, zx_device_t* parent) {
fbl::AllocChecker checker;
fbl::unique_ptr<RamNandCtl> device(new (&checker) RamNandCtl(parent));
if (!checker.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = device->Bind();
if (status == ZX_OK) {
// devmgr is now in charge of the device.
__UNUSED RamNandCtl* dummy = device.release();
}
return status;
}