blob: 4955a0908d049ab4eb4c40e7407a91b6fed24921 [file] [log] [blame]
Samuel Ortize5354102013-03-27 17:29:53 +02001/*
2 * Intel Management Engine Interface (Intel MEI) Linux driver
3 * Copyright (c) 2012-2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/kernel.h>
Samuel Ortiz3e833292013-03-27 17:29:55 +020019#include <linux/sched.h>
Samuel Ortize5354102013-03-27 17:29:53 +020020#include <linux/init.h>
21#include <linux/errno.h>
22#include <linux/slab.h>
23#include <linux/mutex.h>
24#include <linux/interrupt.h>
Samuel Ortize5354102013-03-27 17:29:53 +020025#include <linux/mei_cl_bus.h>
26
27#include "mei_dev.h"
Samuel Ortiz3e833292013-03-27 17:29:55 +020028#include "client.h"
Samuel Ortize5354102013-03-27 17:29:53 +020029
30#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
31#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
32
Tomas Winkler62382992015-07-23 15:08:35 +030033/**
34 * __mei_cl_send - internal client send (write)
35 *
36 * @cl: host client
37 * @buf: buffer to send
38 * @length: buffer length
39 * @blocking: wait for write completion
40 *
41 * Return: written size bytes or < 0 on error
42 */
43ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
44 bool blocking)
45{
46 struct mei_device *bus;
47 struct mei_cl_cb *cb = NULL;
48 ssize_t rets;
49
50 if (WARN_ON(!cl || !cl->dev))
51 return -ENODEV;
52
53 bus = cl->dev;
54
55 mutex_lock(&bus->device_lock);
56 if (!mei_cl_is_connected(cl)) {
57 rets = -ENODEV;
58 goto out;
59 }
60
61 /* Check if we have an ME client device */
62 if (!mei_me_cl_is_active(cl->me_cl)) {
63 rets = -ENOTTY;
64 goto out;
65 }
66
67 if (length > mei_cl_mtu(cl)) {
68 rets = -EFBIG;
69 goto out;
70 }
71
72 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
73 if (!cb) {
74 rets = -ENOMEM;
75 goto out;
76 }
77
78 memcpy(cb->buf.data, buf, length);
79
80 rets = mei_cl_write(cl, cb, blocking);
81
82out:
83 mutex_unlock(&bus->device_lock);
84 if (rets < 0)
85 mei_io_cb_free(cb);
86
87 return rets;
88}
89
90/**
91 * __mei_cl_recv - internal client receive (read)
92 *
93 * @cl: host client
94 * @buf: buffer to send
95 * @length: buffer length
96 *
97 * Return: read size in bytes of < 0 on error
98 */
99ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
100{
101 struct mei_device *bus;
102 struct mei_cl_cb *cb;
103 size_t r_length;
104 ssize_t rets;
105
106 if (WARN_ON(!cl || !cl->dev))
107 return -ENODEV;
108
109 bus = cl->dev;
110
111 mutex_lock(&bus->device_lock);
112
113 cb = mei_cl_read_cb(cl, NULL);
114 if (cb)
115 goto copy;
116
117 rets = mei_cl_read_start(cl, length, NULL);
118 if (rets && rets != -EBUSY)
119 goto out;
120
121 /* wait on event only if there is no other waiter */
122 if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
123
124 mutex_unlock(&bus->device_lock);
125
126 if (wait_event_interruptible(cl->rx_wait,
127 (!list_empty(&cl->rd_completed)) ||
128 (!mei_cl_is_connected(cl)))) {
129
130 if (signal_pending(current))
131 return -EINTR;
132 return -ERESTARTSYS;
133 }
134
135 mutex_lock(&bus->device_lock);
136
137 if (!mei_cl_is_connected(cl)) {
138 rets = -EBUSY;
139 goto out;
140 }
141 }
142
143 cb = mei_cl_read_cb(cl, NULL);
144 if (!cb) {
145 rets = 0;
146 goto out;
147 }
148
149copy:
150 if (cb->status) {
151 rets = cb->status;
152 goto free;
153 }
154
155 r_length = min_t(size_t, length, cb->buf_idx);
156 memcpy(buf, cb->buf.data, r_length);
157 rets = r_length;
158
159free:
160 mei_io_cb_free(cb);
161out:
162 mutex_unlock(&bus->device_lock);
163
164 return rets;
165}
166
167/**
168 * mei_cl_send - me device send (write)
169 *
170 * @cldev: me client device
171 * @buf: buffer to send
172 * @length: buffer length
173 *
174 * Return: written size in bytes or < 0 on error
175 */
176ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
177{
178 struct mei_cl *cl = cldev->cl;
179
180 if (cl == NULL)
181 return -ENODEV;
182
183 return __mei_cl_send(cl, buf, length, 1);
184}
185EXPORT_SYMBOL_GPL(mei_cl_send);
186
187/**
188 * mei_cl_recv - client receive (read)
189 *
190 * @cldev: me client device
191 * @buf: buffer to send
192 * @length: buffer length
193 *
194 * Return: read size in bytes of < 0 on error
195 */
196ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
197{
198 struct mei_cl *cl = cldev->cl;
199
200 if (cl == NULL)
201 return -ENODEV;
202
203 return __mei_cl_recv(cl, buf, length);
204}
205EXPORT_SYMBOL_GPL(mei_cl_recv);
206
207/**
208 * mei_bus_event_work - dispatch rx event for a bus device
209 * and schedule new work
210 *
211 * @work: work
212 */
213static void mei_bus_event_work(struct work_struct *work)
214{
215 struct mei_cl_device *cldev;
216
217 cldev = container_of(work, struct mei_cl_device, event_work);
218
219 if (cldev->event_cb)
220 cldev->event_cb(cldev, cldev->events, cldev->event_context);
221
222 cldev->events = 0;
223
224 /* Prepare for the next read */
225 mei_cl_read_start(cldev->cl, 0, NULL);
226}
227
228/**
229 * mei_cl_bus_rx_event - schedule rx evenet
230 *
231 * @cl: host client
232 */
233void mei_cl_bus_rx_event(struct mei_cl *cl)
234{
235 struct mei_cl_device *cldev = cl->cldev;
236
237 if (!cldev || !cldev->event_cb)
238 return;
239
240 set_bit(MEI_CL_EVENT_RX, &cldev->events);
241
242 schedule_work(&cldev->event_work);
243}
244
245/**
246 * mei_cl_register_event_cb - register event callback
247 *
248 * @cldev: me client devices
249 * @event_cb: callback function
250 * @context: driver context data
251 *
252 * Return: 0 on success
253 * -EALREADY if an callback is already registered
254 * <0 on other errors
255 */
256int mei_cl_register_event_cb(struct mei_cl_device *cldev,
257 mei_cl_event_cb_t event_cb, void *context)
258{
Tomas Winkler48168f42015-07-23 15:08:38 +0300259 int ret;
260
Tomas Winkler62382992015-07-23 15:08:35 +0300261 if (cldev->event_cb)
262 return -EALREADY;
263
264 cldev->events = 0;
265 cldev->event_cb = event_cb;
266 cldev->event_context = context;
267 INIT_WORK(&cldev->event_work, mei_bus_event_work);
268
Tomas Winkler48168f42015-07-23 15:08:38 +0300269 ret = mei_cl_read_start(cldev->cl, 0, NULL);
270 if (ret && ret != -EBUSY)
271 return ret;
Tomas Winkler62382992015-07-23 15:08:35 +0300272
273 return 0;
274}
275EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
276
277/**
278 * mei_cl_get_drvdata - driver data getter
279 *
280 * @cldev: mei client device
281 *
282 * Return: driver private data
283 */
284void *mei_cl_get_drvdata(const struct mei_cl_device *cldev)
285{
286 return dev_get_drvdata(&cldev->dev);
287}
288EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
289
290/**
291 * mei_cl_set_drvdata - driver data setter
292 *
293 * @cldev: mei client device
294 * @data: data to store
295 */
296void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data)
297{
298 dev_set_drvdata(&cldev->dev, data);
299}
300EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
301
302/**
303 * mei_cl_enable_device - enable me client device
304 * create connection with me client
305 *
306 * @cldev: me client device
307 *
308 * Return: 0 on success and < 0 on error
309 */
310int mei_cl_enable_device(struct mei_cl_device *cldev)
311{
312 int err;
313 struct mei_device *bus;
314 struct mei_cl *cl = cldev->cl;
315
316 if (cl == NULL)
317 return -ENODEV;
318
319 bus = cl->dev;
320
321 mutex_lock(&bus->device_lock);
322
323 if (mei_cl_is_connected(cl)) {
324 mutex_unlock(&bus->device_lock);
325 dev_warn(bus->dev, "Already connected");
326 return -EBUSY;
327 }
328
329 err = mei_cl_connect(cl, cldev->me_cl, NULL);
330 if (err < 0) {
331 mutex_unlock(&bus->device_lock);
332 dev_err(bus->dev, "Could not connect to the ME client");
333
334 return err;
335 }
336
337 mutex_unlock(&bus->device_lock);
338
Tomas Winkler62382992015-07-23 15:08:35 +0300339 return 0;
340}
341EXPORT_SYMBOL_GPL(mei_cl_enable_device);
342
343/**
344 * mei_cl_disable_device - disable me client device
345 * disconnect form the me client
346 *
347 * @cldev: me client device
348 *
349 * Return: 0 on success and < 0 on error
350 */
351int mei_cl_disable_device(struct mei_cl_device *cldev)
352{
353 int err;
354 struct mei_device *bus;
355 struct mei_cl *cl = cldev->cl;
356
357 if (cl == NULL)
358 return -ENODEV;
359
360 bus = cl->dev;
361
362 cldev->event_cb = NULL;
363
364 mutex_lock(&bus->device_lock);
365
366 if (!mei_cl_is_connected(cl)) {
367 dev_err(bus->dev, "Already disconnected");
368 err = 0;
369 goto out;
370 }
371
372 err = mei_cl_disconnect(cl);
373 if (err < 0) {
374 dev_err(bus->dev, "Could not disconnect from the ME client");
375 goto out;
376 }
377
378 /* Flush queues and remove any pending read */
379 mei_cl_flush_queues(cl, NULL);
380
381out:
382 mutex_unlock(&bus->device_lock);
383 return err;
384
385}
386EXPORT_SYMBOL_GPL(mei_cl_disable_device);
387
Tomas Winkler688a9cc2015-07-23 15:08:39 +0300388/**
389 * mei_cl_device_find - find matching entry in the driver id table
390 *
391 * @cldev: me client device
392 * @cldrv: me client driver
393 *
394 * Return: id on success; NULL if no id is matching
395 */
396static const
397struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev,
398 struct mei_cl_driver *cldrv)
Samuel Ortize5354102013-03-27 17:29:53 +0200399{
Samuel Ortize5354102013-03-27 17:29:53 +0200400 const struct mei_cl_device_id *id;
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300401 const uuid_le *uuid;
Samuel Ortize5354102013-03-27 17:29:53 +0200402
Tomas Winklerb37719c32015-07-23 15:08:33 +0300403 uuid = mei_me_cl_uuid(cldev->me_cl);
Samuel Ortize5354102013-03-27 17:29:53 +0200404
Tomas Winklerb37719c32015-07-23 15:08:33 +0300405 id = cldrv->id_table;
Greg Kroah-Hartmanb144ce22015-05-27 17:17:27 -0700406 while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) {
Greg Kroah-Hartmanb144ce22015-05-27 17:17:27 -0700407 if (!uuid_le_cmp(*uuid, id->uuid)) {
Tomas Winkler688a9cc2015-07-23 15:08:39 +0300408
409 if (!cldev->name[0])
410 return id;
411
412 if (!strncmp(cldev->name, id->name, sizeof(id->name)))
413 return id;
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300414 }
Samuel Ortize5354102013-03-27 17:29:53 +0200415
416 id++;
417 }
418
Tomas Winkler688a9cc2015-07-23 15:08:39 +0300419 return NULL;
420}
421
422/**
423 * mei_cl_device_match - device match function
424 *
425 * @dev: device
426 * @drv: driver
427 *
428 * Return: 1 if matching device was found 0 otherwise
429 */
430static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
431{
432 struct mei_cl_device *cldev = to_mei_cl_device(dev);
433 struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
434 const struct mei_cl_device_id *found_id;
435
436 if (!cldev)
437 return 0;
438
439 if (!cldrv || !cldrv->id_table)
440 return 0;
441
442 found_id = mei_cl_device_find(cldev, cldrv);
443 if (found_id)
444 return 1;
445
Samuel Ortize5354102013-03-27 17:29:53 +0200446 return 0;
447}
448
449static int mei_cl_device_probe(struct device *dev)
450{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300451 struct mei_cl_device *cldev = to_mei_cl_device(dev);
452 struct mei_cl_driver *cldrv;
Samuel Ortize5354102013-03-27 17:29:53 +0200453 struct mei_cl_device_id id;
454
Tomas Winklerb37719c32015-07-23 15:08:33 +0300455 if (!cldev)
Samuel Ortize5354102013-03-27 17:29:53 +0200456 return 0;
457
Tomas Winklerb37719c32015-07-23 15:08:33 +0300458 cldrv = to_mei_cl_driver(dev->driver);
459 if (!cldrv || !cldrv->probe)
Samuel Ortize5354102013-03-27 17:29:53 +0200460 return -ENODEV;
461
462 dev_dbg(dev, "Device probe\n");
463
Tomas Winklerb37719c32015-07-23 15:08:33 +0300464 strlcpy(id.name, cldev->name, sizeof(id.name));
Samuel Ortize5354102013-03-27 17:29:53 +0200465
Tomas Winklerb37719c32015-07-23 15:08:33 +0300466 return cldrv->probe(cldev, &id);
Samuel Ortize5354102013-03-27 17:29:53 +0200467}
468
469static int mei_cl_device_remove(struct device *dev)
470{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300471 struct mei_cl_device *cldev = to_mei_cl_device(dev);
472 struct mei_cl_driver *cldrv;
Samuel Ortize5354102013-03-27 17:29:53 +0200473
Tomas Winklerb37719c32015-07-23 15:08:33 +0300474 if (!cldev || !dev->driver)
Samuel Ortize5354102013-03-27 17:29:53 +0200475 return 0;
476
Tomas Winklerb37719c32015-07-23 15:08:33 +0300477 if (cldev->event_cb) {
478 cldev->event_cb = NULL;
479 cancel_work_sync(&cldev->event_work);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200480 }
481
Tomas Winklerb37719c32015-07-23 15:08:33 +0300482 cldrv = to_mei_cl_driver(dev->driver);
483 if (!cldrv->remove) {
Samuel Ortize5354102013-03-27 17:29:53 +0200484 dev->driver = NULL;
485
486 return 0;
487 }
488
Tomas Winklerb37719c32015-07-23 15:08:33 +0300489 return cldrv->remove(cldev);
Samuel Ortize5354102013-03-27 17:29:53 +0200490}
491
Tomas Winkler007d64e2015-05-07 15:54:03 +0300492static ssize_t name_show(struct device *dev, struct device_attribute *a,
493 char *buf)
494{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300495 struct mei_cl_device *cldev = to_mei_cl_device(dev);
Tomas Winkler007d64e2015-05-07 15:54:03 +0300496 size_t len;
497
Tomas Winklerb37719c32015-07-23 15:08:33 +0300498 len = snprintf(buf, PAGE_SIZE, "%s", cldev->name);
Tomas Winkler007d64e2015-05-07 15:54:03 +0300499
500 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
501}
502static DEVICE_ATTR_RO(name);
503
504static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
505 char *buf)
506{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300507 struct mei_cl_device *cldev = to_mei_cl_device(dev);
508 const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
Tomas Winkler007d64e2015-05-07 15:54:03 +0300509 size_t len;
510
511 len = snprintf(buf, PAGE_SIZE, "%pUl", uuid);
512
513 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
514}
515static DEVICE_ATTR_RO(uuid);
516
Samuel Ortize5354102013-03-27 17:29:53 +0200517static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
518 char *buf)
519{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300520 struct mei_cl_device *cldev = to_mei_cl_device(dev);
521 const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300522 size_t len;
Samuel Ortize5354102013-03-27 17:29:53 +0200523
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300524 len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":",
Tomas Winklerb37719c32015-07-23 15:08:33 +0300525 cldev->name, MEI_CL_UUID_ARGS(uuid->b));
Samuel Ortize5354102013-03-27 17:29:53 +0200526
527 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
528}
Greg Kroah-Hartman32f389ec2013-08-23 14:24:39 -0700529static DEVICE_ATTR_RO(modalias);
Samuel Ortize5354102013-03-27 17:29:53 +0200530
Greg Kroah-Hartman32f389ec2013-08-23 14:24:39 -0700531static struct attribute *mei_cl_dev_attrs[] = {
Tomas Winkler007d64e2015-05-07 15:54:03 +0300532 &dev_attr_name.attr,
533 &dev_attr_uuid.attr,
Greg Kroah-Hartman32f389ec2013-08-23 14:24:39 -0700534 &dev_attr_modalias.attr,
535 NULL,
Samuel Ortize5354102013-03-27 17:29:53 +0200536};
Greg Kroah-Hartman32f389ec2013-08-23 14:24:39 -0700537ATTRIBUTE_GROUPS(mei_cl_dev);
Samuel Ortize5354102013-03-27 17:29:53 +0200538
Tomas Winkler38d3c002015-07-23 15:08:36 +0300539/**
540 * mei_cl_device_uevent - me client bus uevent handler
541 *
542 * @dev: device
543 * @env: uevent kobject
544 *
545 * Return: 0 on success -ENOMEM on when add_uevent_var fails
546 */
547static int mei_cl_device_uevent(struct device *dev, struct kobj_uevent_env *env)
Samuel Ortize5354102013-03-27 17:29:53 +0200548{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300549 struct mei_cl_device *cldev = to_mei_cl_device(dev);
550 const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300551
Tomas Winkler007d64e2015-05-07 15:54:03 +0300552 if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid))
553 return -ENOMEM;
554
Tomas Winklerb37719c32015-07-23 15:08:33 +0300555 if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name))
Tomas Winkler007d64e2015-05-07 15:54:03 +0300556 return -ENOMEM;
557
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300558 if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":",
Tomas Winklerb37719c32015-07-23 15:08:33 +0300559 cldev->name, MEI_CL_UUID_ARGS(uuid->b)))
Samuel Ortize5354102013-03-27 17:29:53 +0200560 return -ENOMEM;
561
562 return 0;
563}
564
565static struct bus_type mei_cl_bus_type = {
566 .name = "mei",
Greg Kroah-Hartman32f389ec2013-08-23 14:24:39 -0700567 .dev_groups = mei_cl_dev_groups,
Samuel Ortize5354102013-03-27 17:29:53 +0200568 .match = mei_cl_device_match,
569 .probe = mei_cl_device_probe,
570 .remove = mei_cl_device_remove,
Tomas Winkler38d3c002015-07-23 15:08:36 +0300571 .uevent = mei_cl_device_uevent,
Samuel Ortize5354102013-03-27 17:29:53 +0200572};
573
574static void mei_cl_dev_release(struct device *dev)
575{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300576 struct mei_cl_device *cldev = to_mei_cl_device(dev);
Alexander Usyskind49ed642015-05-04 09:43:54 +0300577
Tomas Winklerb37719c32015-07-23 15:08:33 +0300578 if (!cldev)
Alexander Usyskind49ed642015-05-04 09:43:54 +0300579 return;
580
Tomas Winklerb37719c32015-07-23 15:08:33 +0300581 mei_me_cl_put(cldev->me_cl);
582 kfree(cldev);
Samuel Ortize5354102013-03-27 17:29:53 +0200583}
584
585static struct device_type mei_cl_device_type = {
586 .release = mei_cl_dev_release,
587};
588
Tomas Winklerb37719c32015-07-23 15:08:33 +0300589struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus,
Alexander Usyskind49ed642015-05-04 09:43:54 +0300590 uuid_le uuid)
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200591{
Tomas Winkler31f88f52014-02-17 15:13:25 +0200592 struct mei_cl *cl;
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200593
Tomas Winklerb37719c32015-07-23 15:08:33 +0300594 list_for_each_entry(cl, &bus->device_list, device_link) {
595 if (cl->cldev && cl->cldev->me_cl &&
596 !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl)))
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200597 return cl;
598 }
599
600 return NULL;
601}
Alexander Usyskind49ed642015-05-04 09:43:54 +0300602
Tomas Winklerb37719c32015-07-23 15:08:33 +0300603struct mei_cl_device *mei_cl_add_device(struct mei_device *bus,
Alexander Usyskind49ed642015-05-04 09:43:54 +0300604 struct mei_me_client *me_cl,
605 struct mei_cl *cl,
Tomas Winklerbe9b7202015-05-07 15:54:04 +0300606 char *name)
Samuel Ortize5354102013-03-27 17:29:53 +0200607{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300608 struct mei_cl_device *cldev;
Samuel Ortize5354102013-03-27 17:29:53 +0200609 int status;
610
Tomas Winklerb37719c32015-07-23 15:08:33 +0300611 cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
612 if (!cldev)
Samuel Ortize5354102013-03-27 17:29:53 +0200613 return NULL;
614
Tomas Winklerb37719c32015-07-23 15:08:33 +0300615 cldev->me_cl = mei_me_cl_get(me_cl);
616 if (!cldev->me_cl) {
617 kfree(cldev);
Alexander Usyskind49ed642015-05-04 09:43:54 +0300618 return NULL;
619 }
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200620
Tomas Winklerb37719c32015-07-23 15:08:33 +0300621 cldev->cl = cl;
622 cldev->dev.parent = bus->dev;
623 cldev->dev.bus = &mei_cl_bus_type;
624 cldev->dev.type = &mei_cl_device_type;
Samuel Ortize5354102013-03-27 17:29:53 +0200625
Tomas Winklerb37719c32015-07-23 15:08:33 +0300626 strlcpy(cldev->name, name, sizeof(cldev->name));
Tomas Winklerc93b76b2015-05-07 15:54:02 +0300627
Tomas Winklerb37719c32015-07-23 15:08:33 +0300628 dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl));
Samuel Ortize5354102013-03-27 17:29:53 +0200629
Tomas Winklerb37719c32015-07-23 15:08:33 +0300630 status = device_register(&cldev->dev);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200631 if (status) {
Tomas Winklerb37719c32015-07-23 15:08:33 +0300632 dev_err(bus->dev, "Failed to register MEI device\n");
633 mei_me_cl_put(cldev->me_cl);
634 kfree(cldev);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200635 return NULL;
636 }
637
Tomas Winklerb37719c32015-07-23 15:08:33 +0300638 cl->cldev = cldev;
Samuel Ortize5354102013-03-27 17:29:53 +0200639
Tomas Winklerb37719c32015-07-23 15:08:33 +0300640 dev_dbg(&cldev->dev, "client %s registered\n", name);
Samuel Ortize5354102013-03-27 17:29:53 +0200641
Tomas Winklerb37719c32015-07-23 15:08:33 +0300642 return cldev;
Samuel Ortize5354102013-03-27 17:29:53 +0200643}
644EXPORT_SYMBOL_GPL(mei_cl_add_device);
645
Tomas Winklerb37719c32015-07-23 15:08:33 +0300646void mei_cl_remove_device(struct mei_cl_device *cldev)
Samuel Ortize5354102013-03-27 17:29:53 +0200647{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300648 device_unregister(&cldev->dev);
Samuel Ortize5354102013-03-27 17:29:53 +0200649}
650EXPORT_SYMBOL_GPL(mei_cl_remove_device);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200651
Tomas Winklerb37719c32015-07-23 15:08:33 +0300652int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner)
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200653{
654 int err;
655
Tomas Winklerb37719c32015-07-23 15:08:33 +0300656 cldrv->driver.name = cldrv->name;
657 cldrv->driver.owner = owner;
658 cldrv->driver.bus = &mei_cl_bus_type;
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200659
Tomas Winklerb37719c32015-07-23 15:08:33 +0300660 err = driver_register(&cldrv->driver);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200661 if (err)
662 return err;
663
Tomas Winklerb37719c32015-07-23 15:08:33 +0300664 pr_debug("mei: driver [%s] registered\n", cldrv->driver.name);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200665
666 return 0;
667}
668EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
669
Tomas Winklerb37719c32015-07-23 15:08:33 +0300670void mei_cl_driver_unregister(struct mei_cl_driver *cldrv)
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200671{
Tomas Winklerb37719c32015-07-23 15:08:33 +0300672 driver_unregister(&cldrv->driver);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200673
Tomas Winklerb37719c32015-07-23 15:08:33 +0300674 pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200675}
676EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200677
Samuel Ortizcf3baef2013-03-27 17:29:57 +0200678int __init mei_cl_bus_init(void)
679{
680 return bus_register(&mei_cl_bus_type);
681}
682
683void __exit mei_cl_bus_exit(void)
684{
685 bus_unregister(&mei_cl_bus_type);
686}