2013-03-27 15:31:10

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 00/11 V5] Add Client MEI bus and NFC device

This is take 5 on the MEI bus + NFC device patches

This patch set adds implementation of MEI CLIENT BUS abstraction
over MEI device, this allows standard Linux device drivers
to access functionality exposed by MEI device clients that was previously
available only to the user space through /dev/mei

The first exercises is to export the NFC radio

More information can be found under

Documentation/misc-devices/mei/mei-client-bus.txt

v4 -> v5:
* Sanitize mei_cl_bus.h by removing the licensing terms.
* Removed uuid field from the device_id structure as it's redundant.
* Added the device_id structure to mod_devicetable.h and modified file2alias.c accordingly.
* Added a modalias sysfs attribute and a uevent routine, allowing for module autoloading on the MEI bus.
* Added a Documentation/ABI/testing/sysfs-bus-mei entry for documenting the modalias sysfs attribute.

v3 -> v4:
* The bus is named mei client bus
- Renames:
* mei_bus_driver to mei_cl_driver
* mei_bus_device to mei_cl_device
v2 -> v3:
- Renames:
* mei_device to mei_host. The mei_host pointers are still called *dev
as I didn't want the first patch to get too fat.
* mei_bus_driver to mei_driver
* mei_bus_client to mei_device

- mei_driver structure changes:
* name pointer addition
* MEI id table
* probe routine now takes the probed MEI id as an argument

- mei-bus.txt update according to the mei_driver changes and the structure
renaming.
- All exported symbols converted to EXPORT_SYMBOL_GPL.
- to_mei_* macros moved to bus.c
- drivers/misc/mei/bus.h deleted, all API definitions moved to mei_dev.h
- mei_device structure clenup: mei_host, mei_driver, and name fields removed.
- Fixed driver owner: mei_driver_register() is now a macro over
__mei_driver_register, using THIS_MODULE as the default owner.


Samuel Ortiz (11):
mei: bus: Initial MEI Client bus type implementation
mei: bus: Implement driver registration
mei: bus: Initial implementation for I/O routines
mei: bus: Add bus related structures to mei_cl
mei: bus: Call bus routines from the core code
mei: bus: Synchronous API for the data transmission
mei: bus: Implement bus driver data setter/getter
mei: nfc: Initial nfc implementation
mei: nfc: Connect also the regular ME client
mei: nfc: Add NFC device to the MEI bus
mei: nfc: Implement MEI bus IO ops

Documentation/ABI/testing/sysfs-bus-mei | 7 +
Documentation/misc-devices/mei/mei-client-bus.txt | 135 ++++++
drivers/misc/mei/Kconfig | 8 +
drivers/misc/mei/Makefile | 3 +
drivers/misc/mei/bus.c | 496 ++++++++++++++++++++++
drivers/misc/mei/client.c | 4 +
drivers/misc/mei/init.c | 3 +
drivers/misc/mei/interrupt.c | 2 +
drivers/misc/mei/main.c | 13 +
drivers/misc/mei/mei_dev.h | 99 ++++-
drivers/misc/mei/nfc.c | 458 ++++++++++++++++++++
drivers/misc/mei/nfc.h | 141 ++++++
drivers/misc/mei/pci-me.c | 1 -
include/linux/mei_cl_bus.h | 41 ++
include/linux/mod_devicetable.h | 9 +
scripts/mod/devicetable-offsets.c | 3 +
scripts/mod/file2alias.c | 12 +
17 files changed, 1433 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-mei
create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
create mode 100644 drivers/misc/mei/bus.c
create mode 100644 drivers/misc/mei/nfc.c
create mode 100644 drivers/misc/mei/nfc.h
create mode 100644 include/linux/mei_cl_bus.h

--
1.7.11.7


2013-03-27 15:31:13

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 02/11 V5] mei: bus: Implement driver registration

From: Samuel Ortiz <[email protected]>

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 26 ++++++++++++++++++++++++++
include/linux/mei_cl_bus.h | 7 +++++++
2 files changed, 33 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 78c876a..d16b3c3 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -170,3 +170,29 @@ void mei_cl_remove_device(struct mei_cl_device *device)
device_unregister(&device->dev);
}
EXPORT_SYMBOL_GPL(mei_cl_remove_device);
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
+{
+ int err;
+
+ driver->driver.name = driver->name;
+ driver->driver.owner = owner;
+ driver->driver.bus = &mei_cl_bus_type;
+
+ err = driver_register(&driver->driver);
+ if (err)
+ return err;
+
+ pr_debug("mei: driver [%s] registered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver)
+{
+ driver_unregister(&driver->driver);
+
+ pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 4e7351d..ba2aa3b 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -17,4 +17,11 @@ struct mei_cl_driver {
int (*remove)(struct mei_cl_device *dev);
};

+int __mei_cl_driver_register(struct mei_cl_driver *driver,
+ struct module *owner);
+#define mei_cl_driver_register(driver) \
+ __mei_cl_driver_register(driver, THIS_MODULE)
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver);
+
#endif /* _LINUX_MEI_CL_BUS_H */
--
1.7.11.7

2013-03-27 15:31:20

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 09/11 V5] mei: nfc: Connect also the regular ME client

From: Samuel Ortiz <[email protected]>

After receiving the NFC interface version, IVN and radio type,
we can connect to the the actual nfc ME client and send the
initialization (nfc connect) message.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/nfc.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 867cbe7..b903d82 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -28,6 +28,7 @@

/** mei_nfc_dev - NFC mei device
*
+ * @cl: NFC host client
* @cl_info: NFC info host client
* @init_work: perform connection to the info client
* @fw_ivn: NFC Intervace Version Number
@@ -35,6 +36,7 @@
* @radio_type: NFC radio type
*/
struct mei_nfc_dev {
+ struct mei_cl *cl;
struct mei_cl *cl_info;
struct work_struct init_work;
u8 fw_ivn;
@@ -55,6 +57,12 @@ static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,

static void mei_nfc_free(struct mei_nfc_dev *ndev)
{
+ if (ndev->cl) {
+ list_del(&ndev->cl->device_link);
+ mei_cl_unlink(ndev->cl);
+ kfree(ndev->cl);
+ }
+
if (ndev->cl_info) {
list_del(&ndev->cl_info->device_link);
mei_cl_unlink(ndev->cl_info);
@@ -62,6 +70,73 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
}
}

+static int mei_nfc_connect(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+ struct mei_cl *cl;
+ struct mei_nfc_cmd *cmd, *reply;
+ struct mei_nfc_connect *connect;
+ struct mei_nfc_connect_resp *connect_resp;
+ size_t connect_length, connect_resp_length;
+ int bytes_recv, ret;
+
+ cl = ndev->cl;
+ dev = cl->dev;
+
+ connect_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect);
+
+ connect_resp_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect_resp);
+
+ cmd = kzalloc(connect_length, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+ connect = (struct mei_nfc_connect *)cmd->data;
+
+ reply = kzalloc(connect_resp_length, GFP_KERNEL);
+ if (!reply) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ connect_resp = (struct mei_nfc_connect_resp *)reply->data;
+
+ cmd->command = MEI_NFC_CMD_MAINTENANCE;
+ cmd->data_size = 3;
+ cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
+ connect->fw_ivn = ndev->fw_ivn;
+ connect->vendor_id = ndev->vendor_id;
+
+ ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
+ goto err;
+ }
+
+ bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
+ if (bytes_recv < 0) {
+ dev_err(&dev->pdev->dev, "Could not read connect response\n");
+ ret = bytes_recv;
+ goto err;
+ }
+
+ dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
+ connect_resp->fw_ivn, connect_resp->vendor_id);
+
+ dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
+ connect_resp->me_major, connect_resp->me_minor,
+ connect_resp->me_hotfix, connect_resp->me_build);
+
+ ret = 0;
+
+err:
+ kfree(reply);
+ kfree(cmd);
+
+ return ret;
+}
+
static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
{
struct mei_device *dev;
@@ -117,12 +192,13 @@ static void mei_nfc_init(struct work_struct *work)
{
struct mei_device *dev;
struct mei_nfc_dev *ndev;
- struct mei_cl *cl_info;
+ struct mei_cl *cl_info, *cl;
int ret;

ndev = container_of(work, struct mei_nfc_dev, init_work);

cl_info = ndev->cl_info;
+ cl = ndev->cl;
dev = cl_info->dev;

mutex_lock(&dev->device_lock);
@@ -148,6 +224,24 @@ static void mei_nfc_init(struct work_struct *work)
"NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);

+ mutex_lock(&dev->device_lock);
+
+ if (mei_cl_connect(cl, NULL) < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not connect to the NFC ME client");
+
+ goto err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ ret = mei_nfc_connect(ndev);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not connect to NFC");
+ return;
+ }
+
return;

err:
@@ -160,7 +254,7 @@ err:
int mei_nfc_host_init(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
- struct mei_cl *cl_info;
+ struct mei_cl *cl_info, *cl = NULL;
int i, ret;

/* already initialzed */
@@ -168,14 +262,19 @@ int mei_nfc_host_init(struct mei_device *dev)
return 0;

cl_info = mei_cl_allocate(dev);
- if (!cl_info)
- return -ENOMEM;
+ cl = mei_cl_allocate(dev);
+
+ if (!cl || !cl_info) {
+ ret = -ENOMEM;
+ goto err;
+ }

/* check for valid client id */
i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto err;
}

cl_info->me_client_id = dev->me_clients[i].client_id;
@@ -188,7 +287,26 @@ int mei_nfc_host_init(struct mei_device *dev)

list_add_tail(&cl_info->device_link, &dev->device_list);

+ /* check for valid client id */
+ i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
+ if (i < 0) {
+ dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ cl->me_client_id = dev->me_clients[i].client_id;
+
+ ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
+ if (ret)
+ goto err;
+
+ cl->device_uuid = mei_nfc_guid;
+
+ list_add_tail(&cl->device_link, &dev->device_list);
+
ndev->cl_info = cl_info;
+ ndev->cl = cl;

INIT_WORK(&ndev->init_work, mei_nfc_init);
schedule_work(&ndev->init_work);
--
1.7.11.7

2013-03-27 15:31:23

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 11/11 V5] mei: nfc: Implement MEI bus IO ops

From: Samuel Ortiz <[email protected]>

The send ops for NFC builds the command header, updates the request id
and then waits for an ACK.
The recv ops check if it receives data or an ACK and in the latter case
wakes the send ops up.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/nfc.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/mei/nfc.h | 13 +++++++++
2 files changed, 89 insertions(+)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 372d336..14d6076 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -15,6 +15,7 @@
*/

#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -39,11 +40,15 @@ struct mei_nfc_dev {
struct mei_cl *cl;
struct mei_cl *cl_info;
struct work_struct init_work;
+ wait_queue_head_t send_wq;
u8 fw_ivn;
u8 vendor_id;
u8 radio_type;

char *bus_name;
+
+ u16 req_id;
+ u16 recv_req_id;
};

static struct mei_nfc_dev nfc_dev;
@@ -223,6 +228,74 @@ err:
return ret;
}

+static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+ struct mei_device *dev;
+ struct mei_nfc_dev *ndev;
+ struct mei_nfc_hci_hdr *hdr;
+ u8 *mei_buf;
+ int err;
+
+ ndev = (struct mei_nfc_dev *) cldev->priv_data;
+ dev = ndev->cl->dev;
+
+ mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
+ if (!mei_buf)
+ return -ENOMEM;
+
+ hdr = (struct mei_nfc_hci_hdr *) mei_buf;
+ hdr->cmd = MEI_NFC_CMD_HCI_SEND;
+ hdr->status = 0;
+ hdr->req_id = ndev->req_id;
+ hdr->reserved = 0;
+ hdr->data_size = length;
+
+ memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
+
+ err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
+
+ kfree(mei_buf);
+
+ if (!wait_event_interruptible_timeout(ndev->send_wq,
+ ndev->recv_req_id == ndev->req_id, HZ)) {
+ dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
+ err = -ETIMEDOUT;
+ } else {
+ ndev->req_id++;
+ }
+
+ return err;
+}
+
+static int mei_nfc_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+ struct mei_nfc_dev *ndev;
+ struct mei_nfc_hci_hdr *hci_hdr;
+ int received_length;
+
+ ndev = (struct mei_nfc_dev *)cldev->priv_data;
+
+ received_length = __mei_cl_recv(ndev->cl, buf, length);
+ if (received_length < 0)
+ return received_length;
+
+ hci_hdr = (struct mei_nfc_hci_hdr *) buf;
+
+ if (hci_hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
+ ndev->recv_req_id = hci_hdr->req_id;
+ wake_up(&ndev->send_wq);
+
+ return 0;
+ }
+
+ return received_length;
+}
+
+static struct mei_cl_transport_ops nfc_ops = {
+ .send = mei_nfc_send,
+ .recv = mei_nfc_recv,
+};
+
static void mei_nfc_init(struct work_struct *work)
{
struct mei_device *dev;
@@ -293,6 +366,7 @@ static void mei_nfc_init(struct work_struct *work)
}

cldev->priv_data = ndev;
+ cldev->ops = &nfc_ops;

return;

@@ -359,8 +433,10 @@ int mei_nfc_host_init(struct mei_device *dev)

ndev->cl_info = cl_info;
ndev->cl = cl;
+ ndev->req_id = 1;

INIT_WORK(&ndev->init_work, mei_nfc_init);
+ init_waitqueue_head(&ndev->send_wq);
schedule_work(&ndev->init_work);

return 0;
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
index 4440436..12e48d3 100644
--- a/drivers/misc/mei/nfc.h
+++ b/drivers/misc/mei/nfc.h
@@ -114,11 +114,24 @@ struct mei_nfc_connect_resp {
uint16_t me_build;
} __packed;

+struct mei_nfc_hci_hdr {
+ u8 cmd;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+} __packed;
+
#define MEI_NFC_CMD_MAINTENANCE 0x00
+#define MEI_NFC_CMD_HCI_SEND 0x01
+#define MEI_NFC_CMD_HCI_RECV 0x02

#define MEI_NFC_SUBCMD_CONNECT 0x00
#define MEI_NFC_SUBCMD_IF_VERSION 0x01

+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+
/* Vendors */
#define MEI_NFC_VENDOR_INSIDE 0x00

--
1.7.11.7

2013-03-27 15:31:19

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 06/11 V5] mei: bus: Synchronous API for the data transmission

From: Samuel Ortiz <[email protected]>

Define a truly synchronous API for the bus Tx path by putting all pending
request to the write list and wait for the interrupt tx handler to wake
us up.
The ___mei_cl_send() out path is also slightly reworked to make it look more
like main.c:mei_write().

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 39 +++++++++++++++++++++++++++++----------
drivers/misc/mei/mei_dev.h | 1 +
2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index c626dc9..2b4b5b3 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -222,7 +222,8 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
}
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);

-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+ bool blocking)
{
struct mei_device *dev;
struct mei_msg_hdr mei_hdr;
@@ -273,11 +274,8 @@ int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
cb->buf_idx = 0;
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;
- list_add_tail(&cb->list, &dev->write_list.list);
-
- mutex_unlock(&dev->device_lock);

- return length;
+ goto out;
}

dev->hbuf_is_ready = false;
@@ -303,19 +301,30 @@ int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;

- if (!mei_hdr.msg_complete) {
- list_add_tail(&cb->list, &dev->write_list.list);
- } else {
+out:
+ if (mei_hdr.msg_complete) {
if (mei_cl_flow_ctrl_reduce(cl)) {
- err = -EIO;
+ err = -ENODEV;
goto out_err;
}
-
list_add_tail(&cb->list, &dev->write_waiting_list.list);
+ } else {
+ list_add_tail(&cb->list, &dev->write_list.list);
}

mutex_unlock(&dev->device_lock);

+ if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
+ if (wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE)) {
+ if (signal_pending(current))
+ err = -EINTR;
+ err = -ERESTARTSYS;
+ mutex_lock(&dev->device_lock);
+ goto out_err;
+ }
+ }
+
return mei_hdr.length;

out_err:
@@ -382,6 +391,16 @@ out:
return r_length;
}

+inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ return ___mei_cl_send(cl, buf, length, 0);
+}
+
+inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ return ___mei_cl_send(cl, buf, length, 1);
+}
+
int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
{
struct mei_cl *cl = device->cl;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7d594be..325f71a 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -273,6 +273,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
uuid_le uuid, char *name);
void mei_cl_remove_device(struct mei_cl_device *device);

+int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);

--
1.7.11.7

2013-03-27 15:31:56

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 08/11 V5] mei: nfc: Initial nfc implementation

From: Samuel Ortiz <[email protected]>

NFC ME device is exported through the MEI bus to be consumed by the
NFC subsystem.

NFC is represented by two mei clients: An info one and the actual
NFC one. In order to properly build the ME id we first need to retrieve
the firmware information from the info client.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/Kconfig | 8 ++
drivers/misc/mei/Makefile | 2 +
drivers/misc/mei/client.c | 3 +
drivers/misc/mei/init.c | 2 +
drivers/misc/mei/mei_dev.h | 28 ++++++
drivers/misc/mei/nfc.c | 209 +++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/mei/nfc.h | 122 ++++++++++++++++++++++++++
7 files changed, 374 insertions(+)
create mode 100644 drivers/misc/mei/nfc.c
create mode 100644 drivers/misc/mei/nfc.h

diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index c76fa31..58e6ea4 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -9,6 +9,14 @@ config INTEL_MEI
For more information see
<http://software.intel.com/en-us/manageability/>

+config INTEL_MEI_BUS_NFC
+ bool "MEI bus NFC support"
+ depends on INTEL_MEI
+ help
+ When selecting this option the ME NFC device will be added to the
+ MEI bus. This is needed by the NFC kernel subsystem for sending and
+ receiving HCI frames to and from the NFC device.
+
config INTEL_MEI_ME
tristate "ME Enabled Intel Chipsets"
select INTEL_MEI
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 1b29f7c..20007a1 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -12,6 +12,8 @@ mei-objs += amthif.o
mei-objs += wd.o
mei-objs += bus.o

+mei-$(CONFIG_INTEL_MEI_BUS_NFC) += nfc.o
+
obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
mei-me-objs := pci-me.o
mei-me-objs += hw-me.o
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e14397b..eb27bf6 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -358,6 +358,9 @@ void mei_host_client_init(struct work_struct *work)
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
+ else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+ mei_nfc_host_init(dev);
+
}

dev->dev_state = MEI_DEV_ENABLED;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 54b51c0..4e102ad 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -219,6 +219,8 @@ void mei_stop(struct mei_device *dev)

mei_wd_stop(dev);

+ mei_nfc_host_exit();
+
dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev, 0);

diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 325f71a..89b23bd 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -498,6 +498,34 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,

void mei_amthif_run_next_cmd(struct mei_device *dev);

+#ifdef CONFIG_INTEL_MEI_BUS_NFC
+/*
+ * NFC functions
+ */
+int mei_nfc_host_init(struct mei_device *dev);
+void mei_nfc_host_exit(void);
+
+/*
+ * NFC Client UUID
+ */
+extern const uuid_le mei_nfc_guid;
+
+#else /* CONFIG_INTEL_MEI_BUS_NFC */
+
+static inline int mei_nfc_host_init(struct mei_device *dev)
+{
+ return 0;
+}
+
+static inline void mei_nfc_host_exit(void)
+{
+ return;
+}
+
+static const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+ 0x94, 0xd4, 0x50, 0x26,
+ 0x67, 0x23, 0x77, 0x5c);
+#endif /* CONFIG_INTEL_MEI_BUS_NFC */

int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
new file mode 100644
index 0000000..867cbe7
--- /dev/null
+++ b/drivers/misc/mei/nfc.c
@@ -0,0 +1,209 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/mei.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "client.h"
+#include "nfc.h"
+
+/** mei_nfc_dev - NFC mei device
+ *
+ * @cl_info: NFC info host client
+ * @init_work: perform connection to the info client
+ * @fw_ivn: NFC Intervace Version Number
+ * @vendor_id: NFC manufacturer ID
+ * @radio_type: NFC radio type
+ */
+struct mei_nfc_dev {
+ struct mei_cl *cl_info;
+ struct work_struct init_work;
+ u8 fw_ivn;
+ u8 vendor_id;
+ u8 radio_type;
+};
+
+static struct mei_nfc_dev nfc_dev;
+
+/* UUIDs for NFC F/W clients */
+const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+ 0x94, 0xd4, 0x50, 0x26,
+ 0x67, 0x23, 0x77, 0x5c);
+
+static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
+ 0x48, 0xa4, 0xef, 0xab,
+ 0xba, 0x8a, 0x12, 0x06);
+
+static void mei_nfc_free(struct mei_nfc_dev *ndev)
+{
+ if (ndev->cl_info) {
+ list_del(&ndev->cl_info->device_link);
+ mei_cl_unlink(ndev->cl_info);
+ kfree(ndev->cl_info);
+ }
+}
+
+static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+ struct mei_cl *cl;
+
+ struct mei_nfc_cmd cmd;
+ struct mei_nfc_reply *reply = NULL;
+ struct mei_nfc_if_version *version;
+ size_t if_version_length;
+ int bytes_recv, ret;
+
+ cl = ndev->cl_info;
+ dev = cl->dev;
+
+ memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
+ cmd.command = MEI_NFC_CMD_MAINTENANCE;
+ cmd.data_size = 1;
+ cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
+
+ ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
+ return ret;
+ }
+
+ /* to be sure on the stack we alloc memory */
+ if_version_length = sizeof(struct mei_nfc_reply) +
+ sizeof(struct mei_nfc_if_version);
+
+ reply = kzalloc(if_version_length, GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+
+ bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
+ if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+ dev_err(&dev->pdev->dev, "Could not read IF version\n");
+ ret = -EIO;
+ goto err;
+ }
+
+ version = (struct mei_nfc_if_version *)reply->data;
+
+ ndev->fw_ivn = version->fw_ivn;
+ ndev->vendor_id = version->vendor_id;
+ ndev->radio_type = version->radio_type;
+
+err:
+ kfree(reply);
+ return ret;
+}
+
+static void mei_nfc_init(struct work_struct *work)
+{
+ struct mei_device *dev;
+ struct mei_nfc_dev *ndev;
+ struct mei_cl *cl_info;
+ int ret;
+
+ ndev = container_of(work, struct mei_nfc_dev, init_work);
+
+ cl_info = ndev->cl_info;
+ dev = cl_info->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (mei_cl_connect(cl_info, NULL) < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not connect to the NFC INFO ME client");
+
+ goto err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ ret = mei_nfc_if_version(ndev);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not get the NFC interfave version");
+
+ goto err;
+ }
+
+ dev_info(&dev->pdev->dev,
+ "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
+ ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
+
+ return;
+
+err:
+ mei_nfc_free(ndev);
+
+ return;
+}
+
+
+int mei_nfc_host_init(struct mei_device *dev)
+{
+ struct mei_nfc_dev *ndev = &nfc_dev;
+ struct mei_cl *cl_info;
+ int i, ret;
+
+ /* already initialzed */
+ if (ndev->cl_info)
+ return 0;
+
+ cl_info = mei_cl_allocate(dev);
+ if (!cl_info)
+ return -ENOMEM;
+
+ /* check for valid client id */
+ i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
+ if (i < 0) {
+ dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+ return -ENOENT;
+ }
+
+ cl_info->me_client_id = dev->me_clients[i].client_id;
+
+ ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
+ if (ret)
+ goto err;
+
+ cl_info->device_uuid = mei_nfc_info_guid;
+
+ list_add_tail(&cl_info->device_link, &dev->device_list);
+
+ ndev->cl_info = cl_info;
+
+ INIT_WORK(&ndev->init_work, mei_nfc_init);
+ schedule_work(&ndev->init_work);
+
+ return 0;
+
+err:
+ mei_nfc_free(ndev);
+
+ return ret;
+}
+
+void mei_nfc_host_exit(void)
+{
+ struct mei_nfc_dev *ndev = &nfc_dev;
+
+ mei_nfc_free(ndev);
+}
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
new file mode 100644
index 0000000..59e6703
--- /dev/null
+++ b/drivers/misc/mei/nfc.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation.
+ * [email protected]
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef _MEI_NFC_H
+#define _MEI_NFC_H
+
+#include <linux/types.h>
+
+struct mei_nfc_cmd {
+ uint8_t command;
+ uint8_t status;
+ uint16_t req_id;
+ uint32_t reserved;
+ uint16_t data_size;
+ uint8_t sub_command;
+ uint8_t data[];
+} __packed;
+
+struct mei_nfc_reply {
+ uint8_t command;
+ uint8_t status;
+ uint16_t req_id;
+ uint32_t reserved;
+ uint16_t data_size;
+ uint8_t sub_command;
+ uint8_t reply_status;
+ uint8_t data[];
+} __packed;
+
+struct mei_nfc_if_version {
+ uint8_t radio_version_sw[3];
+ uint8_t reserved[3];
+ uint8_t radio_version_hw[3];
+ uint8_t i2c_addr;
+ uint8_t fw_ivn;
+ uint8_t vendor_id;
+ uint8_t radio_type;
+} __packed;
+
+struct mei_nfc_connect {
+ uint8_t fw_ivn;
+ uint8_t vendor_id;
+} __packed;
+
+struct mei_nfc_connect_resp {
+ uint8_t fw_ivn;
+ uint8_t vendor_id;
+ uint16_t me_major;
+ uint16_t me_minor;
+ uint16_t me_hotfix;
+ uint16_t me_build;
+} __packed;
+
+#define MEI_NFC_CMD_MAINTENANCE 0x00
+
+#define MEI_NFC_SUBCMD_CONNECT 0x00
+#define MEI_NFC_SUBCMD_IF_VERSION 0x01
+
+#endif /* _MEI_NFC_H */
--
1.7.11.7

2013-03-27 15:31:16

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 04/11 V5] mei: bus: Add bus related structures to mei_cl

From: Samuel Ortiz <[email protected]>

We keep track of all MEI devices on the bus through a specific linked list.
We also have a mei_device instance in the mei_cl structure.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 49 ++++++++++++++++++++++++++++++++--------------
drivers/misc/mei/client.c | 1 +
drivers/misc/mei/init.c | 1 +
drivers/misc/mei/mei_dev.h | 8 ++++++++
4 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 16c7fff..162cd54 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -140,36 +140,53 @@ static struct device_type mei_cl_device_type = {
.release = mei_cl_dev_release,
};

-struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
+static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
+ uuid_le uuid)
+{
+ struct mei_cl *cl, *next;
+
+ list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ if (!uuid_le_cmp(uuid, cl->device_uuid))
+ return cl;
+ }
+
+ return NULL;
+}
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
uuid_le uuid, char *name)
{
struct mei_cl_device *device;
+ struct mei_cl *cl;
int status;

+ cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
+ if (cl == NULL)
+ return NULL;
+
device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
if (!device)
return NULL;

- device->dev.parent = &mei_device->pdev->dev;
+ device->cl = cl;
+
+ device->dev.parent = &dev->pdev->dev;
device->dev.bus = &mei_cl_bus_type;
device->dev.type = &mei_cl_device_type;

dev_set_name(&device->dev, "%s", name);

status = device_register(&device->dev);
- if (status)
- goto out_err;
+ if (status) {
+ dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
+ kfree(device);
+ return NULL;
+ }
+
+ cl->device = device;

dev_dbg(&device->dev, "client %s registered\n", name);

return device;
-
-out_err:
- dev_err(device->dev.parent, "Failed to register MEI client\n");
-
- kfree(device);
-
- return NULL;
}
EXPORT_SYMBOL_GPL(mei_cl_add_device);

@@ -367,9 +384,10 @@ out:

int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
{
- struct mei_cl *cl = NULL;
+ struct mei_cl *cl = device->cl;

- /* TODO: hook between mei_bus_client and mei_cl */
+ if (cl == NULL)
+ return -ENODEV;

if (device->ops && device->ops->send)
return device->ops->send(device, buf, length);
@@ -380,9 +398,10 @@ EXPORT_SYMBOL_GPL(mei_cl_send);

int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
{
- struct mei_cl *cl = NULL;
+ struct mei_cl *cl = device->cl;

- /* TODO: hook between mei_bus_client and mei_cl */
+ if (cl == NULL)
+ return -ENODEV;

if (device->ops && device->ops->recv)
return device->ops->recv(device, buf, length);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1569afe..e14397b 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -216,6 +216,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->rx_wait);
init_waitqueue_head(&cl->tx_wait);
INIT_LIST_HEAD(&cl->link);
+ INIT_LIST_HEAD(&cl->device_link);
cl->reading_state = MEI_IDLE;
cl->writing_state = MEI_IDLE;
cl->dev = dev;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index c1c8d76..54b51c0 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -47,6 +47,7 @@ void mei_device_init(struct mei_device *dev)
{
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
+ INIT_LIST_HEAD(&dev->device_list);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_recvd_msg);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index cde5687..0313c24 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -209,6 +209,11 @@ struct mei_cl {
enum mei_file_transaction_states writing_state;
int sm_state;
struct mei_cl_cb *read_cb;
+
+ /* MEI CL bus data */
+ struct mei_cl_device *device;
+ struct list_head device_link;
+ uuid_le device_uuid;
};

/** struct mei_hw_ops
@@ -423,6 +428,9 @@ struct mei_device {

struct work_struct init_work;

+ /* List of bus devices */
+ struct list_head device_list;
+
const struct mei_hw_ops *ops;
char hw[0] __aligned(sizeof(void *));
};
--
1.7.11.7

2013-03-27 15:32:16

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 10/11 V5] mei: nfc: Add NFC device to the MEI bus

From: Samuel Ortiz <[email protected]>

After building its bus name as a string based on its vendor id and radio
type, we can add it to the bus.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/nfc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/mei/nfc.h | 6 ++++++
2 files changed, 61 insertions(+)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index b903d82..372d336 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -42,6 +42,8 @@ struct mei_nfc_dev {
u8 fw_ivn;
u8 vendor_id;
u8 radio_type;
+
+ char *bus_name;
};

static struct mei_nfc_dev nfc_dev;
@@ -70,6 +72,39 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
}
}

+static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+
+ if (!ndev->cl)
+ return -ENODEV;
+
+ dev = ndev->cl->dev;
+
+ switch (ndev->vendor_id) {
+ case MEI_NFC_VENDOR_INSIDE:
+ switch (ndev->radio_type) {
+ case MEI_NFC_VENDOR_INSIDE_UREAD:
+ ndev->bus_name = "microread";
+ return 0;
+
+ default:
+ dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+ ndev->radio_type);
+
+ return -EINVAL;
+ }
+
+ default:
+ dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n",
+ ndev->vendor_id);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mei_nfc_connect(struct mei_nfc_dev *ndev)
{
struct mei_device *dev;
@@ -191,6 +226,7 @@ err:
static void mei_nfc_init(struct work_struct *work)
{
struct mei_device *dev;
+ struct mei_cl_device *cldev;
struct mei_nfc_dev *ndev;
struct mei_cl *cl_info, *cl;
int ret;
@@ -242,6 +278,22 @@ static void mei_nfc_init(struct work_struct *work)
return;
}

+ if (mei_nfc_build_bus_name(ndev) < 0) {
+ dev_err(&dev->pdev->dev,
+ "Could not build the bus ID name\n");
+ return;
+ }
+
+ cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name);
+ if (!cldev) {
+ dev_err(&dev->pdev->dev,
+ "Could not add the NFC device to the MEI bus\n");
+
+ goto err;
+ }
+
+ cldev->priv_data = ndev;
+
return;

err:
@@ -323,5 +375,8 @@ void mei_nfc_host_exit(void)
{
struct mei_nfc_dev *ndev = &nfc_dev;

+ if (ndev->cl && ndev->cl->device)
+ mei_cl_remove_device(ndev->cl->device);
+
mei_nfc_free(ndev);
}
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
index 59e6703..4440436 100644
--- a/drivers/misc/mei/nfc.h
+++ b/drivers/misc/mei/nfc.h
@@ -119,4 +119,10 @@ struct mei_nfc_connect_resp {
#define MEI_NFC_SUBCMD_CONNECT 0x00
#define MEI_NFC_SUBCMD_IF_VERSION 0x01

+/* Vendors */
+#define MEI_NFC_VENDOR_INSIDE 0x00
+
+/* Radio types */
+#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
+
#endif /* _MEI_NFC_H */
--
1.7.11.7

2013-03-27 15:35:37

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 07/11 V5] mei: bus: Implement bus driver data setter/getter

From: Samuel Ortiz <[email protected]>

MEI drivers should be able to carry their private data around.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 12 ++++++++++++
include/linux/mei_cl_bus.h | 3 +++
2 files changed, 15 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 2b4b5b3..8dbcb15 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -461,6 +461,18 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);

+void *mei_cl_get_drvdata(const struct mei_cl_device *device)
+{
+ return dev_get_drvdata(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
+
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
+{
+ dev_set_drvdata(&device->dev, data);
+}
+EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
+
void mei_cl_bus_rx_event(struct mei_cl *cl)
{
struct mei_cl_device *device = cl->device;
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index d9958c3..1bece18 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -35,4 +35,7 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
#define MEI_CL_EVENT_RX 0
#define MEI_CL_EVENT_TX 1

+void *mei_cl_get_drvdata(const struct mei_cl_device *device);
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
+
#endif /* _LINUX_MEI_CL_BUS_H */
--
1.7.11.7

2013-03-27 15:35:57

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 05/11 V5] mei: bus: Call bus routines from the core code

From: Samuel Ortiz <[email protected]>

Register the MEI bus type against the kernel core bus APIs and
call the bus Rx handler from interrupt.c

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 22 ++++++++++++++++++++++
drivers/misc/mei/interrupt.c | 2 ++
drivers/misc/mei/main.c | 13 +++++++++++++
drivers/misc/mei/mei_dev.h | 6 +++++-
drivers/misc/mei/pci-me.c | 1 -
5 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 162cd54..c626dc9 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -441,3 +441,25 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
return 0;
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
+
+void mei_cl_bus_rx_event(struct mei_cl *cl)
+{
+ struct mei_cl_device *device = cl->device;
+
+ if (!device || !device->event_cb)
+ return;
+
+ set_bit(MEI_CL_EVENT_RX, &device->events);
+
+ schedule_work(&device->event_work);
+}
+
+int __init mei_cl_bus_init(void)
+{
+ return bus_register(&mei_cl_bus_type);
+}
+
+void __exit mei_cl_bus_exit(void)
+{
+ bus_unregister(&mei_cl_bus_type);
+}
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 6ce45ef..255e085 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -50,6 +50,8 @@ static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb)
cl->reading_state = MEI_READ_COMPLETE;
if (waitqueue_active(&cl->rx_wait))
wake_up_interruptible(&cl->rx_wait);
+ else
+ mei_cl_bus_rx_event(cl);

}
}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 27b3df2..872de9d 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -767,6 +767,19 @@ void mei_deregister(void)
}
EXPORT_SYMBOL_GPL(mei_deregister);

+static int __init mei_init(void)
+{
+ return mei_cl_bus_init();
+}
+
+static void __exit mei_exit(void)
+{
+ mei_cl_bus_exit();
+}
+
+module_init(mei_init);
+module_exit(mei_exit);
+
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 0313c24..7d594be 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -292,6 +292,11 @@ struct mei_cl_transport_ops {
int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
};

+void mei_cl_bus_rx_event(struct mei_cl *cl);
+int mei_cl_bus_init(void);
+void mei_cl_bus_exit(void);
+
+
/**
* struct mei_cl_device - MEI device handle
* An mei_cl_device pointer is returned from mei_add_device()
@@ -451,7 +456,6 @@ static inline u32 mei_data2slots(size_t length)
return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
}

-
/*
* mei init function prototypes
*/
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 178928e..a1a582b 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -197,7 +197,6 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mei_pdev = pdev;
pci_set_drvdata(pdev, dev);

-
schedule_delayed_work(&dev->timer_work, HZ);

mutex_unlock(&mei_mutex);
--
1.7.11.7

2013-03-27 15:36:29

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 01/11 V5] mei: bus: Initial MEI Client bus type implementation

From: Samuel Ortiz <[email protected]>

mei client bus will present some of the mei clients
as devices for other standard subsystems

Implement the probe, remove, match, device addtion routines, along with
the sysfs and uevent ones. mei_cl_device_id is also added to
mod_devicetable.h
A mei-cleint-bus.txt document describing the rationale and the API usage
is also added while ABI/testing/sysfs-bus-mei describeis the modalias ABI.

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
Documentation/ABI/testing/sysfs-bus-mei | 7 +
Documentation/misc-devices/mei/mei-client-bus.txt | 135 +++++++++++++++++
drivers/misc/mei/Makefile | 1 +
drivers/misc/mei/bus.c | 172 ++++++++++++++++++++++
drivers/misc/mei/mei_dev.h | 26 ++++
include/linux/mei_cl_bus.h | 20 +++
include/linux/mod_devicetable.h | 9 ++
scripts/mod/devicetable-offsets.c | 3 +
scripts/mod/file2alias.c | 12 ++
9 files changed, 385 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-mei
create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
create mode 100644 drivers/misc/mei/bus.c
create mode 100644 include/linux/mei_cl_bus.h

diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei
new file mode 100644
index 0000000..2066f0b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-mei
@@ -0,0 +1,7 @@
+What: /sys/bus/mei/devices/.../modalias
+Date: March 2013
+KernelVersion: 3.10
+Contact: Samuel Ortiz <[email protected]>
+ [email protected]
+Description: Stores the same MODALIAS value emitted by uevent
+ Format: mei:<mei device name>
diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
new file mode 100644
index 0000000..9dc5ebf
--- /dev/null
+++ b/Documentation/misc-devices/mei/mei-client-bus.txt
@@ -0,0 +1,135 @@
+Intel(R) Management Engine (ME) Client bus API
+===============================================
+
+
+Rationale
+=========
+MEI misc 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 make 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 existing bus
+based device drivers. The driver registers itself as an MEI CL bus driver through
+the mei_cl_driver structure:
+
+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);
+};
+
+struct mei_cl_id {
+ char name[MEI_NAME_SIZE];
+ kernel_ulong_t driver_info;
+};
+
+The mei_cl_id structure allows the driver to bind itself against a device name.
+
+To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
+API. This is typically called at module init time.
+
+Once registered on the ME Client bus, a driver will typically try to do some I/O on
+this bus and this should be done through the mei_cl_send() and mei_cl_recv()
+routines. The latter is synchronous (blocks and sleeps until data shows up).
+In order for drivers to be notified of pending events waiting for them (e.g.
+an Rx event) they can register an event handler through the
+mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
+will trigger an event handler call and the driver implementation is supposed
+to call mei_recv() from the event handler in order to fetch the pending
+received buffers.
+
+
+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:
+
+#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:
+
+int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
+{
+ struct contact_driver *contact;
+
+ [...]
+ mei_cl_register_event_cb(dev, contact_event_cb, contact);
+
+ return 0;
+ }
+
+In the probe routine the driver basically registers an ME bus event handler
+which is as close as it can get to registering a threaded IRQ handler.
+The handler implementation will typically call some I/O routine depending on
+the pending events:
+
+#define MAX_NFC_PAYLOAD 128
+
+static void contact_event_cb(struct mei_cl_device *dev, u32 events,
+ void *context)
+{
+ struct contact_driver *contact = context;
+
+ if (events & BIT(MEI_EVENT_RX)) {
+ u8 payload[MAX_NFC_PAYLOAD];
+ int payload_size;
+
+ payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
+ if (payload_size <= 0)
+ return;
+
+ /* Hook to the NFC subsystem */
+ nfc_hci_recv_frame(contact->hdev, payload, payload_size);
+ }
+}
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 2c336d0..1b29f7c 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -10,6 +10,7 @@ mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
+mei-objs += bus.o

obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
mei-me-objs := pci-me.o
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
new file mode 100644
index 0000000..78c876a
--- /dev/null
+++ b/drivers/misc/mei/bus.c
@@ -0,0 +1,172 @@
+/*
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+
+#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
+#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
+
+static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver = to_mei_cl_driver(drv);
+ const struct mei_cl_device_id *id;
+
+ if (!device)
+ return 0;
+
+ if (!driver || !driver->id_table)
+ return 0;
+
+ id = driver->id_table;
+
+ while (id->name[0]) {
+ if (!strcmp(dev_name(dev), id->name))
+ return 1;
+
+ id++;
+ }
+
+ return 0;
+}
+
+static int mei_cl_device_probe(struct device *dev)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver;
+ struct mei_cl_device_id id;
+
+ if (!device)
+ return 0;
+
+ driver = to_mei_cl_driver(dev->driver);
+ if (!driver || !driver->probe)
+ return -ENODEV;
+
+ dev_dbg(dev, "Device probe\n");
+
+ strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+
+ return driver->probe(device, &id);
+}
+
+static int mei_cl_device_remove(struct device *dev)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver;
+
+ if (!device || !dev->driver)
+ return 0;
+
+ driver = to_mei_cl_driver(dev->driver);
+ if (!driver->remove) {
+ dev->driver = NULL;
+
+ return 0;
+ }
+
+ return driver->remove(device);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute mei_cl_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct bus_type mei_cl_bus_type = {
+ .name = "mei",
+ .dev_attrs = mei_cl_dev_attrs,
+ .match = mei_cl_device_match,
+ .probe = mei_cl_device_probe,
+ .remove = mei_cl_device_remove,
+ .uevent = mei_cl_uevent,
+};
+
+static void mei_cl_dev_release(struct device *dev)
+{
+ kfree(to_mei_cl_device(dev));
+}
+
+static struct device_type mei_cl_device_type = {
+ .release = mei_cl_dev_release,
+};
+
+struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
+ uuid_le uuid, char *name)
+{
+ struct mei_cl_device *device;
+ int status;
+
+ device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
+ if (!device)
+ return NULL;
+
+ device->dev.parent = &mei_device->pdev->dev;
+ device->dev.bus = &mei_cl_bus_type;
+ device->dev.type = &mei_cl_device_type;
+
+ dev_set_name(&device->dev, "%s", name);
+
+ status = device_register(&device->dev);
+ if (status)
+ goto out_err;
+
+ dev_dbg(&device->dev, "client %s registered\n", name);
+
+ return device;
+
+out_err:
+ dev_err(device->dev.parent, "Failed to register MEI client\n");
+
+ kfree(device);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(mei_cl_add_device);
+
+void mei_cl_remove_device(struct mei_cl_device *device)
+{
+ device_unregister(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_remove_device);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index b5d6607..7abb705d 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -21,6 +21,7 @@
#include <linux/watchdog.h>
#include <linux/poll.h>
#include <linux/mei.h>
+#include <linux/mei_cl_bus.h>

#include "hw.h"
#include "hw-me-regs.h"
@@ -262,6 +263,31 @@ struct mei_hw_ops {
unsigned char *buf, unsigned long len);
};

+/* MEI bus API*/
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+ uuid_le uuid, char *name);
+void mei_cl_remove_device(struct mei_cl_device *device);
+
+/**
+ * struct mei_cl_device - MEI device handle
+ * An mei_cl_device pointer is returned from mei_add_device()
+ * and links MEI bus clients to their actual ME host client pointer.
+ * Drivers for MEI devices will get an mei_cl_device pointer
+ * when being probed and shall use it for doing ME bus I/O.
+ *
+ * @dev: linux driver model device pointer
+ * @uuid: me client uuid
+ * @cl: mei client
+ * @priv_data: client private data
+ */
+struct mei_cl_device {
+ struct device dev;
+
+ struct mei_cl *cl;
+
+ void *priv_data;
+};
+
/**
* struct mei_device - MEI private device struct

diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
new file mode 100644
index 0000000..4e7351d
--- /dev/null
+++ b/include/linux/mei_cl_bus.h
@@ -0,0 +1,20 @@
+#ifndef _LINUX_MEI_CL_BUS_H
+#define _LINUX_MEI_CL_BUS_H
+
+#include <linux/device.h>
+#include <linux/uuid.h>
+
+struct mei_cl_device;
+
+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_device_id *id);
+ int (*remove)(struct mei_cl_device *dev);
+};
+
+#endif /* _LINUX_MEI_CL_BUS_H */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 779cf7c..b508016 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -9,6 +9,7 @@

#ifdef __KERNEL__
#include <linux/types.h>
+#include <linux/uuid.h>
typedef unsigned long kernel_ulong_t;
#endif

@@ -568,4 +569,12 @@ struct ipack_device_id {
__u32 device; /* Device ID or IPACK_ANY_ID */
};

+#define MEI_CL_MODULE_PREFIX "mei:"
+#define MEI_CL_NAME_SIZE 32
+
+struct mei_cl_device_id {
+ char name[MEI_CL_NAME_SIZE];
+ kernel_ulong_t driver_info;
+};
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index b45260b..e66d4d2 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -174,5 +174,8 @@ int main(void)
DEVID_FIELD(x86_cpu_id, model);
DEVID_FIELD(x86_cpu_id, vendor);

+ DEVID(mei_cl_device_id);
+ DEVID_FIELD(mei_cl_device_id, name);
+
return 0;
}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 771ac17..45f9a33 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1133,6 +1133,18 @@ static int do_x86cpu_entry(const char *filename, void *symval,
}
ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry);

+/* Looks like: mei:S */
+static int do_mei_entry(const char *filename, void *symval,
+ char *alias)
+{
+ DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
+
+ sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name);
+
+ return 1;
+}
+ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry);
+
/* Does namelen bytes of name exactly match the symbol? */
static bool sym_is(const char *name, unsigned namelen, const char *symbol)
{
--
1.7.11.7

2013-03-27 15:36:27

by Tomas Winkler

[permalink] [raw]
Subject: [char-misc-next 03/11 V5] mei: bus: Initial implementation for I/O routines

From: Samuel Ortiz <[email protected]>

Signed-off-by: Samuel Ortiz <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/misc/mei/bus.c | 226 +++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/mei/mei_dev.h | 30 ++++++
include/linux/mei_cl_bus.h | 11 +++
3 files changed, 267 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index d16b3c3..16c7fff 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -25,6 +26,8 @@
#include <linux/mei_cl_bus.h>

#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"

#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
@@ -81,6 +84,11 @@ static int mei_cl_device_remove(struct device *dev)
if (!device || !dev->driver)
return 0;

+ if (device->event_cb) {
+ device->event_cb = NULL;
+ cancel_work_sync(&device->event_work);
+ }
+
driver = to_mei_cl_driver(dev->driver);
if (!driver->remove) {
dev->driver = NULL;
@@ -196,3 +204,221 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
}
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
+
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ struct mei_device *dev;
+ struct mei_msg_hdr mei_hdr;
+ struct mei_cl_cb *cb;
+ int me_cl_id, err;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ if (cl->state != MEI_FILE_CONNECTED)
+ return -ENODEV;
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+
+ err = mei_io_cb_alloc_req_buf(cb, length);
+ if (err < 0) {
+ mei_io_cb_free(cb);
+ return err;
+ }
+
+ memcpy(cb->request_buffer.data, buf, length);
+ cb->fop_type = MEI_FOP_WRITE;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ /* Check if we have an ME client device */
+ me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (me_cl_id == dev->me_clients_num) {
+ err = -ENODEV;
+ goto out_err;
+ }
+
+ if (length > dev->me_clients[me_cl_id].props.max_msg_length) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ err = mei_cl_flow_ctrl_creds(cl);
+ if (err < 0)
+ goto out_err;
+
+ /* Host buffer is not ready, we queue the request */
+ if (err == 0 || !dev->hbuf_is_ready) {
+ cb->buf_idx = 0;
+ mei_hdr.msg_complete = 0;
+ cl->writing_state = MEI_WRITING;
+ list_add_tail(&cb->list, &dev->write_list.list);
+
+ mutex_unlock(&dev->device_lock);
+
+ return length;
+ }
+
+ dev->hbuf_is_ready = false;
+
+ /* Check for a maximum length */
+ if (length > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
+ mei_hdr.msg_complete = 0;
+ } else {
+ mei_hdr.length = length;
+ mei_hdr.msg_complete = 1;
+ }
+
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
+
+ if (mei_write_message(dev, &mei_hdr, buf)) {
+ err = -EIO;
+ goto out_err;
+ }
+
+ cl->writing_state = MEI_WRITING;
+ cb->buf_idx = mei_hdr.length;
+
+ if (!mei_hdr.msg_complete) {
+ list_add_tail(&cb->list, &dev->write_list.list);
+ } else {
+ if (mei_cl_flow_ctrl_reduce(cl)) {
+ err = -EIO;
+ goto out_err;
+ }
+
+ list_add_tail(&cb->list, &dev->write_waiting_list.list);
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ return mei_hdr.length;
+
+out_err:
+ mutex_unlock(&dev->device_lock);
+ mei_io_cb_free(cb);
+
+ return err;
+}
+
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ size_t r_length;
+ int err;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (!cl->read_cb) {
+ err = mei_cl_read_start(cl);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ return err;
+ }
+ }
+
+ if (cl->reading_state != MEI_READ_COMPLETE &&
+ !waitqueue_active(&cl->rx_wait)) {
+ mutex_unlock(&dev->device_lock);
+
+ if (wait_event_interruptible(cl->rx_wait,
+ (MEI_READ_COMPLETE == cl->reading_state))) {
+ if (signal_pending(current))
+ return -EINTR;
+ return -ERESTARTSYS;
+ }
+
+ mutex_lock(&dev->device_lock);
+ }
+
+ cb = cl->read_cb;
+
+ if (cl->reading_state != MEI_READ_COMPLETE) {
+ r_length = 0;
+ goto out;
+ }
+
+ r_length = min_t(size_t, length, cb->buf_idx);
+
+ memcpy(buf, cb->response_buffer.data, r_length);
+
+ mei_io_cb_free(cb);
+ cl->reading_state = MEI_IDLE;
+ cl->read_cb = NULL;
+
+out:
+ mutex_unlock(&dev->device_lock);
+
+ return r_length;
+}
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+ struct mei_cl *cl = NULL;
+
+ /* TODO: hook between mei_bus_client and mei_cl */
+
+ if (device->ops && device->ops->send)
+ return device->ops->send(device, buf, length);
+
+ return __mei_cl_send(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_send);
+
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+ struct mei_cl *cl = NULL;
+
+ /* TODO: hook between mei_bus_client and mei_cl */
+
+ if (device->ops && device->ops->recv)
+ return device->ops->recv(device, buf, length);
+
+ return __mei_cl_recv(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_recv);
+
+static void mei_bus_event_work(struct work_struct *work)
+{
+ struct mei_cl_device *device;
+
+ device = container_of(work, struct mei_cl_device, event_work);
+
+ if (device->event_cb)
+ device->event_cb(device, device->events, device->event_context);
+
+ device->events = 0;
+
+ /* Prepare for the next read */
+ mei_cl_read_start(device->cl);
+}
+
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+ mei_cl_event_cb_t event_cb, void *context)
+{
+ if (device->event_cb)
+ return -EALREADY;
+
+ device->events = 0;
+ device->event_cb = event_cb;
+ device->event_context = context;
+ INIT_WORK(&device->event_work, mei_bus_event_work);
+
+ mei_cl_read_start(device->cl);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7abb705d..cde5687 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -268,6 +268,25 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
uuid_le uuid, char *name);
void mei_cl_remove_device(struct mei_cl_device *device);

+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+
+/**
+ * struct mei_cl_transport_ops - MEI CL device transport ops
+ * This structure allows ME host clients to implement technology
+ * specific transport layers.
+ *
+ * @send: Tx hook for the device. This allows ME host clients to trap
+ * the device driver buffers before actually physically
+ * pushing it to the ME.
+ * @recv: Rx hook for the device. This allows ME host clients to trap the
+ * ME buffers before forwarding them to the device driver.
+ */
+struct mei_cl_transport_ops {
+ int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
+ int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
+};
+
/**
* struct mei_cl_device - MEI device handle
* An mei_cl_device pointer is returned from mei_add_device()
@@ -278,6 +297,10 @@ void mei_cl_remove_device(struct mei_cl_device *device);
* @dev: linux driver model device pointer
* @uuid: me client uuid
* @cl: mei client
+ * @ops: ME transport ops
+ * @event_cb: Drivers register this callback to get asynchronous ME
+ * events (e.g. Rx buffer pending) notifications.
+ * @events: Events bitmask sent to the driver.
* @priv_data: client private data
*/
struct mei_cl_device {
@@ -285,6 +308,13 @@ struct mei_cl_device {

struct mei_cl *cl;

+ const struct mei_cl_transport_ops *ops;
+
+ struct work_struct event_work;
+ mei_cl_event_cb_t event_cb;
+ void *event_context;
+ unsigned long events;
+
void *priv_data;
};

diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index ba2aa3b..d9958c3 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -24,4 +24,15 @@ int __mei_cl_driver_register(struct mei_cl_driver *driver,

void mei_cl_driver_unregister(struct mei_cl_driver *driver);

+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+
+typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
+ u32 events, void *context);
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+ mei_cl_event_cb_t read_cb, void *context);
+
+#define MEI_CL_EVENT_RX 0
+#define MEI_CL_EVENT_TX 1
+
#endif /* _LINUX_MEI_CL_BUS_H */
--
1.7.11.7

2013-03-29 15:48:27

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [char-misc-next 08/11 V5] mei: nfc: Initial nfc implementation

On Wed, Mar 27, 2013 at 05:30:00PM +0200, Tomas Winkler wrote:
> From: Samuel Ortiz <[email protected]>
>
> NFC ME device is exported through the MEI bus to be consumed by the
> NFC subsystem.
>
> NFC is represented by two mei clients: An info one and the actual
> NFC one. In order to properly build the ME id we first need to retrieve
> the firmware information from the info client.
>
> Signed-off-by: Samuel Ortiz <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> ---
> drivers/misc/mei/Kconfig | 8 ++
> drivers/misc/mei/Makefile | 2 +
> drivers/misc/mei/client.c | 3 +
> drivers/misc/mei/init.c | 2 +
> drivers/misc/mei/mei_dev.h | 28 ++++++
> drivers/misc/mei/nfc.c | 209 +++++++++++++++++++++++++++++++++++++++++++++
> drivers/misc/mei/nfc.h | 122 ++++++++++++++++++++++++++

Why do you need a nfc.h at all?


> --- /dev/null
> +++ b/drivers/misc/mei/nfc.c
> @@ -0,0 +1,209 @@
> +/*
> + *
> + * Intel Management Engine Interface (Intel MEI) Linux driver
> + * Copyright (c) 2003-2012, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + */

<snip>

> --- /dev/null
> +++ b/drivers/misc/mei/nfc.h
> @@ -0,0 +1,122 @@
> +/******************************************************************************
> + * Intel Management Engine Interface (Intel MEI) Linux driver
> + * Intel MEI Interface Header
> + *
> + * This file is provided under a dual BSD/GPLv2 license. When using or
> + * redistributing this file, you may do so under either license.
> + *
> + * GPL LICENSE SUMMARY
> + *
> + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
> + * USA
> + *
> + * The full GNU General Public License is included in this distribution
> + * in the file called LICENSE.GPL.
> + *
> + * Contact Information:
> + * Intel Corporation.
> + * [email protected]
> + * http://www.intel.com
> + *
> + * BSD LICENSE
> + *
> + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in
> + * the documentation and/or other materials provided with the
> + * distribution.
> + * * Neither the name Intel Corporation nor the names of its
> + * contributors may be used to endorse or promote products derived
> + * from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + *****************************************************************************/

How is your .h file dual licensed, and yet, the .c file is gpl2 only?

Please fix this by not even having this .h file, it's not needed.


> +#ifndef _MEI_NFC_H
> +#define _MEI_NFC_H
> +
> +#include <linux/types.h>
> +
> +struct mei_nfc_cmd {
> + uint8_t command;
> + uint8_t status;
> + uint16_t req_id;
> + uint32_t reserved;
> + uint16_t data_size;
> + uint8_t sub_command;
> + uint8_t data[];
> +} __packed;

Use "real" Linux kernel data types, not these cruddy userspace ones
(i.e. u8, u16, etc.)

I've applied the patches prior to this in the series and stopped here,
so feel free to redo the rest of them and resend.

thanks,

greg k-h

2013-03-29 15:49:48

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [char-misc-next 08/11 V5] mei: nfc: Initial nfc implementation

On Wed, Mar 27, 2013 at 05:30:00PM +0200, Tomas Winkler wrote:
> --- a/drivers/misc/mei/mei_dev.h
> +++ b/drivers/misc/mei/mei_dev.h
> @@ -498,6 +498,34 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
>
> void mei_amthif_run_next_cmd(struct mei_device *dev);
>
> +#ifdef CONFIG_INTEL_MEI_BUS_NFC
> +/*
> + * NFC functions
> + */
> +int mei_nfc_host_init(struct mei_device *dev);
> +void mei_nfc_host_exit(void);
> +
> +/*
> + * NFC Client UUID
> + */
> +extern const uuid_le mei_nfc_guid;
> +
> +#else /* CONFIG_INTEL_MEI_BUS_NFC */
> +
> +static inline int mei_nfc_host_init(struct mei_device *dev)
> +{
> + return 0;
> +}
> +
> +static inline void mei_nfc_host_exit(void)
> +{
> + return;
> +}
> +
> +static const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
> + 0x94, 0xd4, 0x50, 0x26,
> + 0x67, 0x23, 0x77, 0x5c);
> +#endif /* CONFIG_INTEL_MEI_BUS_NFC */


As you are using the bus model, why do you need "fake" init and exit
functions at all? Your core shouldn't care about if the nfc code is
build or not, that's why we have driver model in the first place...

greg k-h

2013-03-31 22:49:56

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [char-misc-next 08/11 V5] mei: nfc: Initial nfc implementation

Hi Greg,

On Fri, Mar 29, 2013 at 08:48:23AM -0700, Greg KH wrote:
> On Wed, Mar 27, 2013 at 05:30:00PM +0200, Tomas Winkler wrote:
> > --- /dev/null
> > +++ b/drivers/misc/mei/nfc.h
> > @@ -0,0 +1,122 @@
> > +/******************************************************************************
> > + * Intel Management Engine Interface (Intel MEI) Linux driver
> > + * Intel MEI Interface Header
> > + *
> > + * This file is provided under a dual BSD/GPLv2 license. When using or
> > + * redistributing this file, you may do so under either license.
> > + *
> > + * GPL LICENSE SUMMARY
> > + *
> > + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of version 2 of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful, but
> > + * WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> > + * General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
> > + * USA
> > + *
> > + * The full GNU General Public License is included in this distribution
> > + * in the file called LICENSE.GPL.
> > + *
> > + * Contact Information:
> > + * Intel Corporation.
> > + * [email protected]
> > + * http://www.intel.com
> > + *
> > + * BSD LICENSE
> > + *
> > + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> > + * All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + *
> > + * * Redistributions of source code must retain the above copyright
> > + * notice, this list of conditions and the following disclaimer.
> > + * * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in
> > + * the documentation and/or other materials provided with the
> > + * distribution.
> > + * * Neither the name Intel Corporation nor the names of its
> > + * contributors may be used to endorse or promote products derived
> > + * from this software without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > + *
> > + *****************************************************************************/
>
> How is your .h file dual licensed, and yet, the .c file is gpl2 only?
>
> Please fix this by not even having this .h file, it's not needed.
The structures and commands defined in nfc.h may be used by pure userspace NFC
stacks (e.g. the Android ones) and I don't want them to be defined under a GPL
only license (Even though some will say structure and command definitions are
not copyrighteable). Would it be fine with you if I'd put those definitions
under include/uapi/linux/mei.h ?

> > +struct mei_nfc_cmd {
> > + uint8_t command;
> > + uint8_t status;
> > + uint16_t req_id;
> > + uint32_t reserved;
> > + uint16_t data_size;
> > + uint8_t sub_command;
> > + uint8_t data[];
> > +} __packed;
>
> Use "real" Linux kernel data types, not these cruddy userspace ones
> (i.e. u8, u16, etc.)
Will fix that.


> I've applied the patches prior to this in the series and stopped here,
Thanks.


> so feel free to redo the rest of them and resend.
I will do so in the next days.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2013-03-31 23:04:13

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [char-misc-next 08/11 V5] mei: nfc: Initial nfc implementation

On Mon, Apr 01, 2013 at 12:49:49AM +0200, Samuel Ortiz wrote:
> Hi Greg,
>
> On Fri, Mar 29, 2013 at 08:48:23AM -0700, Greg KH wrote:
> > On Wed, Mar 27, 2013 at 05:30:00PM +0200, Tomas Winkler wrote:
> > > --- /dev/null
> > > +++ b/drivers/misc/mei/nfc.h
> > > @@ -0,0 +1,122 @@
> > > +/******************************************************************************
> > > + * Intel Management Engine Interface (Intel MEI) Linux driver
> > > + * Intel MEI Interface Header
> > > + *
> > > + * This file is provided under a dual BSD/GPLv2 license. When using or
> > > + * redistributing this file, you may do so under either license.
> > > + *
> > > + * GPL LICENSE SUMMARY
> > > + *
> > > + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> > > + *
> > > + * This program is free software; you can redistribute it and/or modify
> > > + * it under the terms of version 2 of the GNU General Public License as
> > > + * published by the Free Software Foundation.
> > > + *
> > > + * This program is distributed in the hope that it will be useful, but
> > > + * WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> > > + * General Public License for more details.
> > > + *
> > > + * You should have received a copy of the GNU General Public License
> > > + * along with this program; if not, write to the Free Software
> > > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
> > > + * USA
> > > + *
> > > + * The full GNU General Public License is included in this distribution
> > > + * in the file called LICENSE.GPL.
> > > + *
> > > + * Contact Information:
> > > + * Intel Corporation.
> > > + * [email protected]
> > > + * http://www.intel.com
> > > + *
> > > + * BSD LICENSE
> > > + *
> > > + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> > > + * All rights reserved.
> > > + *
> > > + * Redistribution and use in source and binary forms, with or without
> > > + * modification, are permitted provided that the following conditions
> > > + * are met:
> > > + *
> > > + * * Redistributions of source code must retain the above copyright
> > > + * notice, this list of conditions and the following disclaimer.
> > > + * * Redistributions in binary form must reproduce the above copyright
> > > + * notice, this list of conditions and the following disclaimer in
> > > + * the documentation and/or other materials provided with the
> > > + * distribution.
> > > + * * Neither the name Intel Corporation nor the names of its
> > > + * contributors may be used to endorse or promote products derived
> > > + * from this software without specific prior written permission.
> > > + *
> > > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> > > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> > > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> > > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> > > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> > > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> > > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> > > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> > > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > > + *
> > > + *****************************************************************************/
> >
> > How is your .h file dual licensed, and yet, the .c file is gpl2 only?
> >
> > Please fix this by not even having this .h file, it's not needed.
> The structures and commands defined in nfc.h may be used by pure userspace NFC
> stacks (e.g. the Android ones) and I don't want them to be defined under a GPL
> only license (Even though some will say structure and command definitions are
> not copyrighteable).

The law says that structures and command definitions are not
copyrightable, Oracle hasn't overturned that one yet. That explains how
the BSDs now have the kobject api taken from Linux with no issues at
all.

> Would it be fine with you if I'd put those definitions under
> include/uapi/linux/mei.h ?

No, just put them in the driver itself, there is no need for them to be
in a .h file at all.

thanks,

greg k-h