Commit | Line | Data |
---|---|---|
19838fb8 TW |
1 | /* |
2 | * | |
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | |
4 | * Copyright (c) 2003-2012, Intel Corporation. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/fs.h> | |
19 | #include <linux/errno.h> | |
20 | #include <linux/types.h> | |
21 | #include <linux/fcntl.h> | |
19838fb8 TW |
22 | #include <linux/ioctl.h> |
23 | #include <linux/cdev.h> | |
24 | #include <linux/list.h> | |
25 | #include <linux/delay.h> | |
26 | #include <linux/sched.h> | |
27 | #include <linux/uuid.h> | |
28 | #include <linux/jiffies.h> | |
29 | #include <linux/uaccess.h> | |
1f180359 | 30 | #include <linux/slab.h> |
19838fb8 | 31 | |
47a73801 | 32 | #include <linux/mei.h> |
19838fb8 TW |
33 | |
34 | #include "mei_dev.h" | |
0edb23fc | 35 | #include "hbm.h" |
90e0b5f1 | 36 | #include "client.h" |
19838fb8 | 37 | |
1a1aca42 TW |
38 | const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, |
39 | 0xac, 0xa8, 0x46, 0xe0, | |
40 | 0xff, 0x65, 0x81, 0x4c); | |
19838fb8 TW |
41 | |
42 | /** | |
43 | * mei_amthif_reset_params - initializes mei device iamthif | |
44 | * | |
45 | * @dev: the device structure | |
46 | */ | |
47 | void mei_amthif_reset_params(struct mei_device *dev) | |
48 | { | |
49 | /* reset iamthif parameters. */ | |
50 | dev->iamthif_current_cb = NULL; | |
19838fb8 | 51 | dev->iamthif_canceled = false; |
19838fb8 TW |
52 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
53 | dev->iamthif_timer = 0; | |
4a704575 | 54 | dev->iamthif_stall_timer = 0; |
22f96a0e | 55 | dev->iamthif_open_count = 0; |
19838fb8 TW |
56 | } |
57 | ||
58 | /** | |
393b148f | 59 | * mei_amthif_host_init - mei initialization amthif client. |
19838fb8 TW |
60 | * |
61 | * @dev: the device structure | |
d49ed64a | 62 | * @me_cl: me client |
19838fb8 | 63 | * |
ce23139c | 64 | * Return: 0 on success, <0 on failure. |
19838fb8 | 65 | */ |
d49ed64a | 66 | int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl) |
19838fb8 | 67 | { |
781d0d89 | 68 | struct mei_cl *cl = &dev->iamthif_cl; |
d320832f | 69 | int ret; |
19838fb8 | 70 | |
6222f7bf TW |
71 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
72 | ||
781d0d89 | 73 | mei_cl_init(cl, dev); |
19838fb8 | 74 | |
781d0d89 | 75 | ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); |
781d0d89 | 76 | if (ret < 0) { |
79563db9 | 77 | dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); |
d49ed64a | 78 | return ret; |
781d0d89 TW |
79 | } |
80 | ||
d49ed64a | 81 | ret = mei_cl_connect(cl, me_cl, NULL); |
64092858 TW |
82 | |
83 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | |
84 | ||
85 | return ret; | |
19838fb8 TW |
86 | } |
87 | ||
88 | /** | |
89 | * mei_amthif_find_read_list_entry - finds a amthilist entry for current file | |
90 | * | |
91 | * @dev: the device structure | |
92 | * @file: pointer to file object | |
93 | * | |
a8605ea2 | 94 | * Return: returned a list entry on success, NULL on failure. |
19838fb8 TW |
95 | */ |
96 | struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, | |
97 | struct file *file) | |
98 | { | |
31f88f57 | 99 | struct mei_cl_cb *cb; |
92db1555 | 100 | |
05e314e2 AU |
101 | list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) |
102 | if (cb->file_object == file) | |
31f88f57 | 103 | return cb; |
19838fb8 TW |
104 | return NULL; |
105 | } | |
106 | ||
107 | ||
108 | /** | |
109 | * mei_amthif_read - read data from AMTHIF client | |
110 | * | |
111 | * @dev: the device structure | |
19838fb8 | 112 | * @file: pointer to file object |
a8605ea2 | 113 | * @ubuf: pointer to user data in user space |
19838fb8 TW |
114 | * @length: data length to read |
115 | * @offset: data read offset | |
116 | * | |
117 | * Locking: called under "dev->device_lock" lock | |
118 | * | |
a8605ea2 | 119 | * Return: |
19838fb8 TW |
120 | * returned data length on success, |
121 | * zero if no data to read, | |
122 | * negative on failure. | |
123 | */ | |
124 | int mei_amthif_read(struct mei_device *dev, struct file *file, | |
125 | char __user *ubuf, size_t length, loff_t *offset) | |
126 | { | |
19838fb8 | 127 | struct mei_cl *cl = file->private_data; |
d320832f | 128 | struct mei_cl_cb *cb; |
19838fb8 | 129 | unsigned long timeout; |
d320832f TW |
130 | int rets; |
131 | int wait_ret; | |
19838fb8 | 132 | |
83ce0741 | 133 | /* Only possible if we are in timeout */ |
05e314e2 | 134 | if (!cl) { |
2bf94cab | 135 | dev_err(dev->dev, "bad file ext.\n"); |
7ca96aa2 | 136 | return -ETIME; |
19838fb8 TW |
137 | } |
138 | ||
2bf94cab | 139 | dev_dbg(dev->dev, "checking amthif data\n"); |
19838fb8 TW |
140 | cb = mei_amthif_find_read_list_entry(dev, file); |
141 | ||
142 | /* Check for if we can block or not*/ | |
143 | if (cb == NULL && file->f_flags & O_NONBLOCK) | |
144 | return -EAGAIN; | |
145 | ||
146 | ||
2bf94cab | 147 | dev_dbg(dev->dev, "waiting for amthif data\n"); |
19838fb8 TW |
148 | while (cb == NULL) { |
149 | /* unlock the Mutex */ | |
150 | mutex_unlock(&dev->device_lock); | |
151 | ||
152 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, | |
153 | (cb = mei_amthif_find_read_list_entry(dev, file))); | |
154 | ||
e6028db0 AK |
155 | /* Locking again the Mutex */ |
156 | mutex_lock(&dev->device_lock); | |
157 | ||
19838fb8 TW |
158 | if (wait_ret) |
159 | return -ERESTARTSYS; | |
160 | ||
2bf94cab | 161 | dev_dbg(dev->dev, "woke up from sleep\n"); |
19838fb8 TW |
162 | } |
163 | ||
db4756fd TW |
164 | if (cb->status) { |
165 | rets = cb->status; | |
166 | dev_dbg(dev->dev, "read operation failed %d\n", rets); | |
167 | goto free; | |
168 | } | |
19838fb8 | 169 | |
2bf94cab | 170 | dev_dbg(dev->dev, "Got amthif data\n"); |
19838fb8 TW |
171 | dev->iamthif_timer = 0; |
172 | ||
db4756fd TW |
173 | timeout = cb->read_time + |
174 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); | |
175 | dev_dbg(dev->dev, "amthif timeout = %lud\n", | |
176 | timeout); | |
177 | ||
178 | if (time_after(jiffies, timeout)) { | |
179 | dev_dbg(dev->dev, "amthif Time out\n"); | |
180 | /* 15 sec for the message has expired */ | |
928fa666 | 181 | list_del_init(&cb->list); |
db4756fd TW |
182 | rets = -ETIME; |
183 | goto free; | |
19838fb8 TW |
184 | } |
185 | /* if the whole message will fit remove it from the list */ | |
186 | if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) | |
928fa666 | 187 | list_del_init(&cb->list); |
19838fb8 TW |
188 | else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { |
189 | /* end of the message has been reached */ | |
928fa666 | 190 | list_del_init(&cb->list); |
19838fb8 TW |
191 | rets = 0; |
192 | goto free; | |
193 | } | |
194 | /* else means that not full buffer will be read and do not | |
195 | * remove message from deletion list | |
196 | */ | |
197 | ||
5db7514d TW |
198 | dev_dbg(dev->dev, "amthif cb->buf size - %d\n", |
199 | cb->buf.size); | |
2bf94cab | 200 | dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); |
19838fb8 | 201 | |
83ce0741 | 202 | /* length is being truncated to PAGE_SIZE, however, |
19838fb8 TW |
203 | * the buf_idx may point beyond */ |
204 | length = min_t(size_t, length, (cb->buf_idx - *offset)); | |
205 | ||
5db7514d | 206 | if (copy_to_user(ubuf, cb->buf.data + *offset, length)) { |
2bf94cab | 207 | dev_dbg(dev->dev, "failed to copy data to userland\n"); |
19838fb8 | 208 | rets = -EFAULT; |
34e267d0 | 209 | } else { |
19838fb8 TW |
210 | rets = length; |
211 | if ((*offset + length) < cb->buf_idx) { | |
212 | *offset += length; | |
213 | goto out; | |
214 | } | |
215 | } | |
216 | free: | |
2bf94cab | 217 | dev_dbg(dev->dev, "free amthif cb memory.\n"); |
19838fb8 TW |
218 | *offset = 0; |
219 | mei_io_cb_free(cb); | |
220 | out: | |
221 | return rets; | |
222 | } | |
223 | ||
224 | /** | |
c54bf3ab | 225 | * mei_amthif_read_start - queue message for sending read credential |
19838fb8 | 226 | * |
c54bf3ab TW |
227 | * @cl: host client |
228 | * @file: file pointer of message recipient | |
19838fb8 | 229 | * |
a8605ea2 | 230 | * Return: 0 on success, <0 on failure. |
19838fb8 | 231 | */ |
c54bf3ab | 232 | static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) |
19838fb8 | 233 | { |
c54bf3ab TW |
234 | struct mei_device *dev = cl->dev; |
235 | struct mei_cl_cb *cb; | |
c54bf3ab | 236 | int rets; |
19838fb8 | 237 | |
bca67d68 | 238 | cb = mei_io_cb_init(cl, MEI_FOP_READ, file); |
c54bf3ab TW |
239 | if (!cb) { |
240 | rets = -ENOMEM; | |
241 | goto err; | |
242 | } | |
19838fb8 | 243 | |
9e239362 | 244 | rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl)); |
c54bf3ab TW |
245 | if (rets) |
246 | goto err; | |
19838fb8 | 247 | |
c54bf3ab | 248 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
19838fb8 | 249 | |
c54bf3ab TW |
250 | dev->iamthif_state = MEI_IAMTHIF_READING; |
251 | dev->iamthif_file_object = cb->file_object; | |
252 | dev->iamthif_current_cb = cb; | |
19838fb8 | 253 | |
19838fb8 | 254 | return 0; |
c54bf3ab TW |
255 | err: |
256 | mei_io_cb_free(cb); | |
257 | return rets; | |
19838fb8 TW |
258 | } |
259 | ||
ab5c4a56 | 260 | /** |
ab5c4a56 | 261 | * mei_amthif_send_cmd - send amthif command to the ME |
ab5c4a56 | 262 | * |
8660172e | 263 | * @cl: the host client |
ab5c4a56 TW |
264 | * @cb: mei call back struct |
265 | * | |
a8605ea2 | 266 | * Return: 0 on success, <0 on failure. |
ab5c4a56 | 267 | */ |
8660172e | 268 | static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb) |
ab5c4a56 | 269 | { |
8660172e | 270 | struct mei_device *dev; |
ab5c4a56 TW |
271 | int ret; |
272 | ||
8660172e | 273 | if (!cl->dev || !cb) |
ab5c4a56 TW |
274 | return -ENODEV; |
275 | ||
8660172e | 276 | dev = cl->dev; |
19838fb8 TW |
277 | |
278 | dev->iamthif_state = MEI_IAMTHIF_WRITING; | |
279 | dev->iamthif_current_cb = cb; | |
280 | dev->iamthif_file_object = cb->file_object; | |
281 | dev->iamthif_canceled = false; | |
19838fb8 | 282 | |
8660172e | 283 | ret = mei_cl_write(cl, cb, false); |
19838fb8 | 284 | if (ret < 0) |
ab5c4a56 TW |
285 | return ret; |
286 | ||
8660172e TW |
287 | if (cb->completed) |
288 | cb->status = mei_amthif_read_start(cl, cb->file_object); | |
ab5c4a56 | 289 | |
19838fb8 | 290 | return 0; |
ab5c4a56 | 291 | } |
19838fb8 TW |
292 | |
293 | /** | |
ce23139c | 294 | * mei_amthif_run_next_cmd - send next amt command from queue |
19838fb8 TW |
295 | * |
296 | * @dev: the device structure | |
ab5c4a56 | 297 | * |
a8605ea2 | 298 | * Return: 0 on success, <0 on failure. |
19838fb8 | 299 | */ |
8660172e | 300 | int mei_amthif_run_next_cmd(struct mei_device *dev) |
19838fb8 | 301 | { |
8660172e | 302 | struct mei_cl *cl = &dev->iamthif_cl; |
05e314e2 | 303 | struct mei_cl_cb *cb; |
19838fb8 | 304 | |
19838fb8 | 305 | dev->iamthif_canceled = false; |
19838fb8 TW |
306 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
307 | dev->iamthif_timer = 0; | |
308 | dev->iamthif_file_object = NULL; | |
309 | ||
2bf94cab | 310 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); |
19838fb8 | 311 | |
140c7553 AU |
312 | cb = list_first_entry_or_null(&dev->amthif_cmd_list.list, |
313 | typeof(*cb), list); | |
314 | if (!cb) | |
8660172e TW |
315 | return 0; |
316 | ||
c54bf3ab | 317 | list_del_init(&cb->list); |
8660172e | 318 | return mei_amthif_send_cmd(cl, cb); |
19838fb8 TW |
319 | } |
320 | ||
8660172e TW |
321 | /** |
322 | * mei_amthif_write - write amthif data to amthif client | |
323 | * | |
324 | * @cl: host client | |
325 | * @cb: mei call back struct | |
326 | * | |
327 | * Return: 0 on success, <0 on failure. | |
328 | */ | |
329 | int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |
330 | { | |
331 | ||
332 | struct mei_device *dev; | |
333 | ||
334 | if (WARN_ON(!cl || !cl->dev)) | |
335 | return -ENODEV; | |
336 | ||
337 | if (WARN_ON(!cb)) | |
338 | return -EINVAL; | |
339 | ||
340 | dev = cl->dev; | |
341 | ||
8660172e TW |
342 | list_add_tail(&cb->list, &dev->amthif_cmd_list.list); |
343 | return mei_amthif_run_next_cmd(dev); | |
344 | } | |
744f0f2f | 345 | |
1d9013f0 TW |
346 | /** |
347 | * mei_amthif_poll - the amthif poll function | |
348 | * | |
349 | * @dev: the device structure | |
350 | * @file: pointer to file structure | |
351 | * @wait: pointer to poll_table structure | |
352 | * | |
353 | * Return: poll mask | |
354 | * | |
355 | * Locking: called under "dev->device_lock" lock | |
356 | */ | |
744f0f2f TW |
357 | |
358 | unsigned int mei_amthif_poll(struct mei_device *dev, | |
359 | struct file *file, poll_table *wait) | |
360 | { | |
361 | unsigned int mask = 0; | |
b950ac1d | 362 | |
744f0f2f | 363 | poll_wait(file, &dev->iamthif_cl.wait, wait); |
b950ac1d | 364 | |
1d9013f0 TW |
365 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && |
366 | dev->iamthif_file_object == file) { | |
b950ac1d | 367 | |
1d9013f0 | 368 | mask |= POLLIN | POLLRDNORM; |
744f0f2f TW |
369 | mei_amthif_run_next_cmd(dev); |
370 | } | |
b950ac1d | 371 | |
744f0f2f TW |
372 | return mask; |
373 | } | |
374 | ||
375 | ||
376 | ||
19838fb8 | 377 | /** |
9d098192 | 378 | * mei_amthif_irq_write - write iamthif command in irq thread context. |
19838fb8 | 379 | * |
19838fb8 | 380 | * @cl: private data of the file object. |
a8605ea2 | 381 | * @cb: callback block. |
19838fb8 TW |
382 | * @cmpl_list: complete list. |
383 | * | |
a8605ea2 | 384 | * Return: 0, OK; otherwise, error. |
19838fb8 | 385 | */ |
9d098192 TW |
386 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
387 | struct mei_cl_cb *cmpl_list) | |
19838fb8 | 388 | { |
8660172e | 389 | int ret; |
24c656e5 | 390 | |
8660172e TW |
391 | ret = mei_cl_irq_write(cl, cb, cmpl_list); |
392 | if (ret) | |
393 | return ret; | |
19838fb8 | 394 | |
8660172e | 395 | if (cb->completed) |
c54bf3ab | 396 | cb->status = mei_amthif_read_start(cl, cb->file_object); |
24c656e5 | 397 | |
19838fb8 TW |
398 | return 0; |
399 | } | |
400 | ||
401 | /** | |
ce23139c | 402 | * mei_amthif_irq_read_msg - read routine after ISR to |
1a1aca42 | 403 | * handle the read amthif message |
19838fb8 | 404 | * |
db4756fd | 405 | * @cl: mei client |
1a1aca42 | 406 | * @mei_hdr: header of amthif message |
331e4187 | 407 | * @cmpl_list: completed callbacks list |
19838fb8 | 408 | * |
331e4187 | 409 | * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status |
19838fb8 | 410 | */ |
db4756fd | 411 | int mei_amthif_irq_read_msg(struct mei_cl *cl, |
5ceb46e2 | 412 | struct mei_msg_hdr *mei_hdr, |
331e4187 | 413 | struct mei_cl_cb *cmpl_list) |
19838fb8 | 414 | { |
db4756fd | 415 | struct mei_device *dev; |
331e4187 | 416 | int ret; |
19838fb8 | 417 | |
db4756fd | 418 | dev = cl->dev; |
19838fb8 | 419 | |
db4756fd | 420 | if (dev->iamthif_state != MEI_IAMTHIF_READING) |
331e4187 | 421 | return 0; |
19838fb8 | 422 | |
331e4187 TW |
423 | ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); |
424 | if (ret) | |
425 | return ret; | |
19838fb8 TW |
426 | |
427 | if (!mei_hdr->msg_complete) | |
428 | return 0; | |
429 | ||
2bf94cab | 430 | dev_dbg(dev->dev, "completed amthif read.\n "); |
19838fb8 | 431 | dev->iamthif_current_cb = NULL; |
19838fb8 | 432 | dev->iamthif_stall_timer = 0; |
19838fb8 | 433 | |
19838fb8 TW |
434 | return 0; |
435 | } | |
436 | ||
437 | /** | |
438 | * mei_amthif_complete - complete amthif callback. | |
439 | * | |
440 | * @dev: the device structure. | |
a8605ea2 | 441 | * @cb: callback block. |
19838fb8 TW |
442 | */ |
443 | void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) | |
444 | { | |
c54bf3ab TW |
445 | |
446 | if (cb->fop_type == MEI_FOP_WRITE) { | |
447 | if (!cb->status) { | |
448 | dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; | |
449 | mei_io_cb_free(cb); | |
450 | return; | |
451 | } | |
452 | /* | |
453 | * in case of error enqueue the write cb to complete read list | |
454 | * so it can be propagated to the reader | |
455 | */ | |
456 | list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); | |
457 | wake_up_interruptible(&dev->iamthif_cl.wait); | |
458 | return; | |
459 | } | |
460 | ||
19838fb8 TW |
461 | if (dev->iamthif_canceled != 1) { |
462 | dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; | |
463 | dev->iamthif_stall_timer = 0; | |
e773efc4 | 464 | list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); |
2bf94cab | 465 | dev_dbg(dev->dev, "amthif read completed\n"); |
19838fb8 | 466 | dev->iamthif_timer = jiffies; |
2bf94cab | 467 | dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n", |
c54bf3ab | 468 | dev->iamthif_timer); |
19838fb8 TW |
469 | } else { |
470 | mei_amthif_run_next_cmd(dev); | |
471 | } | |
472 | ||
2bf94cab | 473 | dev_dbg(dev->dev, "completing amthif call back.\n"); |
19838fb8 TW |
474 | wake_up_interruptible(&dev->iamthif_cl.wait); |
475 | } | |
476 | ||
a562d5c2 TW |
477 | /** |
478 | * mei_clear_list - removes all callbacks associated with file | |
479 | * from mei_cb_list | |
480 | * | |
481 | * @dev: device structure. | |
482 | * @file: file structure | |
483 | * @mei_cb_list: callbacks list | |
484 | * | |
485 | * mei_clear_list is called to clear resources associated with file | |
486 | * when application calls close function or Ctrl-C was pressed | |
487 | * | |
a8605ea2 | 488 | * Return: true if callback removed from the list, false otherwise |
a562d5c2 TW |
489 | */ |
490 | static bool mei_clear_list(struct mei_device *dev, | |
491 | const struct file *file, struct list_head *mei_cb_list) | |
492 | { | |
928fa666 TW |
493 | struct mei_cl *cl = &dev->iamthif_cl; |
494 | struct mei_cl_cb *cb, *next; | |
a562d5c2 TW |
495 | bool removed = false; |
496 | ||
497 | /* list all list member */ | |
928fa666 | 498 | list_for_each_entry_safe(cb, next, mei_cb_list, list) { |
a562d5c2 | 499 | /* check if list member associated with a file */ |
928fa666 | 500 | if (file == cb->file_object) { |
a562d5c2 | 501 | /* check if cb equal to current iamthif cb */ |
928fa666 | 502 | if (dev->iamthif_current_cb == cb) { |
a562d5c2 TW |
503 | dev->iamthif_current_cb = NULL; |
504 | /* send flow control to iamthif client */ | |
928fa666 | 505 | mei_hbm_cl_flow_control_req(dev, cl); |
a562d5c2 TW |
506 | } |
507 | /* free all allocated buffers */ | |
928fa666 | 508 | mei_io_cb_free(cb); |
a562d5c2 TW |
509 | removed = true; |
510 | } | |
511 | } | |
512 | return removed; | |
513 | } | |
514 | ||
515 | /** | |
516 | * mei_clear_lists - removes all callbacks associated with file | |
517 | * | |
518 | * @dev: device structure | |
519 | * @file: file structure | |
520 | * | |
521 | * mei_clear_lists is called to clear resources associated with file | |
522 | * when application calls close function or Ctrl-C was pressed | |
523 | * | |
a8605ea2 | 524 | * Return: true if callback removed from the list, false otherwise |
a562d5c2 TW |
525 | */ |
526 | static bool mei_clear_lists(struct mei_device *dev, struct file *file) | |
527 | { | |
528 | bool removed = false; | |
529 | ||
530 | /* remove callbacks associated with a file */ | |
531 | mei_clear_list(dev, file, &dev->amthif_cmd_list.list); | |
532 | if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) | |
533 | removed = true; | |
19838fb8 | 534 | |
a562d5c2 TW |
535 | mei_clear_list(dev, file, &dev->ctrl_rd_list.list); |
536 | ||
537 | if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) | |
538 | removed = true; | |
539 | ||
540 | if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) | |
541 | removed = true; | |
542 | ||
543 | if (mei_clear_list(dev, file, &dev->write_list.list)) | |
544 | removed = true; | |
545 | ||
546 | /* check if iamthif_current_cb not NULL */ | |
547 | if (dev->iamthif_current_cb && !removed) { | |
548 | /* check file and iamthif current cb association */ | |
549 | if (dev->iamthif_current_cb->file_object == file) { | |
550 | /* remove cb */ | |
551 | mei_io_cb_free(dev->iamthif_current_cb); | |
552 | dev->iamthif_current_cb = NULL; | |
553 | removed = true; | |
554 | } | |
555 | } | |
556 | return removed; | |
557 | } | |
558 | ||
559 | /** | |
560 | * mei_amthif_release - the release function | |
561 | * | |
393b148f | 562 | * @dev: device structure |
a562d5c2 TW |
563 | * @file: pointer to file structure |
564 | * | |
a8605ea2 | 565 | * Return: 0 on success, <0 on error |
a562d5c2 TW |
566 | */ |
567 | int mei_amthif_release(struct mei_device *dev, struct file *file) | |
568 | { | |
22f96a0e TW |
569 | if (dev->iamthif_open_count > 0) |
570 | dev->iamthif_open_count--; | |
a562d5c2 TW |
571 | |
572 | if (dev->iamthif_file_object == file && | |
573 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | |
574 | ||
2bf94cab | 575 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", |
a562d5c2 TW |
576 | dev->iamthif_state); |
577 | dev->iamthif_canceled = true; | |
578 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { | |
2bf94cab | 579 | dev_dbg(dev->dev, "run next amthif iamthif cb\n"); |
a562d5c2 TW |
580 | mei_amthif_run_next_cmd(dev); |
581 | } | |
582 | } | |
583 | ||
584 | if (mei_clear_lists(dev, file)) | |
585 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | |
586 | ||
587 | return 0; | |
588 | } |