Driver Messaging Mechanism

When to Use

The HDF messaging mechanism implements the interaction between the user-mode applications and kernel-mode drivers.

Available APIs

The messaging mechanism allows:

  1. A user-mode application to send a message to a driver.

  2. A user-mode application to receive events reported by a driver.

Table 1 APIs for the driver messaging mechanism

API Description
struct HdfIoService *HdfIoServiceBind(const char *serviceName); Obtains a driver service. After obtaining the driver service, the user-mode application uses Dispatch() in the driver service obtained to send messages to the driver.
void HdfIoServiceRecycle(struct HdfIoService *service); Releases a driver service.
int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); Registers the method for receiving events reported by the driver.
int HdfDeviceSendEvent(struct HdfDeviceObject *deviceObject, uint32_t id, struct HdfSBuf *data); Sends events.

How to Develop

  1. In the driver configuration file, set policy to 2. For more details, see Driver Service Management.

    device_sample :: Device {
        policy = 2;
        ...
    }
    
  2. Set permissions for the device node of the driver. By default, the permission field is set to 0666. You can set it based on service requirements.

  3. Implement the Dispatch() method of IDeviceIoService.

    // Dispatch() is used to process messages sent from the user-mode application.
    int32_t SampleDriverDispatch(struct HdfDeviceIoClient *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
    {
        HDF_LOGI("sample driver lite A dispatch");
        return HDF_SUCCESS;
    }
    int32_t SampleDriverBind(struct HdfDeviceObject *device)
    {
        HDF_LOGI("test for lite os sample driver A Open!");
        if (device == NULL) {
            HDF_LOGE("test for lite os sample driver A Open failed!");
            return HDF_FAILURE;
        }
        static struct ISampleDriverService sampleDriverA = {
            .ioService.Dispatch = SampleDriverDispatch,
            .ServiceA = SampleDriverServiceA,
            .ServiceB = SampleDriverServiceB,
        };
        device->service = (struct IDeviceIoService *)(&sampleDriverA);
        return HDF_SUCCESS;
    }
    
  4. Define the cmd type in the message processing function.

    #define SAMPLE_WRITE_READ 1 // Read and write operation 1
    
  5. Enable the user-mode application to obtain a service and send a message to the driver.

    int SendMsg(const char *testMsg)
    {
        if (testMsg == NULL) {
            HDF_LOGE("test msg is null");
            return HDF_FAILURE;
        }
        struct HdfIoService *serv = HdfIoServiceBind("sample_driver");
        if (serv == NULL) {
            HDF_LOGE("fail to get service");
            return HDF_FAILURE;
        }
        struct HdfSBuf *data = HdfSbufObtainDefaultSize();
        if (data == NULL) {
            HDF_LOGE("fail to obtain sbuf data");
            return HDF_FAILURE;
        }
        struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
        if (reply == NULL) {
            HDF_LOGE("fail to obtain sbuf reply");
            ret = HDF_DEV_ERR_NO_MEMORY;
            goto out;
        }
        if (!HdfSbufWriteString(data, testMsg)) {
            HDF_LOGE("fail to write sbuf");
            ret = HDF_FAILURE;
            goto out;
        }
        int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
        if (ret != HDF_SUCCESS) {
            HDF_LOGE("fail to send service call");
            goto out;
        }
    out:
        HdfSbufRecycle(data);
        HdfSbbufRecycle(reply);
        HdfIoServiceRecycle(serv);
        return ret;
    }
    
  6. Enable the user-mode application to receive messages from the driver.

    1. Implement the method for the user-mode application to process the events reported by the driver.

      static int OnDevEventReceived(void *priv,  uint32_t id, struct HdfSBuf *data)
      {
          OsalTimespec time;
          OsalGetTime(&time);
          HDF_LOGI("%{public}s received event at %{public}llu.%{public}llu", (char *)priv, time.sec, time.usec);
      
          const char *string = HdfSbufReadString(data);
          if (string == NULL) {
              HDF_LOGE("fail to read string in event data");
              return HDF_FAILURE;
          }
          HDF_LOGI("%{public}s: dev event received: %{public}d %{public}s",  (char *)priv, id, string);
          return HDF_SUCCESS;
      }
      
    2. Register the method for the user-mode application to receive messages from the driver.

      int RegisterListen()
      {
          struct HdfIoService *serv = HdfIoServiceBind("sample_driver");
          if (serv == NULL) {
              HDF_LOGE("fail to get service");
              return HDF_FAILURE;
          }
          static struct HdfDevEventlistener listener = {
              .callBack = OnDevEventReceived,
              .priv ="Service0"
          };
          if (HdfDeviceRegisterEventListener(serv, &listener) != 0) {
              HDF_LOGE("fail to register event listener");
              return HDF_FAILURE;
          }
          ......
          HdfDeviceUnregisterEventListener(serv, &listener);
          HdfIoServiceRecycle(serv);
          return HDF_SUCCESS;
      }
      
    3. Enable the driver to report events.

      int32_t SampleDriverDispatch(HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
      {
          // Process the API call.
          return HdfDeviceSendEvent(client->device, cmdCode, data);
      }