【HarmonyOS HiSpark AI Camera试用连载 】第一个驱动程序 - HarmonyOS技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

[文章]

【HarmonyOS HiSpark AI Camera试用连载 】第一个驱动程序

本帖最后由 jf_64182030 于 2020-11-1 16:35 编辑

一、前言
本文主要介绍hi3516上串口的驱动配置和测试,以及主体驱动代码的跟踪。所涉及的驱动程序源码位于vendor/huawei/hdf/sample目录。
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c

二、参考文档:
$ vi ~/harmony/sdk/docs/docs-en/quick-start/developing-the-first-driver-running-on-hi3516.md
$ vi ~/harmony/sdk/docs/docs-en/guide/developing-the-first-driver-program-running-on-the-hi3516-development-board.md

三、驱动修改和跟踪
修改HDF框架的驱动配置文件:
$ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
  1. root {
  2.     platform {
  3.         ...
  4.         controller_0x120a3000 :: uart_controller {
  5.             num = 3;
  6.             baudrate = 9600;
  7.             regPbase = 0x120a3000;
  8.             interrupt = 41;
  9.             match_attr = "hisilicon_hi35xx_uart_3";
  10.         }

  11. +++
  12.         // 平台配置:串口控制器参数配置
  13.         uart_sample {
  14.             num = 5;
  15.             base = 0x120a0000;  // UART base register address
  16.             irqNum = 38;
  17.             baudrate = 115200;
  18.             uartClk = 24000000; // 24 M
  19.             wlen = 0x60;        // 8 bit width
  20.             parity = 0;
  21.             stopBit = 0;
  22.             match_attr = "sample_uart_5";
  23.         }
  24. +++
  25.     }
  26. }
修改HDF框架的设备配置文件
$ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
  1. root {
  2.     device_info {
  3.         platform :: host {
  4.             hostName = "platform_host";
  5.             priority = 50;
  6.             device_uart :: device {
  7. ...
  8.                 device3 :: deviceNode {
  9.                     policy = 1;
  10.                     priority = 40;
  11.                     permission = 0644;
  12.                     moduleName = "HDF_PLATFORM_UART";
  13.                     serviceName = "HDF_PLATFORM_UART_3";
  14.                     deviceMatchAttr = "hisilicon_hi35xx_uart_3";
  15.                 }
  16. +++
  17.                 // 描述设备节点信息
  18.                 device5 :: deviceNode {
  19.                     policy = 2;
  20.                     priority = 10;
  21.                     permission = 0660;
  22.                     moduleName = "UART_SAMPLE";
  23.                     serviceName = "HDF_PLATFORM_UART_5";
  24.                     deviceMatchAttr = "sample_uart_5";
  25.                 }
  26. +++
  27.             }
  28.         }
  29.     }
  30. }
基于HDF框架注册UART驱动的入口HdfDriverEntry,代码如下:
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
  1. // 修改HDF框架的驱动配置文件
  2. $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
  3. root {
  4.     platform {
  5. +++
  6.         // 平台配置:串口控制器参数配置
  7.         uart_sample {
  8.             num = 5;
  9.             base = 0x120a0000;  // UART base register address
  10.             irqNum = 38;
  11.             baudrate = 115200;
  12.             uartClk = 24000000; // 24 M
  13.             wlen = 0x60;        // 8 bit width
  14.             parity = 0;
  15.             stopBit = 0;
  16.             match_attr = "sample_uart_5"; // uart_config.hcs和device_info.hcs通过deviceMatchAttr匹配
  17.         }
  18. +++
  19.     }
  20. }


  21. // 修改HDF框架的设备配置文件
  22. $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
  23. root {
  24.     device_info {
  25.         platform :: host {
  26.             hostName = "platform_host";
  27.             priority = 50;
  28.             device_uart :: device {
  29. +++
  30.                 // 描述设备节点信息
  31.                 device5 :: deviceNode {
  32.                     policy = 2;
  33.                     priority = 10;
  34.                     permission = 0660;
  35.                     moduleName = "UART_SAMPLE"; // 设备和驱动源码uart_sample.c通过moduleName匹配
  36.                     serviceName = "HDF_PLATFORM_UART_5";
  37.                     deviceMatchAttr = "sample_uart_5"; // uart_config.hcs和device_info.hcs通过deviceMatchAttr匹配
  38.                 }
  39. +++
  40.             }
  41.         }
  42.     }
  43. }

  44. // 系统启动过程中设备和驱动的加载(绑定)
  45. $ vi ~/harmony/sdk/drivers/hdf/frameworks/core/host/src/hdf_driver_loader.c
  46. static struct HdfDeviceNode *HdfDriverLoaderLoadNode(struct IDriverLoader *loader, const struct HdfDeviceInfo *deviceInfo)
  47.     struct HdfDriverEntry *driverEntry = NULL;
  48.     struct HdfDeviceNode *devNode = NULL;
  49.     driverEntry = loader->GetDriverEntry(deviceInfo);
  50.     devNode = HdfDeviceNodeNewInstance();
  51.     devNode->deviceObject.property = HcsGetNodeByMatchAttr(HcsGetRootNode(), deviceInfo->deviceMatchAttr);
  52.     if (driverEntry->Bind(&devNode->deviceObject) != 0) { // 调用uart_sample.c中的Bind = HdfUartSampleBind函数
  53.         HDF_LOGE("bind driver failed");
  54.         HdfDeviceNodeFreeInstance(devNode);
  55.     }

  56. // 串口驱动源码主入口!!!
  57. $ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
  58. /* HdfDriverEntry definitions */
  59. struct HdfDriverEntry g_hdfUartSample = {
  60.     .moduleVersion = 1,
  61.     .moduleName = "UART_SAMPLE",
  62.                 // $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
  63.                 // 与描述设备节点信息的device5 :: deviceNode 中的 moduleName = "UART_SAMPLE"一致。
  64.     .Bind = HdfUartSampleBind,       // 驱动的绑定
  65.     .Init = HdfUartSampleInit,       // 驱动的初始化
  66.     .Release = HdfUartSampleRelease, // 驱动的释放
  67. };
  68. //
  69. // Initialize HdfDriverEntry
  70. HDF_INIT(g_hdfUartSample);  // .Init对应的函数可能是在这里面做了统一处理,
  71.                             // 这是一段带有特殊属性HDF_SECTION的代码段,
  72.                             // 编译器应该会将驱动操作函数放到特定的代码段,
  73.                             // 以便启动的时候依次初始化所有设备的驱动。
  74.     // Registers the driver with the HDF
  75.     // $ vi ~/harmony/sdk/drivers/hdf/frameworks/include/core/hdf_device_desc.h
  76.     #define HDF_INIT(module)  HDF_DRIVER_INIT(module)
  77.         // $ vi ~/harmony/sdk/drivers/hdf/lite/include/host/hdf_device_section.h
  78.         #define HDF_DRIVER_INIT(module) const size_t USED_ATTR module##HdfEntry HDF_SECTION = (size_t)(&(module))

  79. // 绑定UART驱动接口到HDF框架
  80. static int32_t HdfUartSampleBind(struct HdfDeviceObject *device)
  81.         UartHostCreate(device)

  82. // 初始化UART
  83. static int32_t HdfUartSampleInit(struct HdfDeviceObject *device)
  84.         host = UartHostFromDevice(device);
  85.         ret = SampleAttach(host, device); // 将UART驱动的配置和接口附加到HDF驱动框架
  86.         uartDevice = (struct UartDevice *)OsalMemCalloc(sizeof(struct UartDevice)); // 为串口设备创建新的资源空间
  87.         SampleDispatchConstruct(uartDevice);
  88.         // 从UART驱动的HCS中获取平台配置信息:串口控制器参数配置
  89.         ret = UartDeviceGetResource(uartDevice, device->property);
  90.             dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
  91.             dri->GetUint32(resourceNode, "num", &resource->num, 0)
  92.             dri->GetUint32(resourceNode, "base", &resource->base, 0)
  93.             dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0)
  94.             dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0)
  95.             dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0)
  96.             dri->GetUint32(resourceNode, "parity", &resource->parity, 0)
  97.             dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0)
  98.             dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0)
  99.         UartSampleAddDev(host);
  100.         UartDeviceInit(uartDevice);
  101.             struct UartResource *resource = &device->resource;
  102.             struct UartRegisterMap *regMap = (struct UartRegisterMap *)resource->physBase; // 获取物理寄存器地址,以便后续读写和设置
  103.             /* Updating the system clock */
  104.             device->uartClk = resource->uartClk;
  105.             /* clear and reset registers. */
  106.             UartPl011ResetRegisters(regMap); // 复位寄存器
  107.             /* set baud rate as device config */
  108.             err = UartPl011SetBaudrate(regMap, resource->uartClk, resource->baudrate); // 设置寄存器
  109.             /* set the data format as device config */
  110.             UartPl011SetDataFormat(regMap, resource->wlen, resource->parity, resource->stopBit);
  111.             /* Enabling the FIFOs */
  112.             BufferFifoInit(&device->rxFifo, g_fifoBuffer, UART_RX_FIFO_SIZE);
  113.             device->state = UART_DEVICE_INITIALIZED; // 设置初始化完成标志位
  114.     host->method = &g_uartSampleHostMethod; // 注册串口驱动接口,给用户层提供操作接口
  115.         .Init = SampleInit,
  116.         .Deinit = SampleDeinit,
  117.         .Read = NULL,
  118.         .Write = SampleWrite,
  119.             device = (struct UartDevice *)host->priv; // 通过私有数据获得设备接口,和linux很像
  120.             regMap = (struct UartRegisterMap *)device->resource.physBase; // 获取串口的物理寄存器基地址
  121.             UartPl011Write(regMap, data[idx]); // 操作串口的底层接口
  122.         .SetBaud = SampleSetBaud,
  123.             device = (struct UartDevice *)host->priv;
  124.             regMap = (struct UartRegisterMap *)device->resource.physBase;
  125.             err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate);
  126.             device->baudrate = baudRate;
  127.         .GetBaud = SampleGetBaud,
  128.             device = (struct UartDevice *)host->priv;
  129.             *baudRate = device->baudrate;
  130.         .SetAttribute = NULL,
  131.         .GetAttribute = NULL,
  132.         .SetTransMode = NULL,

  133. // 释放UART
  134. static void HdfUartSampleRelease(struct HdfDeviceObject *device)
  135.     host = UartHostFromDevice(device);
  136.     SampleDetach(host);
  137.         UartDeviceDeinit(uartDevice); // 解绑并释放UART驱动
  138.             while (UartPl011IsBusy(regMap));
  139.             UartPl011ResetRegisters(regMap);
  140.             uart_clk_cfg(0, false);
  141.             OsalIoUnmap((void *)device->resource.physBase);
  142.             device->state = UART_DEVICE_UNINITIALIZED; // 设置设备释放完成标志位
  143.         (void)OsalMemFree(uartDevice);
  144.     UartHostDestroy(host);
目前SDK代码已经和官方文档里的代码不太一样了,主要是函数名称变了,大部分底层接口的函数名没有变化。通过跟踪串口驱动源码,可以发现harmony系统的很多框架和方法(驱动和设备树匹配,数据的传递等)都是参考Linux来设计的,不过具体的细节是不一样的。
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/include/uart_pl011_sample.h
  1. // 核心的串口寄存器
  2. struct UartRegisterMap {
  3.     volatile uint32_t dr;            /* Offset: 0x000 TYPE: (RW) Data register */
  4.     union {
  5.         volatile uint32_t rsr;       /* Offset: 0x004 TYPE: (RO) Receive status register */
  6.         volatile uint32_t ecr;       /* Offset: 0x004 TYPE: (WO) Error clear register */
  7.     };
  8.     volatile uint32_t reserved0[4];  /* Offset: 0x008-0x014 Reserved */
  9.     volatile uint32_t fr;            /* Offset: 0x018 TYPE: (RO) Flag register */
  10.     volatile uint32_t reserved1;     /* Offset: 0x01C Reserved */
  11.     volatile uint32_t ilpr;          /* Offset: 0x020 TYPE: (RW) IrDA low-power counter register */
  12.     volatile uint32_t ibrd;          /* Offset: 0x024 TYPE: (RW) Integer baud rate register */
  13.     volatile uint32_t fbrd;          /* Offset: 0x028 TYPE: (RW) Fractional baud rate register */
  14.     volatile uint32_t lcr;           /* Offset: 0x02C TYPE: (RW) Line control register */
  15.     volatile uint32_t cr;            /* Offset: 0x030 TYPE: (RW) Control register */
  16.     volatile uint32_t ifls;          /* Offset: 0x034 TYPE: (RW) Interrupt FIFO level select register */
  17.     volatile uint32_t imsc;          /* Offset: 0x038 TYPE: (RW) Interrupt mask set/clear register */
  18.     volatile uint32_t ris;           /* Offset: 0x03C TYPE: (RO) Raw interrupt status register */
  19.     volatile uint32_t mis;           /* Offset: 0x040 TYPE: (RO) Masked interrupt status register */
  20.     volatile uint32_t icr;           /* Offset: 0x044 TYPE: (WO) Interrupt clear register */
  21.     volatile uint32_t dmacr;         /* Offset: 0x048 TYPE: (RW) DMA control register */
  22. };

  23. // 串口设置的一些基本参数
  24. struct UartResource {
  25.     uint32_t num;        /* UART port num */
  26.     uint32_t base;       /* UART PL011 base address */
  27.     uint32_t irqNum;     /* UART PL011 IRQ num */
  28.     uint32_t baudrate;   /* Default baudrate */
  29.     uint32_t wlen;       /* Default word length */
  30.     uint32_t parity;     /* Default parity */
  31.     uint32_t stopBit;    /* Default stop bits */
  32.     uint32_t uartClk;    /* UART clock */
  33.     unsigned long physBase;
  34. };

  35. // 串口的busy寄存器
  36. static inline bool UartPl011IsBusy(struct UartRegisterMap *regMap)
  37. {
  38.     return (bool)(regMap->fr & UART_PL011_FR_BUSY_MASK);
  39. }

  40. // 串口的写寄存器
  41. static inline void UartPl011Write(struct UartRegisterMap *regMap, uint8_t byte)
  42. {
  43.     while (UartPl011IsBusy(regMap));
  44.     regMap->dr = byte;
  45. }
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_pl011_sample.c
  1. // 通过操作寄存器设置波特率
  2. UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate)
  3. {
  4.     uint32_t value = SAMPLING_FACTOR * baudrate;
  5.     uint32_t divider = clk / value;
  6.     uint32_t remainder = clk % value;
  7.     uint32_t fraction;
  8.     value = (SAMPLING_FACTOR * remainder) / baudrate;
  9.     fraction = (value >> 1) + (value & 1);

  10.     regMap->ibrd = divider;
  11.     regMap->fbrd = fraction;
  12.     // to internally update the contents of UARTIBRD or UARTFBRD, a UARTLCR_H write must always be performed at the end.
  13.     UartPl011UpdateLcr(regMap);
  14.         bool uartEnabled = UartPl011IsEnabled(regMap);
  15.         UartPl011Disable(regMap);
  16.         regMap->lcr = regMap->lcr;
  17.         if (uartEnabled) {
  18.             UartPl011Enable(regMap);
  19.         }
  20. }

  21. // 复位寄存器
  22. void UartPl011ResetRegisters(struct UartRegisterMap *regMap)
  23. {
  24.     regMap->cr = UART_PL011_DEFAULT_CTRL_REG_VALUE;
  25.     regMap->dr = UART_PL011_DEFAULT_DATA_REG_VALUE;
  26.     /* Clear all the errors */
  27.     regMap->ecr = UART_PL011_DEFAULT_ECR_VALUE;
  28.     regMap->ilpr = UART_PL011_DEFAULT_ILPR_VALUE;
  29.     regMap->ibrd = UART_PL011_DEFAULT_IBRD_REG_VALUE;
  30.     regMap->fbrd = UART_PL011_DEFAULT_FBRD_REG_VALUE;
  31.     regMap->lcr = UART_PL011_DEFAULT_LCR_H_VALUE;
  32.     regMap->ifls = UART_PL011_DEFAULT_IFLS_REG_VALUE;
  33.     /* Clear all interrupt mask */
  34.     regMap->imsc = UART_PL011_DEFAULT_IMSC_REG_VALUE;
  35.     /* Clear all interrupts */
  36.     regMap->icr = UART_PL011_DEFAULT_ICR_VALUE;
  37.     regMap->dmacr = UART_PL011_DEFAULT_DMACR_VALUE;
  38. }
$ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/src/uart_core.c
  1. void UartHostDestroy(struct UartHost *host)
  2.     OsalMemFree(host);

  3. // 创建串口主机控制器驱动
  4. struct UartHost *UartHostCreate(struct HdfDeviceObject *device)
  5.     struct UartHost *host = NULL;
  6.     host = (struct UartHost *)OsalMemCalloc(sizeof(*host)); // 创建串口主机控制器新的资源空间
  7.     host->device = device; // 主机驱动和设备驱动关联在一起?
  8.     device->service = &(host->service); // 设备获取主机提供的服务接口?
  9.     host->priv = NULL;
  10.     host->method = NULL;
$ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/include/uart_core.h
  1. static inline struct UartHost *UartHostFromDevice(struct HdfDeviceObject *device)
  2.     return (device == NULL) ? NULL : (struct UartHost *)device->service;
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_dev_sample.c
  1. // 添加串口设备驱动
  2. void UartSampleAddDev(struct UartHost *host)
  3.     UartSampleAddRemoveDev(host, true); // (struct UartHost *host, bool add)
  4.         devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
  5.         ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num);
  6.         if (add) {
  7.             register_driver(devName, &g_uartSampleDevFops, HDF_UART_FS_MODE, host)
  8.         } else {
  9.             unregister_driver(devName)
  10.         }
  11.         OsalMemFree(devName);

  12. // 提供给用户空间的统一系统调用接口
  13. const struct file_operations_vfs g_uartSampleDevFops = {
  14.     .open   = UartSampleDevOpen,
  15.     .close  = UartSampleRelease,
  16.     .read   = UartSampleRead,
  17.     .write  = UartSampleWrite,
  18.     .ioctl  = UartSampleDevIoctl,
  19. };

  20. static int32_t UartSampleDevOpen(FAR struct file *filep)
  21.     inode = (struct inode *)filep->f_inode;
  22.     host = (struct UartHost *)inode->i_private;

  23. static int32_t UartSampleRelease(FAR struct file *filep)
  24.     inode = (struct inode *)filep->f_inode;
  25.     host = (struct UartHost *)inode->i_private;

  26. static ssize_t UartSampleRead(FAR struct file *filep, FAR char *buf, size_t count)
  27.     inode = (struct inode *)filep->f_inode;
  28.     host = (struct UartHost *)inode->i_private;
  29.     if (LOS_IsUserAddressRange((vaddr_t)buf, count)) {
  30.         tmpBuf = (uint8_t *)OsalMemCalloc(count);
  31.         ret = UartHostRead(host, tmpBuf, count);
  32.         ret = LOS_ArchCopyToUser(buf, tmpBuf, count);
  33.     } else {
  34.         return UartHostRead(host, (uint8_t *)buf, count);
  35.     }
  36. }

  37. static ssize_t UartSampleWrite(struct file *filep, const char *buf, size_t count)
  38.     inode = (struct inode *)filep->f_inode;
  39.     host = (struct UartHost *)inode->i_private;
  40.     if (LOS_IsUserAddressRange((vaddr_t)buf, count)) {
  41.         tmpBuf = (uint8_t *)OsalMemCalloc(count);
  42.         ret = LOS_ArchCopyFromUser(tmpBuf, buf, count);
  43.         ret = UartHostWrite(host, tmpBuf, count);
  44.     } else {
  45.         return UartHostWrite(host, (uint8_t *)buf, count);
  46.     }

  47. static int32_t UartSampleDevIoctl(FAR struct file *filep, int32_t cmd, unsigned long arg)
  48.     inode = (struct inode *)filep->f_inode;
  49.     host = (struct UartHost *)inode->i_private;
  50.     switch (cmd) {
  51.         case UART_CFG_BAUDRATE:
  52.             ret = UartHostSetBaud(host, arg);
  53.         default:
  54.             ret = HDF_ERR_NOT_SUPPORT;
  55.     }

  56. // 下面三个函数就是之前在uart_sample.c中注册的g_uartSampleHostMethod提供的具体的函数
  57. // $ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/include/uart_core.h
  58. static inline int32_t UartHostRead(struct UartHost *host, uint8_t *data, uint32_t size)
  59.     return host->method->Read(host, data, size);
  60. static inline int32_t UartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size)
  61.     return host->method->Write(host, data, size);
  62. static inline int32_t UartHostSetBaud(struct UartHost *host, uint32_t baudRate)
  63.     return host->method->SetBaud(host, baudRate);
$ vi ~/harmony/sdk/third_party/NuttX/fs/driver/fs_registerdriver.c
  1. // NuttX,参考了这个开源系统的源码?
  2. // 注册新设备
  3. int register_driver(FAR const char *path, FAR const struct file_operations_vfs *fops,
  4.                     mode_t mode, FAR void *priv)
  5. {
  6.     inode_semtake();
  7.     ret = inode_reserve(path, &node);
  8.     if (ret >= 0)
  9.     {
  10.         INODE_SET_DRIVER(node);
  11.         node->u.i_ops   = fops;
  12.         node->i_private = priv;
  13.         ret             = OK;
  14.     }
  15.     inode_semgive();
  16. }
$ vi ~/harmony/sdk/third_party/NuttX/fs/inode/fs_inode.c
  1. // NuttX,参考了这个开源系统的源码?
  2. // 信号量获取
  3. void inode_semtake(void)
  4. {
  5.     /* Do we already hold the semaphore? */
  6.     me = getpid();
  7.     if (me == g_inode_sem.holder)
  8.     {
  9.         /* Yes... just increment the count */
  10.         g_inode_sem.count++;
  11.         DEBUGASSERT(g_inode_sem.count > 0);
  12.     }
  13.     /* Take the semaphore (perhaps waiting) */
  14.     else
  15.     {
  16.         while (sem_wait(&g_inode_sem.sem) != 0)
  17.         {
  18.             /* The only case that an error should occur here is if the wait was awakened by a signal.*/
  19.             LOS_ASSERT(get_errno() == EINTR);
  20.         }
  21.         
  22.         /* No we hold the semaphore */
  23.         g_inode_sem.holder = me;
  24.         g_inode_sem.count  = 1;
  25.     }
  26. }
  27. // 信号量释放
  28. void inode_semgive(void)
  29. {
  30.     /* Is this our last count on the semaphore? */
  31.     if (g_inode_sem.count > 1)
  32.     {
  33.         /* No.. just decrement the count */
  34.         g_inode_sem.count--;
  35.     }
  36.     /* Yes.. then we can really release the semaphore */
  37.     else
  38.     {
  39.         g_inode_sem.holder = NO_HOLDER;
  40.         g_inode_sem.count  = 0;
  41.         (void)sem_post(&g_inode_sem.sem);
  42.     }
  43. }
$ vi ~/harmony/sdk/third_party/NuttX/fs/inode/fs_inodereserve.c
  1. // 插入新的设备节点
  2. static void inode_insert(FAR struct inode *node,
  3.                          FAR struct inode *peer,
  4.                          FAR struct inode *parent)
  5. {
  6.     /* If peer is non-null, then new node simply goes to the right
  7.     * of that peer node.
  8.     */
  9.     if (peer)
  10.     {
  11.         node->i_peer = peer->i_peer;
  12.         peer->i_peer = node;
  13.     }
  14.     /* If parent is non-null, then it must go at the head of its
  15.     * list of children.
  16.     */
  17.     else if (parent)
  18.     {
  19.         node->i_peer    = parent->i_child;
  20.         parent->i_child = node;
  21.     }
  22.     /* Otherwise, this must be the new root_inode */
  23.     else
  24.     {
  25.         node->i_peer = g_root_inode;
  26.         g_root_inode = node;
  27.     }
  28. }

  29. // 注册设备时添加设备节点
  30. int inode_reserve(FAR const char *path, FAR struct inode **inode_ptr)
  31. {
  32.     /* Find the location to insert the new subtree */
  33.     pathnode = inode_search(&name, &left, &parent, &relpath);
  34.     /* Now we now where to insert the subtree */
  35.     for (; ; ) {
  36.         /* Create a new node -- we need to know if this is the
  37.         * the leaf node or some intermediary.  We can find this
  38.         * by looking at the next name.
  39.         */
  40.         FAR const char *next_name = inode_nextname(name);
  41.         if (*next_name) {
  42.             /* Insert an operationless node */
  43.             node = inode_alloc(name);
  44.             if (node) {
  45.                 inode_insert(node, left, parent);
  46.                 /* Set up for the next time through the loop */
  47.                 name   = next_name;
  48.                 left   = NULL;
  49.                 parent = node;
  50.                 continue;
  51.             }
  52.         } else {
  53.             node = inode_alloc(name);
  54.             if (node) {
  55.                 inode_insert(node, left, parent);
  56.                 *inode_ptr = node;
  57.                 return OK;
  58.             }
  59.         }
  60.     }
  61. }
在编译脚本中增加示例UART驱动模块
$ vi ~/harmony/sdk/vendor/huawei/hdf/hdf_vendor.mk
  1. # lib path
  2. LITEOS_LD_PATH += -L$(VENDOR_HDF_DRIVERS_PLATFORM_ROOT)/libs/$(LITEOS_PLATFORM)
  3. LITEOS_LD_PATH += -L$(VENDOR_HDF_DRIVERS_ROOT)/libs/$(LITEOS_PLATFORM)

  4. +LITEOS_BASELIB += -lhdf_uart_sample
  5. +LIB_SUBDIRS    += $(VENDOR_HDF_DRIVERS_ROOT)/sample/platform/uart
  6. // 匹配~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c

四、用户程序和驱动交互代码
UART驱动成功初始化后,会创建/dev/uartdev-5设备节点,通过设备节点与UART驱动交互的代码如下:
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/dev/hello_uart_dev.c
  1. #include
  2. #include
  3. #include
  4. #include "hdf_log.h"

  5. #define HDF_LOG_TAG "hello_uart"
  6. #define INFO_SIZE 16

  7. int main(void)
  8. {
  9.     int ret;
  10.     int fd;
  11.     const char info[INFO_SIZE] = {" HELLO UART! "};

  12.     fd = open("/dev/uartdev-5", O_RDWR);
  13.     if (fd < 0) {
  14.         HDF_LOGE("hello_uart uartdev-5 open failed %d", fd);
  15.         return -1;
  16.     }
  17.     ret = write(fd, info, INFO_SIZE);
  18.     if (ret != 0) {
  19.         HDF_LOGE("hello_uart write uartdev-5 ret is %d", ret);
  20.     }
  21.     ret = close(fd);
  22.     if (ret != 0) {
  23.         HDF_LOGE("hello_uart uartdev-5 close failed %d", fd);
  24.         return -1;
  25.     }
  26.     return ret;
  27. }
用户空间的应用开发和Linux基本一样。
在产品配置的hdf子系统下增加hello_uart_sample组件:
$ vi ~/harmony/sdk/build/lite/product/ipcamera_hi3516dv300.json
  1. {
  2.   "subsystem": [
  3.     {
  4.       "name": "hdf",
  5.       "component": [
  6.         { "name": "posix", "dir": "//drivers/hdf/lite/posix:hdf_posix", "features":[] },
  7.         { "name": "manager", "dir": "//drivers/hdf/lite/manager:hdf_manager", "features":[] },
  8.         { "name": "wifi", "dir": "//vendor/huawei/hdf/wifi:wifi_firmware", "features":[] },
  9.         { "name": "display", "dir": "//vendor/huawei/hdf/display/hdi:hdi_display", "features":[] },
  10.         { "name": "input", "dir": "//vendor/huawei/hdf/input/hdi:hdi_input", "features":[] },
  11. +        { "name": "hdf_sample", "dir": "//vendor/huawei/hdf/sample/platform/uart:hello_uart_sample", "features":[] }
  12.       ]
  13.     },
  14.   ]
  15. }
如上代码均为示例代码,完整代码可以在vendor/huawei/hdf/sample查看。示例代码默认不参与编译,需要手动添加到编译脚本中。

五、小结
总共修改六个部分代码(驱动和应用示例由官方写好了,主要添加四项配置):
驱动源码:~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
HDF框架驱动配置:~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
HDF框架设备配置:~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
驱动模块编译配置:~/harmony/sdk/vendor/huawei/hdf/hdf_vendor.mk
应用源码:~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/dev/hello_uart_dev.c
应用配置:~/harmony/sdk/build/lite/product/ipcamera_hi3516dv300.json

六 、编译
$ ./build.sh
拷贝到Windows共享目录中:
$ rm /mnt/hgfs/proj-harmony/images/out/ -rf
$ cp -rf out/ /mnt/hgfs/proj-harmony/images/

七 、烧录
下面烧写新增了uart5驱动和串口测试应用的系统:
烧录.png
hisilicon # setenv bootcmd "mmc read 0x0 0x80000000 0x800 0x3000; go 0x80000000";
hisilicon # setenv bootargs "console=ttyAMA0,115200n8 root=emmc fstype=vfat rootaddr=7M rootsize=15M rw";
hisilicon # saveenv
hisilicon # reset
重启后进入系统。

八、测试
在根目录下,在命令行输入指令“./bin/hello_uart”执行写入的demo程序,显示成功结果如下所示:
  1. OHOS # ./bin/hello_uart
  2. OHOS #  HELLO UART!

本文结束,感谢您的阅读!



更多回帖

×
发帖