aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2013-04-08 18:51:38 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-08 19:57:15 -0400
commite46980a10a76ec3282dd6832c1974b880acd23d3 (patch)
tree42d8e5abab5991b4026af385545e23af619f610b
parentd6c36a475fccfca05fd05362c98e49f6dd07721c (diff)
mei: bus: Add device enabling and disabling API
It should be left to the drivers to enable and disable the device on the MEI bus when e.g getting probed. For drivers to be able to safely call the enable and disable hooks, the mei_cl_ops must be set before it's probed and thus this should happen before registering the device on the MEI bus. Hence the mei_cl_add_device() prototype change. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/misc-devices/mei/mei-client-bus.txt7
-rw-r--r--drivers/misc/mei/bus.c99
-rw-r--r--drivers/misc/mei/mei_dev.h28
-rw-r--r--include/linux/mei_cl_bus.h3
4 files changed, 123 insertions, 14 deletions
diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
index 9dc5ebf94eb1..f83910a8ce76 100644
--- a/Documentation/misc-devices/mei/mei-client-bus.txt
+++ b/Documentation/misc-devices/mei/mei-client-bus.txt
@@ -104,13 +104,16 @@ int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
104 struct contact_driver *contact; 104 struct contact_driver *contact;
105 105
106 [...] 106 [...]
107 mei_cl_enable_device(dev);
108
107 mei_cl_register_event_cb(dev, contact_event_cb, contact); 109 mei_cl_register_event_cb(dev, contact_event_cb, contact);
108 110
109 return 0; 111 return 0;
110 } 112 }
111 113
112In the probe routine the driver basically registers an ME bus event handler 114In the probe routine the driver first enable the MEI device and then registers
113which is as close as it can get to registering a threaded IRQ handler. 115an ME bus event handler which is as close as it can get to registering a
116threaded IRQ handler.
114The handler implementation will typically call some I/O routine depending on 117The handler implementation will typically call some I/O routine depending on
115the pending events: 118the pending events:
116 119
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 6badfa1110e9..834ceeb69cbf 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -153,7 +153,8 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
153 return NULL; 153 return NULL;
154} 154}
155struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, 155struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
156 uuid_le uuid, char *name) 156 uuid_le uuid, char *name,
157 struct mei_cl_ops *ops)
157{ 158{
158 struct mei_cl_device *device; 159 struct mei_cl_device *device;
159 struct mei_cl *cl; 160 struct mei_cl *cl;
@@ -168,6 +169,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
168 return NULL; 169 return NULL;
169 170
170 device->cl = cl; 171 device->cl = cl;
172 device->ops = ops;
171 173
172 device->dev.parent = &dev->pdev->dev; 174 device->dev.parent = &dev->pdev->dev;
173 device->dev.bus = &mei_cl_bus_type; 175 device->dev.bus = &mei_cl_bus_type;
@@ -408,6 +410,101 @@ void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
408} 410}
409EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); 411EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
410 412
413int mei_cl_enable_device(struct mei_cl_device *device)
414{
415 int err;
416 struct mei_device *dev;
417 struct mei_cl *cl = device->cl;
418
419 if (cl == NULL)
420 return -ENODEV;
421
422 dev = cl->dev;
423
424 mutex_lock(&dev->device_lock);
425
426 cl->state = MEI_FILE_CONNECTING;
427
428 err = mei_cl_connect(cl, NULL);
429 if (err < 0) {
430 mutex_unlock(&dev->device_lock);
431 dev_err(&dev->pdev->dev, "Could not connect to the ME client");
432
433 return err;
434 }
435
436 mutex_unlock(&dev->device_lock);
437
438 if (device->event_cb && !cl->read_cb)
439 mei_cl_read_start(device->cl);
440
441 if (!device->ops || !device->ops->enable)
442 return 0;
443
444 return device->ops->enable(device);
445}
446EXPORT_SYMBOL_GPL(mei_cl_enable_device);
447
448int mei_cl_disable_device(struct mei_cl_device *device)
449{
450 int err;
451 struct mei_device *dev;
452 struct mei_cl *cl = device->cl;
453
454 if (cl == NULL)
455 return -ENODEV;
456
457 dev = cl->dev;
458
459 mutex_lock(&dev->device_lock);
460
461 if (cl->state != MEI_FILE_CONNECTED) {
462 mutex_unlock(&dev->device_lock);
463 dev_err(&dev->pdev->dev, "Already disconnected");
464
465 return 0;
466 }
467
468 cl->state = MEI_FILE_DISCONNECTING;
469
470 err = mei_cl_disconnect(cl);
471 if (err < 0) {
472 mutex_unlock(&dev->device_lock);
473 dev_err(&dev->pdev->dev,
474 "Could not disconnect from the ME client");
475
476 return err;
477 }
478
479 /* Flush queues and remove any pending read */
480 mei_cl_flush_queues(cl);
481
482 if (cl->read_cb) {
483 struct mei_cl_cb *cb = NULL;
484
485 cb = mei_cl_find_read_cb(cl);
486 /* Remove entry from read list */
487 if (cb)
488 list_del(&cb->list);
489
490 cb = cl->read_cb;
491 cl->read_cb = NULL;
492
493 if (cb) {
494 mei_io_cb_free(cb);
495 cb = NULL;
496 }
497 }
498
499 mutex_unlock(&dev->device_lock);
500
501 if (!device->ops || !device->ops->disable)
502 return 0;
503
504 return device->ops->disable(device);
505}
506EXPORT_SYMBOL_GPL(mei_cl_disable_device);
507
411void mei_cl_bus_rx_event(struct mei_cl *cl) 508void mei_cl_bus_rx_event(struct mei_cl *cl)
412{ 509{
413 struct mei_cl_device *device = cl->device; 510 struct mei_cl_device *device = cl->device;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d786da6aa25b..c02967d01527 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -269,30 +269,36 @@ struct mei_hw_ops {
269}; 269};
270 270
271/* MEI bus API*/ 271/* MEI bus API*/
272struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
273 uuid_le uuid, char *name);
274void mei_cl_remove_device(struct mei_cl_device *device);
275
276int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
277int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
278int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
279 272
280/** 273/**
281 * struct mei_cl_transport_ops - MEI CL device transport ops 274 * struct mei_cl_ops - MEI CL device ops
282 * This structure allows ME host clients to implement technology 275 * This structure allows ME host clients to implement technology
283 * specific transport layers. 276 * specific operations.
284 * 277 *
278 * @enable: Enable an MEI CL device. Some devices require specific
279 * HECI commands to initialize completely.
280 * @disable: Disable an MEI CL device.
285 * @send: Tx hook for the device. This allows ME host clients to trap 281 * @send: Tx hook for the device. This allows ME host clients to trap
286 * the device driver buffers before actually physically 282 * the device driver buffers before actually physically
287 * pushing it to the ME. 283 * pushing it to the ME.
288 * @recv: Rx hook for the device. This allows ME host clients to trap the 284 * @recv: Rx hook for the device. This allows ME host clients to trap the
289 * ME buffers before forwarding them to the device driver. 285 * ME buffers before forwarding them to the device driver.
290 */ 286 */
291struct mei_cl_transport_ops { 287struct mei_cl_ops {
288 int (*enable)(struct mei_cl_device *device);
289 int (*disable)(struct mei_cl_device *device);
292 int (*send)(struct mei_cl_device *device, u8 *buf, size_t length); 290 int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
293 int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length); 291 int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
294}; 292};
295 293
294struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
295 uuid_le uuid, char *name,
296 struct mei_cl_ops *ops);
297void mei_cl_remove_device(struct mei_cl_device *device);
298
299int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
300int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
301int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
296void mei_cl_bus_rx_event(struct mei_cl *cl); 302void mei_cl_bus_rx_event(struct mei_cl *cl);
297int mei_cl_bus_init(void); 303int mei_cl_bus_init(void);
298void mei_cl_bus_exit(void); 304void mei_cl_bus_exit(void);
@@ -319,7 +325,7 @@ struct mei_cl_device {
319 325
320 struct mei_cl *cl; 326 struct mei_cl *cl;
321 327
322 const struct mei_cl_transport_ops *ops; 328 const struct mei_cl_ops *ops;
323 329
324 struct work_struct event_work; 330 struct work_struct event_work;
325 mei_cl_event_cb_t event_cb; 331 mei_cl_event_cb_t event_cb;
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 1bece18825ba..d14af7b722ef 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -38,4 +38,7 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
38void *mei_cl_get_drvdata(const struct mei_cl_device *device); 38void *mei_cl_get_drvdata(const struct mei_cl_device *device);
39void mei_cl_set_drvdata(struct mei_cl_device *device, void *data); 39void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
40 40
41int mei_cl_enable_device(struct mei_cl_device *device);
42int mei_cl_disable_device(struct mei_cl_device *device);
43
41#endif /* _LINUX_MEI_CL_BUS_H */ 44#endif /* _LINUX_MEI_CL_BUS_H */