/Documentation/driver-api/mei/mei-client-bus.rst
ReStructuredText | 168 lines | 117 code | 51 blank | 0 comment | 0 complexity | 66197b8cc30923fe07ee6efa7d9290c7 MD5 | raw file
- .. SPDX-License-Identifier: GPL-2.0
- ==============================================
- Intel(R) Management Engine (ME) Client bus API
- ==============================================
- Rationale
- =========
- The MEI character device is useful for dedicated applications to send and receive
- data to the many FW appliance found in Intel's ME from the user space.
- However, for some of the ME functionalities it makes sense to leverage existing software
- stack and expose them through existing kernel subsystems.
- In order to plug seamlessly into the kernel device driver model we add kernel virtual
- bus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers
- for the various MEI features as a stand alone entities found in their respective subsystem.
- Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
- the existing code.
- MEI CL bus API
- ==============
- A driver implementation for an MEI Client is very similar to any other existing bus
- based device drivers. The driver registers itself as an MEI CL bus driver through
- the ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c`
- .. code-block:: C
- struct mei_cl_driver {
- struct device_driver driver;
- const char *name;
- const struct mei_cl_device_id *id_table;
- int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
- int (*remove)(struct mei_cl_device *dev);
- };
- The mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a
- driver to bind itself against a device name.
- .. code-block:: C
- struct mei_cl_device_id {
- char name[MEI_CL_NAME_SIZE];
- uuid_le uuid;
- __u8 version;
- kernel_ulong_t driver_info;
- };
- To actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver`
- API. This is typically called at module initialization time.
- Once the driver is registered and bound to the device, a driver will typically
- try to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send`
- and :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section.
- In order for a driver to be notified about pending traffic or event, the driver
- should register a callback via :c:func:`mei_cl_devev_register_rx_cb` and
- :c:func:`mei_cldev_register_notify_cb` function respectively.
- .. _api:
- API:
- ----
- .. kernel-doc:: drivers/misc/mei/bus.c
- :export: drivers/misc/mei/bus.c
- Example
- =======
- As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
- The driver init and exit routines for this device would look like:
- .. code-block:: C
- #define CONTACT_DRIVER_NAME "contact"
- static struct mei_cl_device_id contact_mei_cl_tbl[] = {
- { CONTACT_DRIVER_NAME, },
- /* required last entry */
- { }
- };
- MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
- static struct mei_cl_driver contact_driver = {
- .id_table = contact_mei_tbl,
- .name = CONTACT_DRIVER_NAME,
- .probe = contact_probe,
- .remove = contact_remove,
- };
- static int contact_init(void)
- {
- int r;
- r = mei_cl_driver_register(&contact_driver);
- if (r) {
- pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
- return r;
- }
- return 0;
- }
- static void __exit contact_exit(void)
- {
- mei_cl_driver_unregister(&contact_driver);
- }
- module_init(contact_init);
- module_exit(contact_exit);
- And the driver's simplified probe routine would look like that:
- .. code-block:: C
- int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
- {
- [...]
- mei_cldev_enable(dev);
- mei_cldev_register_rx_cb(dev, contact_rx_cb);
- return 0;
- }
- In the probe routine the driver first enable the MEI device and then registers
- an rx handler which is as close as it can get to registering a threaded IRQ handler.
- The handler implementation will typically call :c:func:`mei_cldev_recv` and then
- process received data.
- .. code-block:: C
- #define MAX_PAYLOAD 128
- #define HDR_SIZE 4
- static void conntact_rx_cb(struct mei_cl_device *cldev)
- {
- struct contact *c = mei_cldev_get_drvdata(cldev);
- unsigned char payload[MAX_PAYLOAD];
- ssize_t payload_sz;
- payload_sz = mei_cldev_recv(cldev, payload, MAX_PAYLOAD)
- if (reply_size < HDR_SIZE) {
- return;
- }
- c->process_rx(payload);
- }
- MEI Client Bus Drivers
- ======================
- .. toctree::
- :maxdepth: 2
- hdcp
- nfc