OMAP2/3: Add omap_type() for determining GP/EMU/HS
[linux-ginger.git] / drivers / staging / heci / io_heci.c
blobf7544a7bbbe0998b37acf2695e280a8bc21cdedd
1 /*
2 * Part of Intel(R) Manageability Engine Interface Linux driver
4 * Copyright (c) 2003 - 2008 Intel Corp.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14 * substantially similar to the "NO WARRANTY" disclaimer below
15 * ("Disclaimer") and any redistribution must be conditioned upon
16 * including a substantially similar Disclaimer requirement for further
17 * binary redistribution.
18 * 3. Neither the names of the above-listed copyright holders nor the names
19 * of any contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
26 * NO WARRANTY
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGES.
41 #include <linux/module.h>
42 #include <linux/moduleparam.h>
43 #include <linux/kernel.h>
44 #include <linux/slab.h>
45 #include <linux/fs.h>
46 #include <linux/errno.h>
47 #include <linux/types.h>
48 #include <linux/fcntl.h>
49 #include <linux/aio.h>
50 #include <linux/pci.h>
51 #include <linux/reboot.h>
52 #include <linux/poll.h>
53 #include <linux/init.h>
54 #include <linux/kdev_t.h>
55 #include <linux/ioctl.h>
56 #include <linux/cdev.h>
57 #include <linux/list.h>
58 #include <linux/unistd.h>
59 #include <linux/delay.h>
61 #include "heci_data_structures.h"
62 #include "heci.h"
63 #include "heci_interface.h"
64 #include "heci_version.h"
67 /**
68 * heci_ioctl_get_version - the get driver version IOCTL function
70 * @dev: Device object for our driver
71 * @if_num: minor number
72 * @*u_msg: pointer to user data struct in user space
73 * @k_msg: data in kernel on the stack
74 * @file_ext: private data of the file object
76 * returns 0 on success, <0 on failure.
78 int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num,
79 struct heci_message_data __user *u_msg,
80 struct heci_message_data k_msg,
81 struct heci_file_private *file_ext)
83 int rets = 0;
84 struct heci_driver_version *version;
85 struct heci_message_data res_msg;
87 if ((if_num != HECI_MINOR_NUMBER) || (!dev)
88 || (!file_ext))
89 return -ENODEV;
91 if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) {
92 DBG("user buffer less than heci_driver_version.\n");
93 return -EMSGSIZE;
96 res_msg.data = kmalloc(sizeof(struct heci_driver_version), GFP_KERNEL);
97 if (!res_msg.data) {
98 DBG("failed allocation response buffer size = %d.\n",
99 (int) sizeof(struct heci_driver_version));
100 return -ENOMEM;
103 version = (struct heci_driver_version *) res_msg.data;
104 version->major = MAJOR_VERSION;
105 version->minor = MINOR_VERSION;
106 version->hotfix = QUICK_FIX_NUMBER;
107 version->build = VER_BUILD;
108 res_msg.size = sizeof(struct heci_driver_version);
109 if (k_msg.size < sizeof(struct heci_driver_version))
110 res_msg.size -= 2;
112 rets = file_ext->status;
113 /* now copy the data to user space */
114 if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) {
115 rets = -EFAULT;
116 goto end;
118 if (put_user(res_msg.size, &u_msg->size)) {
119 rets = -EFAULT;
120 goto end;
122 end:
123 kfree(res_msg.data);
124 return rets;
128 * heci_ioctl_connect_client - the connect to fw client IOCTL function
130 * @dev: Device object for our driver
131 * @if_num: minor number
132 * @*u_msg: pointer to user data struct in user space
133 * @k_msg: data in kernel on the stack
134 * @file_ext: private data of the file object
136 * returns 0 on success, <0 on failure.
138 int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num,
139 struct heci_message_data __user *u_msg,
140 struct heci_message_data k_msg,
141 struct file *file)
143 int rets = 0;
144 struct heci_message_data req_msg, res_msg;
145 struct heci_cb_private *priv_cb = NULL;
146 struct heci_client *client;
147 struct heci_file_private *file_ext;
148 struct heci_file_private *file_pos = NULL;
149 struct heci_file_private *file_next = NULL;
150 long timeout = 15; /*15 second */
151 __u8 i;
152 int err = 0;
154 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file))
155 return -ENODEV;
157 file_ext = file->private_data;
158 if (!file_ext)
159 return -ENODEV;
161 if (k_msg.size != sizeof(struct guid)) {
162 DBG("user buffer size is not equal to size of struct "
163 "guid(16).\n");
164 return -EMSGSIZE;
167 if (!k_msg.data)
168 return -EIO;
170 req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL);
171 res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL);
173 if (!res_msg.data) {
174 DBG("failed allocation response buffer size = %d.\n",
175 (int) sizeof(struct heci_client));
176 kfree(req_msg.data);
177 return -ENOMEM;
179 if (!req_msg.data) {
180 DBG("failed allocation request buffer size = %d.\n",
181 (int) sizeof(struct guid));
182 kfree(res_msg.data);
183 return -ENOMEM;
185 req_msg.size = sizeof(struct guid);
186 res_msg.size = sizeof(struct heci_client);
188 /* copy the message to kernel space -
189 * use a pointer already copied into kernel space
191 if (copy_from_user(req_msg.data, k_msg.data, k_msg.size)) {
192 rets = -EFAULT;
193 goto end;
195 /* buffered ioctl cb */
196 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
197 if (!priv_cb) {
198 rets = -ENOMEM;
199 goto end;
201 INIT_LIST_HEAD(&priv_cb->cb_list);
202 priv_cb->response_buffer.data = res_msg.data;
203 priv_cb->response_buffer.size = res_msg.size;
204 priv_cb->request_buffer.data = req_msg.data;
205 priv_cb->request_buffer.size = req_msg.size;
206 priv_cb->major_file_operations = HECI_IOCTL;
207 spin_lock_bh(&dev->device_lock);
208 if (dev->heci_state != HECI_ENABLED) {
209 rets = -ENODEV;
210 spin_unlock_bh(&dev->device_lock);
211 goto end;
213 if ((file_ext->state != HECI_FILE_INITIALIZING) &&
214 (file_ext->state != HECI_FILE_DISCONNECTED)) {
215 rets = -EBUSY;
216 spin_unlock_bh(&dev->device_lock);
217 goto end;
220 /* find ME client we're trying to connect to */
221 for (i = 0; i < dev->num_heci_me_clients; i++) {
222 if (memcmp((struct guid *)req_msg.data,
223 &dev->me_clients[i].props.protocol_name,
224 sizeof(struct guid)) == 0) {
225 if (dev->me_clients[i].props.fixed_address == 0) {
226 file_ext->me_client_id =
227 dev->me_clients[i].client_id;
228 file_ext->state = HECI_FILE_CONNECTING;
230 break;
233 /* if we're connecting to PTHI client so we will use the exist
234 * connection
236 if (memcmp((struct guid *)req_msg.data, &heci_pthi_guid,
237 sizeof(struct guid)) == 0) {
238 if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) {
239 rets = -ENODEV;
240 spin_unlock_bh(&dev->device_lock);
241 goto end;
243 dev->heci_host_clients[file_ext->host_client_id / 8] &=
244 ~(1 << (file_ext->host_client_id % 8));
245 list_for_each_entry_safe(file_pos,
246 file_next, &dev->file_list, link) {
247 if (heci_fe_same_id(file_ext, file_pos)) {
248 DBG("remove file private data node host"
249 " client = %d, ME client = %d.\n",
250 file_pos->host_client_id,
251 file_pos->me_client_id);
252 list_del(&file_pos->link);
256 DBG("free file private data memory.\n");
257 kfree(file_ext);
258 file_ext = NULL;
259 file->private_data = &dev->iamthif_file_ext;
260 client = (struct heci_client *) res_msg.data;
261 client->max_msg_length =
262 dev->me_clients[i].props.max_msg_length;
263 client->protocol_version =
264 dev->me_clients[i].props.protocol_version;
265 rets = dev->iamthif_file_ext.status;
266 spin_unlock_bh(&dev->device_lock);
268 /* now copy the data to user space */
269 if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) {
270 rets = -EFAULT;
271 goto end;
273 if (put_user(res_msg.size, &u_msg->size)) {
274 rets = -EFAULT;
275 goto end;
277 goto end;
279 spin_lock(&file_ext->file_lock);
280 if (file_ext->state != HECI_FILE_CONNECTING) {
281 rets = -ENODEV;
282 spin_unlock(&file_ext->file_lock);
283 spin_unlock_bh(&dev->device_lock);
284 goto end;
286 spin_unlock(&file_ext->file_lock);
287 /* prepare the output buffer */
288 client = (struct heci_client *) res_msg.data;
289 client->max_msg_length = dev->me_clients[i].props.max_msg_length;
290 client->protocol_version = dev->me_clients[i].props.protocol_version;
291 if (dev->host_buffer_is_empty
292 && !other_client_is_connecting(dev, file_ext)) {
293 dev->host_buffer_is_empty = 0;
294 if (!heci_connect(dev, file_ext)) {
295 rets = -ENODEV;
296 spin_unlock_bh(&dev->device_lock);
297 goto end;
298 } else {
299 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
300 priv_cb->file_private = file_ext;
301 list_add_tail(&priv_cb->cb_list,
302 &dev->ctrl_rd_list.heci_cb.
303 cb_list);
307 } else {
308 priv_cb->file_private = file_ext;
309 DBG("add connect cb to control write list.\n");
310 list_add_tail(&priv_cb->cb_list,
311 &dev->ctrl_wr_list.heci_cb.cb_list);
313 spin_unlock_bh(&dev->device_lock);
314 err = wait_event_timeout(dev->wait_recvd_msg,
315 (HECI_FILE_CONNECTED == file_ext->state
316 || HECI_FILE_DISCONNECTED == file_ext->state),
317 timeout * HZ);
319 if (HECI_FILE_CONNECTED == file_ext->state) {
320 DBG("successfully connected to FW client.\n");
321 rets = file_ext->status;
322 /* now copy the data to user space */
323 if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) {
324 rets = -EFAULT;
325 goto end;
327 if (put_user(res_msg.size, &u_msg->size)) {
328 rets = -EFAULT;
329 goto end;
331 goto end;
332 } else {
333 DBG("failed to connect to FW client.file_ext->state = %d.\n",
334 file_ext->state);
335 if (!err) {
336 DBG("wait_event_interruptible_timeout failed on client"
337 " connect message fw response message.\n");
339 rets = -EFAULT;
340 goto remove_list;
343 remove_list:
344 if (priv_cb) {
345 spin_lock_bh(&dev->device_lock);
346 heci_flush_list(&dev->ctrl_rd_list, file_ext);
347 heci_flush_list(&dev->ctrl_wr_list, file_ext);
348 spin_unlock_bh(&dev->device_lock);
350 end:
351 DBG("free connect cb memory.");
352 kfree(req_msg.data);
353 kfree(res_msg.data);
354 kfree(priv_cb);
355 return rets;
359 * heci_ioctl_wd - the wd IOCTL function
361 * @dev: Device object for our driver
362 * @if_num: minor number
363 * @k_msg: data in kernel on the stack
364 * @file_ext: private data of the file object
366 * returns 0 on success, <0 on failure.
368 int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num,
369 struct heci_message_data k_msg,
370 struct heci_file_private *file_ext)
372 int rets = 0;
373 struct heci_message_data req_msg; /*in kernel on the stack */
375 if (if_num != HECI_MINOR_NUMBER)
376 return -ENODEV;
378 spin_lock(&file_ext->file_lock);
379 if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) {
380 DBG("user buffer has invalid size.\n");
381 spin_unlock(&file_ext->file_lock);
382 return -EMSGSIZE;
384 spin_unlock(&file_ext->file_lock);
386 req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL);
387 if (!req_msg.data) {
388 DBG("failed allocation request buffer size = %d.\n",
389 HECI_WATCHDOG_DATA_SIZE);
390 return -ENOMEM;
392 req_msg.size = HECI_WATCHDOG_DATA_SIZE;
394 /* copy the message to kernel space - use a pointer already
395 * copied into kernel space
397 if (copy_from_user(req_msg.data, k_msg.data, req_msg.size)) {
398 rets = -EFAULT;
399 goto end;
401 spin_lock_bh(&dev->device_lock);
402 if (dev->heci_state != HECI_ENABLED) {
403 rets = -ENODEV;
404 spin_unlock_bh(&dev->device_lock);
405 goto end;
408 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
409 rets = -ENODEV;
410 spin_unlock_bh(&dev->device_lock);
411 goto end;
413 if (!dev->asf_mode) {
414 rets = -EIO;
415 spin_unlock_bh(&dev->device_lock);
416 goto end;
419 memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data,
420 HECI_WATCHDOG_DATA_SIZE);
422 dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0];
423 dev->wd_pending = 0;
424 dev->wd_due_counter = 1; /* next timer */
425 if (dev->wd_timeout == 0) {
426 memcpy(dev->wd_data, heci_stop_wd_params,
427 HECI_WD_PARAMS_SIZE);
428 } else {
429 memcpy(dev->wd_data, heci_start_wd_params,
430 HECI_WD_PARAMS_SIZE);
431 mod_timer(&dev->wd_timer, jiffies);
433 spin_unlock_bh(&dev->device_lock);
434 end:
435 kfree(req_msg.data);
436 return rets;
441 * heci_ioctl_bypass_wd - the bypass_wd IOCTL function
443 * @dev: Device object for our driver
444 * @if_num: minor number
445 * @k_msg: data in kernel on the stack
446 * @file_ext: private data of the file object
448 * returns 0 on success, <0 on failure.
450 int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num,
451 struct heci_message_data k_msg,
452 struct heci_file_private *file_ext)
454 __u8 flag = 0;
455 int rets = 0;
457 if (if_num != HECI_MINOR_NUMBER)
458 return -ENODEV;
460 spin_lock(&file_ext->file_lock);
461 if (k_msg.size < 1) {
462 DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n");
463 spin_unlock(&file_ext->file_lock);
464 return -EMSGSIZE;
466 spin_unlock(&file_ext->file_lock);
467 if (copy_from_user(&flag, k_msg.data, 1)) {
468 rets = -EFAULT;
469 goto end;
472 spin_lock_bh(&dev->device_lock);
473 flag = flag ? (1) : (0);
474 dev->wd_bypass = flag;
475 spin_unlock_bh(&dev->device_lock);
476 end:
477 return rets;
481 * find_pthi_read_list_entry - finds a PTHIlist entry for current file
483 * @dev: Device object for our driver
484 * @file: pointer to file object
486 * returns returned a list entry on success, NULL on failure.
488 struct heci_cb_private *find_pthi_read_list_entry(
489 struct iamt_heci_device *dev,
490 struct file *file)
492 struct heci_file_private *file_ext_temp;
493 struct heci_cb_private *priv_cb_pos = NULL;
494 struct heci_cb_private *priv_cb_next = NULL;
496 if ((dev->pthi_read_complete_list.status == 0) &&
497 !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) {
498 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
499 &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list) {
500 file_ext_temp = (struct heci_file_private *)
501 priv_cb_pos->file_private;
502 if ((file_ext_temp != NULL) &&
503 (file_ext_temp == &dev->iamthif_file_ext) &&
504 (priv_cb_pos->file_object == file))
505 return priv_cb_pos;
508 return NULL;
512 * pthi_read - read data from pthi client
514 * @dev: Device object for our driver
515 * @if_num: minor number
516 * @file: pointer to file object
517 * @*ubuf: pointer to user data in user space
518 * @length: data length to read
519 * @offset: data read offset
521 * returns
522 * returned data length on success,
523 * zero if no data to read,
524 * negative on failure.
526 int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file,
527 char __user *ubuf, size_t length, loff_t *offset)
529 int rets = 0;
530 struct heci_cb_private *priv_cb = NULL;
531 struct heci_file_private *file_ext = file->private_data;
532 __u8 i;
533 unsigned long currtime = get_seconds();
535 if ((if_num != HECI_MINOR_NUMBER) || (!dev))
536 return -ENODEV;
538 if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext))
539 return -ENODEV;
541 spin_lock_bh(&dev->device_lock);
542 for (i = 0; i < dev->num_heci_me_clients; i++) {
543 if (dev->me_clients[i].client_id ==
544 dev->iamthif_file_ext.me_client_id)
545 break;
547 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
548 if ((i == dev->num_heci_me_clients)
549 || (dev->me_clients[i].client_id !=
550 dev->iamthif_file_ext.me_client_id)) {
551 DBG("PTHI client not found.\n");
552 spin_unlock_bh(&dev->device_lock);
553 return -ENODEV;
555 priv_cb = find_pthi_read_list_entry(dev, file);
556 if (!priv_cb) {
557 spin_unlock_bh(&dev->device_lock);
558 return 0; /* No more data to read */
559 } else {
560 if (priv_cb &&
561 (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) {
562 /* 15 sec for the message has expired */
563 list_del(&priv_cb->cb_list);
564 spin_unlock_bh(&dev->device_lock);
565 rets = -ETIMEDOUT;
566 goto free;
568 /* if the whole message will fit remove it from the list */
569 if ((priv_cb->information >= *offset) &&
570 (length >= (priv_cb->information - *offset)))
571 list_del(&priv_cb->cb_list);
572 else if ((priv_cb->information > 0) &&
573 (priv_cb->information <= *offset)) {
574 /* end of the message has been reached */
575 list_del(&priv_cb->cb_list);
576 rets = 0;
577 spin_unlock_bh(&dev->device_lock);
578 goto free;
580 /* else means that not full buffer will be read and do not
581 * remove message from deletion list
584 DBG("pthi priv_cb->response_buffer size - %d\n",
585 priv_cb->response_buffer.size);
586 DBG("pthi priv_cb->information - %lu\n",
587 priv_cb->information);
588 spin_unlock_bh(&dev->device_lock);
590 /* length is being turncated to PAGE_SIZE, however,
591 * the information may be longer */
592 length = length < (priv_cb->information - *offset) ?
593 length : (priv_cb->information - *offset);
595 if (copy_to_user(ubuf,
596 priv_cb->response_buffer.data + *offset,
597 length))
598 rets = -EFAULT;
599 else {
600 rets = length;
601 if ((*offset + length) < priv_cb->information) {
602 *offset += length;
603 goto out;
606 free:
607 DBG("free pthi cb memory.\n");
608 *offset = 0;
609 heci_free_cb_private(priv_cb);
610 out:
611 return rets;
615 * heci_start_read - the start read client message function.
617 * @dev: Device object for our driver
618 * @if_num: minor number
619 * @file_ext: private data of the file object
621 * returns 0 on success, <0 on failure.
623 int heci_start_read(struct iamt_heci_device *dev, int if_num,
624 struct heci_file_private *file_ext)
626 int rets = 0;
627 __u8 i;
628 struct heci_cb_private *priv_cb = NULL;
630 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) {
631 DBG("received wrong function input param.\n");
632 return -ENODEV;
634 if (file_ext->state != HECI_FILE_CONNECTED)
635 return -ENODEV;
637 spin_lock_bh(&dev->device_lock);
638 if (dev->heci_state != HECI_ENABLED) {
639 spin_unlock_bh(&dev->device_lock);
640 return -ENODEV;
642 spin_unlock_bh(&dev->device_lock);
643 DBG("check if read is pending.\n");
644 if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) {
645 DBG("read is pending.\n");
646 return -EBUSY;
648 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
649 if (!priv_cb)
650 return -ENOMEM;
652 DBG("allocation call back success\n"
653 "host client = %d, ME client = %d\n",
654 file_ext->host_client_id, file_ext->me_client_id);
655 spin_lock_bh(&dev->device_lock);
656 for (i = 0; i < dev->num_heci_me_clients; i++) {
657 if (dev->me_clients[i].client_id == file_ext->me_client_id)
658 break;
662 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
663 if (i == dev->num_heci_me_clients) {
664 rets = -ENODEV;
665 goto unlock;
668 priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
669 spin_unlock_bh(&dev->device_lock);
670 priv_cb->response_buffer.data =
671 kmalloc(priv_cb->response_buffer.size, GFP_KERNEL);
672 if (!priv_cb->response_buffer.data) {
673 rets = -ENOMEM;
674 goto fail;
676 DBG("allocation call back data success.\n");
677 priv_cb->major_file_operations = HECI_READ;
678 /* make sure information is zero before we start */
679 priv_cb->information = 0;
680 priv_cb->file_private = (void *) file_ext;
681 file_ext->read_cb = priv_cb;
682 spin_lock_bh(&dev->device_lock);
683 if (dev->host_buffer_is_empty) {
684 dev->host_buffer_is_empty = 0;
685 if (!heci_send_flow_control(dev, file_ext)) {
686 rets = -ENODEV;
687 goto unlock;
688 } else {
689 list_add_tail(&priv_cb->cb_list,
690 &dev->read_list.heci_cb.cb_list);
692 } else {
693 list_add_tail(&priv_cb->cb_list,
694 &dev->ctrl_wr_list.heci_cb.cb_list);
696 spin_unlock_bh(&dev->device_lock);
697 return rets;
698 unlock:
699 spin_unlock_bh(&dev->device_lock);
700 fail:
701 heci_free_cb_private(priv_cb);
702 return rets;
706 * pthi_write - write iamthif data to pthi client
708 * @dev: Device object for our driver
709 * @priv_cb: heci call back struct
711 * returns 0 on success, <0 on failure.
713 int pthi_write(struct iamt_heci_device *dev,
714 struct heci_cb_private *priv_cb)
716 int rets = 0;
717 struct heci_msg_hdr heci_hdr;
719 if ((!dev) || (!priv_cb))
720 return -ENODEV;
722 DBG("write data to pthi client.\n");
724 dev->iamthif_state = HECI_IAMTHIF_WRITING;
725 dev->iamthif_current_cb = priv_cb;
726 dev->iamthif_file_object = priv_cb->file_object;
727 dev->iamthif_canceled = 0;
728 dev->iamthif_ioctl = 1;
729 dev->iamthif_msg_buf_size = priv_cb->request_buffer.size;
730 memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data,
731 priv_cb->request_buffer.size);
733 if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) &&
734 dev->host_buffer_is_empty) {
735 dev->host_buffer_is_empty = 0;
736 if (priv_cb->request_buffer.size >
737 (((dev->host_hw_state & H_CBD) >> 24) *
738 sizeof(__u32)) - sizeof(struct heci_msg_hdr)) {
739 heci_hdr.length =
740 (((dev->host_hw_state & H_CBD) >> 24) *
741 sizeof(__u32)) - sizeof(struct heci_msg_hdr);
742 heci_hdr.msg_complete = 0;
743 } else {
744 heci_hdr.length = priv_cb->request_buffer.size;
745 heci_hdr.msg_complete = 1;
748 heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id;
749 heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id;
750 heci_hdr.reserved = 0;
751 dev->iamthif_msg_buf_index += heci_hdr.length;
752 if (!heci_write_message(dev, &heci_hdr,
753 (unsigned char *)(dev->iamthif_msg_buf),
754 heci_hdr.length))
755 return -ENODEV;
757 if (heci_hdr.msg_complete) {
758 flow_ctrl_reduce(dev, &dev->iamthif_file_ext);
759 dev->iamthif_flow_control_pending = 1;
760 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
761 DBG("add pthi cb to write waiting list\n");
762 dev->iamthif_current_cb = priv_cb;
763 dev->iamthif_file_object = priv_cb->file_object;
764 list_add_tail(&priv_cb->cb_list,
765 &dev->write_waiting_list.heci_cb.cb_list);
766 } else {
767 DBG("message does not complete, "
768 "so add pthi cb to write list.\n");
769 list_add_tail(&priv_cb->cb_list,
770 &dev->write_list.heci_cb.cb_list);
772 } else {
773 if (!(dev->host_buffer_is_empty))
774 DBG("host buffer is not empty");
776 DBG("No flow control credentials, "
777 "so add iamthif cb to write list.\n");
778 list_add_tail(&priv_cb->cb_list,
779 &dev->write_list.heci_cb.cb_list);
781 return rets;
785 * iamthif_ioctl_send_msg - send cmd data to pthi client
787 * @dev: Device object for our driver
789 * returns 0 on success, <0 on failure.
791 void run_next_iamthif_cmd(struct iamt_heci_device *dev)
793 struct heci_file_private *file_ext_tmp;
794 struct heci_cb_private *priv_cb_pos = NULL;
795 struct heci_cb_private *priv_cb_next = NULL;
796 int status = 0;
798 if (!dev)
799 return;
801 dev->iamthif_msg_buf_size = 0;
802 dev->iamthif_msg_buf_index = 0;
803 dev->iamthif_canceled = 0;
804 dev->iamthif_ioctl = 1;
805 dev->iamthif_state = HECI_IAMTHIF_IDLE;
806 dev->iamthif_timer = 0;
807 dev->iamthif_file_object = NULL;
809 if (dev->pthi_cmd_list.status == 0 &&
810 !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) {
811 DBG("complete pthi cmd_list cb.\n");
813 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
814 &dev->pthi_cmd_list.heci_cb.cb_list, cb_list) {
815 list_del(&priv_cb_pos->cb_list);
816 file_ext_tmp = (struct heci_file_private *)
817 priv_cb_pos->file_private;
819 if ((file_ext_tmp != NULL) &&
820 (file_ext_tmp == &dev->iamthif_file_ext)) {
821 status = pthi_write(dev, priv_cb_pos);
822 if (status != 0) {
823 DBG("pthi write failed status = %d\n",
824 status);
825 return;
827 break;
834 * heci_free_cb_private - free heci_cb_private related memory
836 * @priv_cb: heci callback struct
838 void heci_free_cb_private(struct heci_cb_private *priv_cb)
840 if (priv_cb == NULL)
841 return;
843 kfree(priv_cb->request_buffer.data);
844 kfree(priv_cb->response_buffer.data);
845 kfree(priv_cb);