ASoC: Remove duplicate ADC/DAC widgets from wm_hubs.c
[linux/fpc-iii.git] / drivers / staging / heci / interrupt.c
blob2a3a01a62bbf748d3fe43e6cb0718d8242c6add8
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/kthread.h>
43 #include "heci.h"
44 #include "heci_interface.h"
47 * interrupt function prototypes
49 static void heci_bh_handler(struct work_struct *work);
50 static int heci_bh_read_handler(struct io_heci_list *complete_list,
51 struct iamt_heci_device *dev,
52 __s32 *slots);
53 static int heci_bh_write_handler(struct io_heci_list *complete_list,
54 struct iamt_heci_device *dev,
55 __s32 *slots);
56 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
57 struct heci_msg_hdr *heci_hdr);
58 static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
59 struct iamt_heci_device *dev,
60 struct heci_msg_hdr *heci_hdr);
61 static int heci_bh_read_client_message(struct io_heci_list *complete_list,
62 struct iamt_heci_device *dev,
63 struct heci_msg_hdr *heci_hdr);
64 static void heci_client_connect_response(struct iamt_heci_device *dev,
65 struct hbm_client_connect_response *connect_res);
66 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
67 struct hbm_client_connect_response *disconnect_res);
68 static void heci_client_flow_control_response(struct iamt_heci_device *dev,
69 struct hbm_flow_control *flow_control);
70 static void heci_client_disconnect_request(struct iamt_heci_device *dev,
71 struct hbm_client_disconnect_request *disconnect_req);
74 /**
75 * heci_isr_interrupt - The ISR of the HECI device
77 * @irq: The irq number
78 * @dev_id: pointer to the device structure
80 * returns irqreturn_t
82 irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
84 int err;
85 struct iamt_heci_device *dev = (struct iamt_heci_device *) dev_id;
87 dev->host_hw_state = read_heci_register(dev, H_CSR);
89 if ((dev->host_hw_state & H_IS) != H_IS)
90 return IRQ_NONE;
92 /* disable interrupts */
93 heci_csr_disable_interrupts(dev);
95 /* clear H_IS bit in H_CSR */
96 heci_csr_clear_his(dev);
99 * Our device interrupted, schedule work the heci_bh_handler
100 * to handle the interrupt processing. This needs to be a
101 * workqueue item since the handler can sleep.
103 PREPARE_WORK(&dev->work, heci_bh_handler);
104 DBG("schedule work the heci_bh_handler.\n");
105 err = schedule_work(&dev->work);
106 if (!err)
107 DBG("heci_bh_handler was already on the workqueue.\n");
108 return IRQ_HANDLED;
112 * _heci_cmpl - process completed operation.
114 * @file_ext: private data of the file object.
115 * @priv_cb_pos: callback block.
117 static void _heci_cmpl(struct heci_file_private *file_ext,
118 struct heci_cb_private *priv_cb_pos)
120 if (priv_cb_pos->major_file_operations == HECI_WRITE) {
121 heci_free_cb_private(priv_cb_pos);
122 DBG("completing write call back.\n");
123 file_ext->writing_state = HECI_WRITE_COMPLETE;
124 if ((&file_ext->tx_wait) &&
125 waitqueue_active(&file_ext->tx_wait))
126 wake_up_interruptible(&file_ext->tx_wait);
128 } else if (priv_cb_pos->major_file_operations == HECI_READ
129 && HECI_READING == file_ext->reading_state) {
130 DBG("completing read call back information= %lu\n",
131 priv_cb_pos->information);
132 file_ext->reading_state = HECI_READ_COMPLETE;
133 if ((&file_ext->rx_wait) &&
134 waitqueue_active(&file_ext->rx_wait))
135 wake_up_interruptible(&file_ext->rx_wait);
141 * _heci_cmpl_iamthif - process completed iamthif operation.
143 * @dev: Device object for our driver.
144 * @priv_cb_pos: callback block.
146 static void _heci_cmpl_iamthif(struct iamt_heci_device *dev,
147 struct heci_cb_private *priv_cb_pos)
149 if (dev->iamthif_canceled != 1) {
150 dev->iamthif_state = HECI_IAMTHIF_READ_COMPLETE;
151 dev->iamthif_stall_timer = 0;
152 memcpy(priv_cb_pos->response_buffer.data,
153 dev->iamthif_msg_buf,
154 dev->iamthif_msg_buf_index);
155 list_add_tail(&priv_cb_pos->cb_list,
156 &dev->pthi_read_complete_list.heci_cb.cb_list);
157 DBG("pthi read completed.\n");
158 } else {
159 run_next_iamthif_cmd(dev);
161 if (&dev->iamthif_file_ext.wait) {
162 DBG("completing pthi call back.\n");
163 wake_up_interruptible(&dev->iamthif_file_ext.wait);
167 * heci_bh_handler - function called after ISR to handle the interrupt
168 * processing.
170 * @work: pointer to the work structure
172 * NOTE: This function is called by schedule work
174 static void heci_bh_handler(struct work_struct *work)
176 struct iamt_heci_device *dev =
177 container_of(work, struct iamt_heci_device, work);
178 struct io_heci_list complete_list;
179 __s32 slots;
180 int rets;
181 struct heci_cb_private *cb_pos = NULL, *cb_next = NULL;
182 struct heci_file_private *file_ext;
183 int bus_message_received = 0;
184 struct task_struct *tsk;
186 DBG("function called after ISR to handle the interrupt processing.\n");
187 /* initialize our complete list */
188 spin_lock_bh(&dev->device_lock);
189 heci_initialize_list(&complete_list, dev);
190 dev->host_hw_state = read_heci_register(dev, H_CSR);
191 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
193 /* check if ME wants a reset */
194 if (((dev->me_hw_state & ME_RDY_HRA) == 0)
195 && (dev->heci_state != HECI_RESETING)
196 && (dev->heci_state != HECI_INITIALIZING)) {
197 DBG("FW not ready.\n");
198 heci_reset(dev, 1);
199 spin_unlock_bh(&dev->device_lock);
200 return;
203 /* check if we need to start the dev */
204 if ((dev->host_hw_state & H_RDY) == 0) {
205 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
206 DBG("we need to start the dev.\n");
207 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
208 heci_set_csr_register(dev);
209 if (dev->heci_state == HECI_INITIALIZING) {
210 dev->recvd_msg = 1;
211 spin_unlock_bh(&dev->device_lock);
212 wake_up_interruptible(&dev->wait_recvd_msg);
213 return;
215 } else {
216 spin_unlock_bh(&dev->device_lock);
217 tsk = kthread_run(heci_task_initialize_clients,
218 dev, "heci_reinit");
219 if (IS_ERR(tsk)) {
220 int rc = PTR_ERR(tsk);
221 printk(KERN_WARNING "heci: Unable to"
222 "start the heci thread: %d\n", rc);
224 return;
226 } else {
227 DBG("enable interrupt FW not ready.\n");
228 heci_csr_enable_interrupts(dev);
229 spin_unlock_bh(&dev->device_lock);
230 return;
233 /* check slots avalable for reading */
234 slots = count_full_read_slots(dev);
235 DBG("slots =%08x extra_write_index =%08x.\n",
236 slots, dev->extra_write_index);
237 while ((slots > 0) && (!dev->extra_write_index)) {
238 DBG("slots =%08x extra_write_index =%08x.\n", slots,
239 dev->extra_write_index);
240 DBG("call heci_bh_read_handler.\n");
241 rets = heci_bh_read_handler(&complete_list, dev, &slots);
242 if (rets != 0)
243 goto end;
245 rets = heci_bh_write_handler(&complete_list, dev, &slots);
246 end:
247 DBG("end of bottom half function.\n");
248 dev->host_hw_state = read_heci_register(dev, H_CSR);
249 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
251 if ((dev->host_hw_state & H_IS) == H_IS) {
252 /* acknowledge interrupt and disable interrupts */
253 heci_csr_disable_interrupts(dev);
255 /* clear H_IS bit in H_CSR */
256 heci_csr_clear_his(dev);
258 PREPARE_WORK(&dev->work, heci_bh_handler);
259 DBG("schedule work the heci_bh_handler.\n");
260 rets = schedule_work(&dev->work);
261 if (!rets)
262 DBG("heci_bh_handler was already queued.\n");
263 } else {
264 heci_csr_enable_interrupts(dev);
267 if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
268 DBG("received waiting bus message\n");
269 bus_message_received = 1;
271 spin_unlock_bh(&dev->device_lock);
272 if (bus_message_received) {
273 DBG("wake up dev->wait_recvd_msg\n");
274 wake_up_interruptible(&dev->wait_recvd_msg);
275 bus_message_received = 0;
277 if ((complete_list.status != 0)
278 || list_empty(&complete_list.heci_cb.cb_list))
279 return;
282 list_for_each_entry_safe(cb_pos, cb_next,
283 &complete_list.heci_cb.cb_list, cb_list) {
284 file_ext = (struct heci_file_private *)cb_pos->file_private;
285 list_del(&cb_pos->cb_list);
286 if (file_ext != NULL) {
287 if (file_ext != &dev->iamthif_file_ext) {
288 DBG("completing call back.\n");
289 _heci_cmpl(file_ext, cb_pos);
290 cb_pos = NULL;
291 } else if (file_ext == &dev->iamthif_file_ext) {
292 _heci_cmpl_iamthif(dev, cb_pos);
300 * heci_bh_read_handler - bottom half read routine after ISR to
301 * handle the read processing.
303 * @cmpl_list: An instance of our list structure
304 * @dev: Device object for our driver
305 * @slots: slots to read.
307 * returns 0 on success, <0 on failure.
309 static int heci_bh_read_handler(struct io_heci_list *cmpl_list,
310 struct iamt_heci_device *dev,
311 __s32 *slots)
313 struct heci_msg_hdr *heci_hdr;
314 int ret = 0;
315 struct heci_file_private *file_pos = NULL;
316 struct heci_file_private *file_next = NULL;
318 if (!dev->rd_msg_hdr) {
319 dev->rd_msg_hdr = read_heci_register(dev, ME_CB_RW);
320 DBG("slots=%08x.\n", *slots);
321 (*slots)--;
322 DBG("slots=%08x.\n", *slots);
324 heci_hdr = (struct heci_msg_hdr *) &dev->rd_msg_hdr;
325 DBG("heci_hdr->length =%d\n", heci_hdr->length);
327 if ((heci_hdr->reserved) || !(dev->rd_msg_hdr)) {
328 DBG("corrupted message header.\n");
329 ret = -ECORRUPTED_MESSAGE_HEADER;
330 goto end;
333 if ((heci_hdr->host_addr) || (heci_hdr->me_addr)) {
334 list_for_each_entry_safe(file_pos, file_next,
335 &dev->file_list, link) {
336 DBG("list_for_each_entry_safe read host"
337 " client = %d, ME client = %d\n",
338 file_pos->host_client_id,
339 file_pos->me_client_id);
340 if ((file_pos->host_client_id == heci_hdr->host_addr)
341 && (file_pos->me_client_id == heci_hdr->me_addr))
342 break;
345 if (&file_pos->link == &dev->file_list) {
346 DBG("corrupted message header\n");
347 ret = -ECORRUPTED_MESSAGE_HEADER;
348 goto end;
351 if (((*slots) * sizeof(__u32)) < heci_hdr->length) {
352 DBG("we can't read the message slots=%08x.\n", *slots);
353 /* we can't read the message */
354 ret = -ERANGE;
355 goto end;
358 /* decide where to read the message too */
359 if (!heci_hdr->host_addr) {
360 DBG("call heci_bh_read_bus_message.\n");
361 heci_bh_read_bus_message(dev, heci_hdr);
362 DBG("end heci_bh_read_bus_message.\n");
363 } else if ((heci_hdr->host_addr == dev->iamthif_file_ext.host_client_id)
364 && (HECI_FILE_CONNECTED == dev->iamthif_file_ext.state)
365 && (dev->iamthif_state == HECI_IAMTHIF_READING)) {
366 DBG("call heci_bh_read_iamthif_message.\n");
367 DBG("heci_hdr->length =%d\n", heci_hdr->length);
368 ret = heci_bh_read_pthi_message(cmpl_list, dev, heci_hdr);
369 if (ret != 0)
370 goto end;
372 } else {
373 DBG("call heci_bh_read_client_message.\n");
374 ret = heci_bh_read_client_message(cmpl_list, dev, heci_hdr);
375 if (ret != 0)
376 goto end;
380 /* reset the number of slots and header */
381 *slots = count_full_read_slots(dev);
382 dev->rd_msg_hdr = 0;
384 if (*slots == -ESLOTS_OVERFLOW) {
385 /* overflow - reset */
386 DBG("reseting due to slots overflow.\n");
387 /* set the event since message has been read */
388 ret = -ERANGE;
389 goto end;
391 end:
392 return ret;
397 * heci_bh_read_bus_message - bottom half read routine after ISR to
398 * handle the read bus message cmd processing.
400 * @dev: Device object for our driver
401 * @heci_hdr: header of bus message
403 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
404 struct heci_msg_hdr *heci_hdr)
406 struct heci_bus_message *heci_msg;
407 struct hbm_host_version_response *version_res;
408 struct hbm_client_connect_response *connect_res;
409 struct hbm_client_connect_response *disconnect_res;
410 struct hbm_flow_control *flow_control;
411 struct hbm_props_response *props_res;
412 struct hbm_host_enum_response *enum_res;
413 struct hbm_client_disconnect_request *disconnect_req;
414 struct hbm_host_stop_request *h_stop_req;
415 int i;
416 unsigned char *buffer;
418 /* read the message to our buffer */
419 buffer = (unsigned char *) dev->rd_msg_buf;
420 BUG_ON(heci_hdr->length >= sizeof(dev->rd_msg_buf));
421 heci_read_slots(dev, buffer, heci_hdr->length);
422 heci_msg = (struct heci_bus_message *) buffer;
424 switch (*(__u8 *) heci_msg) {
425 case HOST_START_RES_CMD:
426 version_res = (struct hbm_host_version_response *) heci_msg;
427 if (version_res->host_version_supported) {
428 dev->version.major_version = HBM_MAJOR_VERSION;
429 dev->version.minor_version = HBM_MINOR_VERSION;
430 } else {
431 dev->version = version_res->me_max_version;
433 dev->recvd_msg = 1;
434 DBG("host start response message received.\n");
435 break;
437 case CLIENT_CONNECT_RES_CMD:
438 connect_res =
439 (struct hbm_client_connect_response *) heci_msg;
440 heci_client_connect_response(dev, connect_res);
441 DBG("client connect response message received.\n");
442 wake_up(&dev->wait_recvd_msg);
443 break;
445 case CLIENT_DISCONNECT_RES_CMD:
446 disconnect_res =
447 (struct hbm_client_connect_response *) heci_msg;
448 heci_client_disconnect_response(dev, disconnect_res);
449 DBG("client disconnect response message received.\n");
450 wake_up(&dev->wait_recvd_msg);
451 break;
453 case HECI_FLOW_CONTROL_CMD:
454 flow_control = (struct hbm_flow_control *) heci_msg;
455 heci_client_flow_control_response(dev, flow_control);
456 DBG("client flow control response message received.\n");
457 break;
459 case HOST_CLIENT_PROPERTEIS_RES_CMD:
460 props_res = (struct hbm_props_response *) heci_msg;
461 if (props_res->status != 0) {
462 BUG();
463 break;
465 for (i = 0; i < dev->num_heci_me_clients; i++) {
466 if (dev->me_clients[i].client_id ==
467 props_res->address) {
468 dev->me_clients[i].props =
469 props_res->client_properties;
470 break;
474 dev->recvd_msg = 1;
475 break;
477 case HOST_ENUM_RES_CMD:
478 enum_res = (struct hbm_host_enum_response *) heci_msg;
479 memcpy(dev->heci_me_clients, enum_res->valid_addresses, 32);
480 dev->recvd_msg = 1;
481 break;
483 case HOST_STOP_RES_CMD:
484 dev->heci_state = HECI_DISABLED;
485 DBG("reseting because of FW stop response.\n");
486 heci_reset(dev, 1);
487 break;
489 case CLIENT_DISCONNECT_REQ_CMD:
490 /* search for client */
491 disconnect_req =
492 (struct hbm_client_disconnect_request *) heci_msg;
493 heci_client_disconnect_request(dev, disconnect_req);
494 break;
496 case ME_STOP_REQ_CMD:
497 /* prepare stop request */
498 heci_hdr = (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
499 heci_hdr->host_addr = 0;
500 heci_hdr->me_addr = 0;
501 heci_hdr->length = sizeof(struct hbm_host_stop_request);
502 heci_hdr->msg_complete = 1;
503 heci_hdr->reserved = 0;
504 h_stop_req =
505 (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
506 memset(h_stop_req, 0, sizeof(struct hbm_host_stop_request));
507 h_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
508 h_stop_req->reason = DRIVER_STOP_REQUEST;
509 h_stop_req->reserved[0] = 0;
510 h_stop_req->reserved[1] = 0;
511 dev->extra_write_index = 2;
512 break;
514 default:
515 BUG();
516 break;
522 * heci_bh_read_pthi_message - bottom half read routine after ISR to
523 * handle the read pthi message data processing.
525 * @complete_list: An instance of our list structure
526 * @dev: Device object for our driver
527 * @heci_hdr: header of pthi message
529 * returns 0 on success, <0 on failure.
531 static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
532 struct iamt_heci_device *dev,
533 struct heci_msg_hdr *heci_hdr)
535 struct heci_file_private *file_ext;
536 struct heci_cb_private *priv_cb;
537 unsigned char *buffer;
539 BUG_ON(heci_hdr->me_addr != dev->iamthif_file_ext.me_client_id);
540 BUG_ON(dev->iamthif_state != HECI_IAMTHIF_READING);
542 buffer = (unsigned char *) (dev->iamthif_msg_buf +
543 dev->iamthif_msg_buf_index);
544 BUG_ON(sizeof(dev->iamthif_msg_buf) <
545 (dev->iamthif_msg_buf_index + heci_hdr->length));
547 heci_read_slots(dev, buffer, heci_hdr->length);
549 dev->iamthif_msg_buf_index += heci_hdr->length;
551 if (!(heci_hdr->msg_complete))
552 return 0;
554 DBG("pthi_message_buffer_index=%d\n", heci_hdr->length);
555 DBG("completed pthi read.\n ");
556 if (!dev->iamthif_current_cb)
557 return -ENODEV;
559 priv_cb = dev->iamthif_current_cb;
560 dev->iamthif_current_cb = NULL;
562 file_ext = (struct heci_file_private *)priv_cb->file_private;
563 if (!file_ext)
564 return -ENODEV;
566 dev->iamthif_stall_timer = 0;
567 priv_cb->information = dev->iamthif_msg_buf_index;
568 priv_cb->read_time = get_seconds();
569 if ((dev->iamthif_ioctl) && (file_ext == &dev->iamthif_file_ext)) {
570 /* found the iamthif cb */
571 DBG("complete the pthi read cb.\n ");
572 if (&dev->iamthif_file_ext) {
573 DBG("add the pthi read cb to complete.\n ");
574 list_add_tail(&priv_cb->cb_list,
575 &complete_list->heci_cb.cb_list);
578 return 0;
582 * _heci_bh_state_ok - check if heci header matches file private data
584 * @file_ext: private data of the file object
585 * @heci_hdr: header of heci client message
587 * returns !=0 if matches, 0 if no match.
589 static int _heci_bh_state_ok(struct heci_file_private *file_ext,
590 struct heci_msg_hdr *heci_hdr)
592 return ((file_ext->host_client_id == heci_hdr->host_addr)
593 && (file_ext->me_client_id == heci_hdr->me_addr)
594 && (file_ext->state == HECI_FILE_CONNECTED)
595 && (HECI_READ_COMPLETE != file_ext->reading_state));
599 * heci_bh_read_client_message - bottom half read routine after ISR to
600 * handle the read heci client message data processing.
602 * @complete_list: An instance of our list structure
603 * @dev: Device object for our driver
604 * @heci_hdr: header of heci client message
606 * returns 0 on success, <0 on failure.
608 static int heci_bh_read_client_message(struct io_heci_list *complete_list,
609 struct iamt_heci_device *dev,
610 struct heci_msg_hdr *heci_hdr)
612 struct heci_file_private *file_ext;
613 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
614 unsigned char *buffer = NULL;
616 DBG("start client msg\n");
617 if (!((dev->read_list.status == 0) &&
618 !list_empty(&dev->read_list.heci_cb.cb_list)))
619 goto quit;
621 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
622 &dev->read_list.heci_cb.cb_list, cb_list) {
623 file_ext = (struct heci_file_private *)
624 priv_cb_pos->file_private;
625 if ((file_ext != NULL) &&
626 (_heci_bh_state_ok(file_ext, heci_hdr))) {
627 spin_lock_bh(&file_ext->read_io_lock);
628 file_ext->reading_state = HECI_READING;
629 buffer = (unsigned char *)
630 (priv_cb_pos->response_buffer.data +
631 priv_cb_pos->information);
632 BUG_ON(priv_cb_pos->response_buffer.size <
633 heci_hdr->length +
634 priv_cb_pos->information);
636 if (priv_cb_pos->response_buffer.size <
637 heci_hdr->length +
638 priv_cb_pos->information) {
639 DBG("message overflow.\n");
640 list_del(&priv_cb_pos->cb_list);
641 spin_unlock_bh(&file_ext->read_io_lock);
642 return -ENOMEM;
644 if (buffer) {
645 heci_read_slots(dev, buffer,
646 heci_hdr->length);
648 priv_cb_pos->information += heci_hdr->length;
649 if (heci_hdr->msg_complete) {
650 file_ext->status = 0;
651 list_del(&priv_cb_pos->cb_list);
652 spin_unlock_bh(&file_ext->read_io_lock);
653 DBG("completed read host client = %d,"
654 "ME client = %d, "
655 "data length = %lu\n",
656 file_ext->host_client_id,
657 file_ext->me_client_id,
658 priv_cb_pos->information);
660 *(priv_cb_pos->response_buffer.data +
661 priv_cb_pos->information) = '\0';
662 DBG("priv_cb_pos->res_buffer - %s\n",
663 priv_cb_pos->response_buffer.data);
664 list_add_tail(&priv_cb_pos->cb_list,
665 &complete_list->heci_cb.cb_list);
666 } else {
667 spin_unlock_bh(&file_ext->read_io_lock);
670 break;
675 quit:
676 DBG("message read\n");
677 if (!buffer) {
678 heci_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
679 heci_hdr->length);
680 DBG("discarding message, header=%08x.\n",
681 *(__u32 *) dev->rd_msg_buf);
684 return 0;
688 * _heci_bh_iamthif_read - prepare to read iamthif data.
690 * @dev: Device object for our driver.
691 * @slots: free slots.
693 * returns 0, OK; otherwise, error.
695 static int _heci_bh_iamthif_read(struct iamt_heci_device *dev, __s32 *slots)
698 if (((*slots) * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr)
699 + sizeof(struct hbm_flow_control))) {
700 *slots -= (sizeof(struct heci_msg_hdr) +
701 sizeof(struct hbm_flow_control) + 3) / 4;
702 if (!heci_send_flow_control(dev, &dev->iamthif_file_ext)) {
703 DBG("iamthif flow control failed\n");
704 } else {
705 DBG("iamthif flow control success\n");
706 dev->iamthif_state = HECI_IAMTHIF_READING;
707 dev->iamthif_flow_control_pending = 0;
708 dev->iamthif_msg_buf_index = 0;
709 dev->iamthif_msg_buf_size = 0;
710 dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
711 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
713 return 0;
714 } else {
715 return -ECOMPLETE_MESSAGE;
720 * _heci_bh_close - process close related operation.
722 * @dev: Device object for our driver.
723 * @slots: free slots.
724 * @priv_cb_pos: callback block.
725 * @file_ext: private data of the file object.
726 * @cmpl_list: complete list.
728 * returns 0, OK; otherwise, error.
730 static int _heci_bh_close(struct iamt_heci_device *dev, __s32 *slots,
731 struct heci_cb_private *priv_cb_pos,
732 struct heci_file_private *file_ext,
733 struct io_heci_list *cmpl_list)
735 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
736 sizeof(struct hbm_client_disconnect_request))) {
737 *slots -= (sizeof(struct heci_msg_hdr) +
738 sizeof(struct hbm_client_disconnect_request) + 3) / 4;
740 if (!heci_disconnect(dev, file_ext)) {
741 file_ext->status = 0;
742 priv_cb_pos->information = 0;
743 list_move_tail(&priv_cb_pos->cb_list,
744 &cmpl_list->heci_cb.cb_list);
745 return -ECOMPLETE_MESSAGE;
746 } else {
747 file_ext->state = HECI_FILE_DISCONNECTING;
748 file_ext->status = 0;
749 priv_cb_pos->information = 0;
750 list_move_tail(&priv_cb_pos->cb_list,
751 &dev->ctrl_rd_list.heci_cb.cb_list);
752 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
754 } else {
755 /* return the cancel routine */
756 return -ECORRUPTED_MESSAGE_HEADER;
759 return 0;
763 * _heci_hb_close - process read related operation.
765 * @dev: Device object for our driver.
766 * @slots: free slots.
767 * @priv_cb_pos: callback block.
768 * @file_ext: private data of the file object.
769 * @cmpl_list: complete list.
771 * returns 0, OK; otherwise, error.
773 static int _heci_bh_read(struct iamt_heci_device *dev, __s32 *slots,
774 struct heci_cb_private *priv_cb_pos,
775 struct heci_file_private *file_ext,
776 struct io_heci_list *cmpl_list)
778 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
779 sizeof(struct hbm_flow_control))) {
780 *slots -= (sizeof(struct heci_msg_hdr) +
781 sizeof(struct hbm_flow_control) + 3) / 4;
782 if (!heci_send_flow_control(dev, file_ext)) {
783 file_ext->status = -ENODEV;
784 priv_cb_pos->information = 0;
785 list_move_tail(&priv_cb_pos->cb_list,
786 &cmpl_list->heci_cb.cb_list);
787 return -ENODEV;
788 } else {
789 list_move_tail(&priv_cb_pos->cb_list,
790 &dev->read_list.heci_cb.cb_list);
792 } else {
793 /* return the cancel routine */
794 list_del(&priv_cb_pos->cb_list);
795 return -ECORRUPTED_MESSAGE_HEADER;
798 return 0;
803 * _heci_bh_ioctl - process ioctl related operation.
805 * @dev: Device object for our driver.
806 * @slots: free slots.
807 * @priv_cb_pos: callback block.
808 * @file_ext: private data of the file object.
809 * @cmpl_list: complete list.
811 * returns 0, OK; otherwise, error.
813 static int _heci_bh_ioctl(struct iamt_heci_device *dev, __s32 *slots,
814 struct heci_cb_private *priv_cb_pos,
815 struct heci_file_private *file_ext,
816 struct io_heci_list *cmpl_list)
818 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
819 sizeof(struct hbm_client_connect_request))) {
820 file_ext->state = HECI_FILE_CONNECTING;
821 *slots -= (sizeof(struct heci_msg_hdr) +
822 sizeof(struct hbm_client_connect_request) + 3) / 4;
823 if (!heci_connect(dev, file_ext)) {
824 file_ext->status = -ENODEV;
825 priv_cb_pos->information = 0;
826 list_del(&priv_cb_pos->cb_list);
827 return -ENODEV;
828 } else {
829 list_move_tail(&priv_cb_pos->cb_list,
830 &dev->ctrl_rd_list.heci_cb.cb_list);
831 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
833 } else {
834 /* return the cancel routine */
835 list_del(&priv_cb_pos->cb_list);
836 return -ECORRUPTED_MESSAGE_HEADER;
839 return 0;
843 * _heci_bh_cmpl - process completed and no-iamthif operation.
845 * @dev: Device object for our driver.
846 * @slots: free slots.
847 * @priv_cb_pos: callback block.
848 * @file_ext: private data of the file object.
849 * @cmpl_list: complete list.
851 * returns 0, OK; otherwise, error.
853 static int _heci_bh_cmpl(struct iamt_heci_device *dev, __s32 *slots,
854 struct heci_cb_private *priv_cb_pos,
855 struct heci_file_private *file_ext,
856 struct io_heci_list *cmpl_list)
858 struct heci_msg_hdr *heci_hdr;
860 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
861 (priv_cb_pos->request_buffer.size -
862 priv_cb_pos->information))) {
863 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
864 heci_hdr->host_addr = file_ext->host_client_id;
865 heci_hdr->me_addr = file_ext->me_client_id;
866 heci_hdr->length = ((priv_cb_pos->request_buffer.size) -
867 (priv_cb_pos->information));
868 heci_hdr->msg_complete = 1;
869 heci_hdr->reserved = 0;
870 DBG("priv_cb_pos->request_buffer.size =%d"
871 "heci_hdr->msg_complete= %d\n",
872 priv_cb_pos->request_buffer.size,
873 heci_hdr->msg_complete);
874 DBG("priv_cb_pos->information =%lu\n",
875 priv_cb_pos->information);
876 DBG("heci_hdr->length =%d\n",
877 heci_hdr->length);
878 *slots -= (sizeof(struct heci_msg_hdr) +
879 heci_hdr->length + 3) / 4;
880 if (!heci_write_message(dev, heci_hdr,
881 (unsigned char *)
882 (priv_cb_pos->request_buffer.data +
883 priv_cb_pos->information),
884 heci_hdr->length)) {
885 file_ext->status = -ENODEV;
886 list_move_tail(&priv_cb_pos->cb_list,
887 &cmpl_list->heci_cb.cb_list);
888 return -ENODEV;
889 } else {
890 flow_ctrl_reduce(dev, file_ext);
891 file_ext->status = 0;
892 priv_cb_pos->information += heci_hdr->length;
893 list_move_tail(&priv_cb_pos->cb_list,
894 &dev->write_waiting_list.heci_cb.cb_list);
896 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
897 /* buffer is still empty */
898 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
899 heci_hdr->host_addr = file_ext->host_client_id;
900 heci_hdr->me_addr = file_ext->me_client_id;
901 heci_hdr->length =
902 (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
903 heci_hdr->msg_complete = 0;
904 heci_hdr->reserved = 0;
906 (*slots) -= (sizeof(struct heci_msg_hdr) +
907 heci_hdr->length + 3) / 4;
908 if (!heci_write_message(dev, heci_hdr,
909 (unsigned char *)
910 (priv_cb_pos->request_buffer.data +
911 priv_cb_pos->information),
912 heci_hdr->length)) {
913 file_ext->status = -ENODEV;
914 list_move_tail(&priv_cb_pos->cb_list,
915 &cmpl_list->heci_cb.cb_list);
916 return -ENODEV;
917 } else {
918 priv_cb_pos->information += heci_hdr->length;
919 DBG("priv_cb_pos->request_buffer.size =%d"
920 " heci_hdr->msg_complete= %d\n",
921 priv_cb_pos->request_buffer.size,
922 heci_hdr->msg_complete);
923 DBG("priv_cb_pos->information =%lu\n",
924 priv_cb_pos->information);
925 DBG("heci_hdr->length =%d\n", heci_hdr->length);
927 return -ECOMPLETE_MESSAGE;
928 } else {
929 return -ECORRUPTED_MESSAGE_HEADER;
932 return 0;
936 * _heci_bh_cmpl_iamthif - process completed iamthif operation.
938 * @dev: Device object for our driver.
939 * @slots: free slots.
940 * @priv_cb_pos: callback block.
941 * @file_ext: private data of the file object.
942 * @cmpl_list: complete list.
944 * returns 0, OK; otherwise, error.
946 static int _heci_bh_cmpl_iamthif(struct iamt_heci_device *dev, __s32 *slots,
947 struct heci_cb_private *priv_cb_pos,
948 struct heci_file_private *file_ext,
949 struct io_heci_list *cmpl_list)
951 struct heci_msg_hdr *heci_hdr;
953 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
954 dev->iamthif_msg_buf_size -
955 dev->iamthif_msg_buf_index)) {
956 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
957 heci_hdr->host_addr = file_ext->host_client_id;
958 heci_hdr->me_addr = file_ext->me_client_id;
959 heci_hdr->length = dev->iamthif_msg_buf_size -
960 dev->iamthif_msg_buf_index;
961 heci_hdr->msg_complete = 1;
962 heci_hdr->reserved = 0;
964 *slots -= (sizeof(struct heci_msg_hdr) +
965 heci_hdr->length + 3) / 4;
967 if (!heci_write_message(dev, heci_hdr,
968 (dev->iamthif_msg_buf +
969 dev->iamthif_msg_buf_index),
970 heci_hdr->length)) {
971 dev->iamthif_state = HECI_IAMTHIF_IDLE;
972 file_ext->status = -ENODEV;
973 list_del(&priv_cb_pos->cb_list);
974 return -ENODEV;
975 } else {
976 flow_ctrl_reduce(dev, file_ext);
977 dev->iamthif_msg_buf_index += heci_hdr->length;
978 priv_cb_pos->information = dev->iamthif_msg_buf_index;
979 file_ext->status = 0;
980 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
981 dev->iamthif_flow_control_pending = 1;
982 /* save iamthif cb sent to pthi client */
983 dev->iamthif_current_cb = priv_cb_pos;
984 list_move_tail(&priv_cb_pos->cb_list,
985 &dev->write_waiting_list.heci_cb.cb_list);
988 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
989 /* buffer is still empty */
990 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
991 heci_hdr->host_addr = file_ext->host_client_id;
992 heci_hdr->me_addr = file_ext->me_client_id;
993 heci_hdr->length =
994 (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
995 heci_hdr->msg_complete = 0;
996 heci_hdr->reserved = 0;
998 *slots -= (sizeof(struct heci_msg_hdr) +
999 heci_hdr->length + 3) / 4;
1001 if (!heci_write_message(dev, heci_hdr,
1002 (dev->iamthif_msg_buf +
1003 dev->iamthif_msg_buf_index),
1004 heci_hdr->length)) {
1005 file_ext->status = -ENODEV;
1006 list_del(&priv_cb_pos->cb_list);
1007 } else {
1008 dev->iamthif_msg_buf_index += heci_hdr->length;
1010 return -ECOMPLETE_MESSAGE;
1011 } else {
1012 return -ECORRUPTED_MESSAGE_HEADER;
1015 return 0;
1019 * heci_bh_write_handler - bottom half write routine after
1020 * ISR to handle the write processing.
1022 * @cmpl_list: An instance of our list structure
1023 * @dev: Device object for our driver
1024 * @slots: slots to write.
1026 * returns 0 on success, <0 on failure.
1028 static int heci_bh_write_handler(struct io_heci_list *cmpl_list,
1029 struct iamt_heci_device *dev,
1030 __s32 *slots)
1033 struct heci_file_private *file_ext;
1034 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1035 struct io_heci_list *list;
1036 int ret;
1038 if (!host_buffer_is_empty(dev)) {
1039 DBG("host buffer is not empty.\n");
1040 return 0;
1042 dev->write_hang = -1;
1043 *slots = count_empty_write_slots(dev);
1044 /* complete all waiting for write CB */
1045 DBG("complete all waiting for write cb.\n");
1047 list = &dev->write_waiting_list;
1048 if ((list->status == 0)
1049 && !list_empty(&list->heci_cb.cb_list)) {
1050 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1051 &list->heci_cb.cb_list, cb_list) {
1052 file_ext = (struct heci_file_private *)
1053 priv_cb_pos->file_private;
1054 if (file_ext != NULL) {
1055 file_ext->status = 0;
1056 list_del(&priv_cb_pos->cb_list);
1057 if ((HECI_WRITING == file_ext->writing_state) &&
1058 (priv_cb_pos->major_file_operations ==
1059 HECI_WRITE) &&
1060 (file_ext != &dev->iamthif_file_ext)) {
1061 DBG("HECI WRITE COMPLETE\n");
1062 file_ext->writing_state =
1063 HECI_WRITE_COMPLETE;
1064 list_add_tail(&priv_cb_pos->cb_list,
1065 &cmpl_list->heci_cb.cb_list);
1067 if (file_ext == &dev->iamthif_file_ext) {
1068 DBG("check iamthif flow control.\n");
1069 if (dev->iamthif_flow_control_pending) {
1070 ret = _heci_bh_iamthif_read(dev,
1071 slots);
1072 if (ret != 0)
1073 return ret;
1081 if ((dev->stop) && (!dev->wd_pending)) {
1082 dev->wd_stoped = 1;
1083 wake_up_interruptible(&dev->wait_stop_wd);
1084 return 0;
1087 if (dev->extra_write_index != 0) {
1088 DBG("extra_write_index =%d.\n", dev->extra_write_index);
1089 heci_write_message(dev,
1090 (struct heci_msg_hdr *) &dev->ext_msg_buf[0],
1091 (unsigned char *) &dev->ext_msg_buf[1],
1092 (dev->extra_write_index - 1) * sizeof(__u32));
1093 *slots -= dev->extra_write_index;
1094 dev->extra_write_index = 0;
1096 if (dev->heci_state == HECI_ENABLED) {
1097 if ((dev->wd_pending)
1098 && flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1099 if (!heci_send_wd(dev))
1100 DBG("wd send failed.\n");
1101 else
1102 flow_ctrl_reduce(dev, &dev->wd_file_ext);
1104 dev->wd_pending = 0;
1106 if (dev->wd_timeout != 0) {
1107 *slots -= (sizeof(struct heci_msg_hdr) +
1108 HECI_START_WD_DATA_SIZE + 3) / 4;
1109 dev->wd_due_counter = 2;
1110 } else {
1111 *slots -= (sizeof(struct heci_msg_hdr) +
1112 HECI_WD_PARAMS_SIZE + 3) / 4;
1113 dev->wd_due_counter = 0;
1118 if (dev->stop)
1119 return ~ENODEV;
1121 /* complete control write list CB */
1122 if (dev->ctrl_wr_list.status == 0) {
1123 /* complete control write list CB */
1124 DBG("complete control write list cb.\n");
1125 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1126 &dev->ctrl_wr_list.heci_cb.cb_list, cb_list) {
1127 file_ext = (struct heci_file_private *)
1128 priv_cb_pos->file_private;
1129 if (file_ext == NULL) {
1130 list_del(&priv_cb_pos->cb_list);
1131 return -ENODEV;
1133 switch (priv_cb_pos->major_file_operations) {
1134 case HECI_CLOSE:
1135 /* send disconnect message */
1136 ret = _heci_bh_close(dev, slots,
1137 priv_cb_pos,
1138 file_ext, cmpl_list);
1139 if (ret != 0)
1140 return ret;
1142 break;
1143 case HECI_READ:
1144 /* send flow control message */
1145 ret = _heci_bh_read(dev, slots,
1146 priv_cb_pos,
1147 file_ext, cmpl_list);
1148 if (ret != 0)
1149 return ret;
1151 break;
1152 case HECI_IOCTL:
1153 /* connect message */
1154 if (!other_client_is_connecting(dev, file_ext))
1155 continue;
1156 ret = _heci_bh_ioctl(dev, slots,
1157 priv_cb_pos,
1158 file_ext, cmpl_list);
1159 if (ret != 0)
1160 return ret;
1162 break;
1164 default:
1165 BUG();
1170 /* complete write list CB */
1171 if ((dev->write_list.status == 0)
1172 && !list_empty(&dev->write_list.heci_cb.cb_list)) {
1173 DBG("complete write list cb.\n");
1174 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1175 &dev->write_list.heci_cb.cb_list, cb_list) {
1176 file_ext = (struct heci_file_private *)
1177 priv_cb_pos->file_private;
1179 if (file_ext != NULL) {
1180 if (file_ext != &dev->iamthif_file_ext) {
1181 if (!flow_ctrl_creds(dev, file_ext)) {
1182 DBG("No flow control"
1183 " credentials for client"
1184 " %d, not sending.\n",
1185 file_ext->host_client_id);
1186 continue;
1188 ret = _heci_bh_cmpl(dev, slots,
1189 priv_cb_pos,
1190 file_ext,
1191 cmpl_list);
1192 if (ret != 0)
1193 return ret;
1195 } else if (file_ext == &dev->iamthif_file_ext) {
1196 /* IAMTHIF IOCTL */
1197 DBG("complete pthi write cb.\n");
1198 if (!flow_ctrl_creds(dev, file_ext)) {
1199 DBG("No flow control"
1200 " credentials for pthi"
1201 " client %d.\n",
1202 file_ext->host_client_id);
1203 continue;
1205 ret = _heci_bh_cmpl_iamthif(dev, slots,
1206 priv_cb_pos,
1207 file_ext,
1208 cmpl_list);
1209 if (ret != 0)
1210 return ret;
1217 return 0;
1222 * is_treat_specially_client - check if the message belong
1223 * to the file private data.
1225 * @file_ext: private data of the file object
1226 * @rs: connect response bus message
1227 * @dev: Device object for our driver
1229 * returns 0 on success, <0 on failure.
1231 static int is_treat_specially_client(struct heci_file_private *file_ext,
1232 struct hbm_client_connect_response *rs)
1234 int ret = 0;
1236 if ((file_ext->host_client_id == rs->host_addr) &&
1237 (file_ext->me_client_id == rs->me_addr)) {
1238 if (rs->status == 0) {
1239 DBG("client connect status = 0x%08x.\n", rs->status);
1240 file_ext->state = HECI_FILE_CONNECTED;
1241 file_ext->status = 0;
1242 } else {
1243 DBG("client connect status = 0x%08x.\n", rs->status);
1244 file_ext->state = HECI_FILE_DISCONNECTED;
1245 file_ext->status = -ENODEV;
1247 ret = 1;
1249 DBG("client state = %d.\n", file_ext->state);
1250 return ret;
1254 * heci_client_connect_response - connect response bh routine
1256 * @dev: Device object for our driver
1257 * @rs: connect response bus message
1259 static void heci_client_connect_response(struct iamt_heci_device *dev,
1260 struct hbm_client_connect_response *rs)
1263 struct heci_file_private *file_ext;
1264 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1266 /* if WD or iamthif client treat specially */
1268 if ((is_treat_specially_client(&(dev->wd_file_ext), rs)) ||
1269 (is_treat_specially_client(&(dev->iamthif_file_ext), rs)))
1270 return;
1272 if (dev->ctrl_rd_list.status == 0
1273 && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1274 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1275 &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
1276 file_ext = (struct heci_file_private *)
1277 priv_cb_pos->file_private;
1278 if (file_ext == NULL) {
1279 list_del(&priv_cb_pos->cb_list);
1280 return;
1282 if (HECI_IOCTL == priv_cb_pos->major_file_operations) {
1283 if (is_treat_specially_client(file_ext, rs)) {
1284 list_del(&priv_cb_pos->cb_list);
1285 file_ext->status = 0;
1286 file_ext->timer_count = 0;
1287 break;
1295 * heci_client_disconnect_response - disconnect response bh routine
1297 * @dev: Device object for our driver
1298 * @rs: disconnect response bus message
1300 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
1301 struct hbm_client_connect_response *rs)
1303 struct heci_file_private *file_ext;
1304 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1306 if (dev->ctrl_rd_list.status == 0
1307 && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1308 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1309 &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
1310 file_ext = (struct heci_file_private *)
1311 priv_cb_pos->file_private;
1313 if (file_ext == NULL) {
1314 list_del(&priv_cb_pos->cb_list);
1315 return;
1318 DBG("list_for_each_entry_safe in ctrl_rd_list.\n");
1319 if ((file_ext->host_client_id == rs->host_addr) &&
1320 (file_ext->me_client_id == rs->me_addr)) {
1322 list_del(&priv_cb_pos->cb_list);
1323 if (rs->status == 0) {
1324 file_ext->state =
1325 HECI_FILE_DISCONNECTED;
1328 file_ext->status = 0;
1329 file_ext->timer_count = 0;
1330 break;
1337 * same_flow_addr - tell they have same address.
1339 * @file: private data of the file object.
1340 * @flow: flow control.
1342 * returns !=0, same; 0,not.
1344 static int same_flow_addr(struct heci_file_private *file,
1345 struct hbm_flow_control *flow)
1347 return ((file->host_client_id == flow->host_addr)
1348 && (file->me_client_id == flow->me_addr));
1352 * add_single_flow_creds - add single buffer credentials.
1354 * @file: private data ot the file object.
1355 * @flow: flow control.
1357 static void add_single_flow_creds(struct iamt_heci_device *dev,
1358 struct hbm_flow_control *flow)
1360 struct heci_me_client *client;
1361 int i;
1363 for (i = 0; i < dev->num_heci_me_clients; i++) {
1364 client = &dev->me_clients[i];
1365 if ((client != NULL) &&
1366 (flow->me_addr == client->client_id)) {
1367 if (client->props.single_recv_buf != 0) {
1368 client->flow_ctrl_creds++;
1369 DBG("recv flow ctrl msg ME %d (single).\n",
1370 flow->me_addr);
1371 DBG("flow control credentials=%d.\n",
1372 client->flow_ctrl_creds);
1373 } else {
1374 BUG(); /* error in flow control */
1381 * heci_client_flow_control_response - flow control response bh routine
1383 * @dev: Device object for our driver
1384 * @flow_control: flow control response bus message
1386 static void heci_client_flow_control_response(struct iamt_heci_device *dev,
1387 struct hbm_flow_control *flow_control)
1389 struct heci_file_private *file_pos = NULL;
1390 struct heci_file_private *file_next = NULL;
1392 if (flow_control->host_addr == 0) {
1393 /* single receive buffer */
1394 add_single_flow_creds(dev, flow_control);
1395 } else {
1396 /* normal connection */
1397 list_for_each_entry_safe(file_pos, file_next,
1398 &dev->file_list, link) {
1399 DBG("list_for_each_entry_safe in file_list\n");
1401 DBG("file_ext of host client %d ME client %d.\n",
1402 file_pos->host_client_id,
1403 file_pos->me_client_id);
1404 DBG("flow ctrl msg for host %d ME %d.\n",
1405 flow_control->host_addr,
1406 flow_control->me_addr);
1407 if (same_flow_addr(file_pos, flow_control)) {
1408 DBG("recv ctrl msg for host %d ME %d.\n",
1409 flow_control->host_addr,
1410 flow_control->me_addr);
1411 file_pos->flow_ctrl_creds++;
1412 DBG("flow control credentials=%d.\n",
1413 file_pos->flow_ctrl_creds);
1414 break;
1421 * same_disconn_addr - tell they have same address
1423 * @file: private data of the file object.
1424 * @disconn: disconnection request.
1426 * returns !=0, same; 0,not.
1428 static int same_disconn_addr(struct heci_file_private *file,
1429 struct hbm_client_disconnect_request *disconn)
1431 return ((file->host_client_id == disconn->host_addr)
1432 && (file->me_client_id == disconn->me_addr));
1436 * heci_client_disconnect_request - disconnect request bh routine
1438 * @dev: Device object for our driver.
1439 * @disconnect_req: disconnect request bus message.
1441 static void heci_client_disconnect_request(struct iamt_heci_device *dev,
1442 struct hbm_client_disconnect_request *disconnect_req)
1444 struct heci_msg_hdr *heci_hdr;
1445 struct hbm_client_connect_response *disconnect_res;
1446 struct heci_file_private *file_pos = NULL;
1447 struct heci_file_private *file_next = NULL;
1449 list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
1450 if (same_disconn_addr(file_pos, disconnect_req)) {
1451 DBG("disconnect request host client %d ME client %d.\n",
1452 disconnect_req->host_addr,
1453 disconnect_req->me_addr);
1454 file_pos->state = HECI_FILE_DISCONNECTED;
1455 file_pos->timer_count = 0;
1456 if (file_pos == &dev->wd_file_ext) {
1457 dev->wd_due_counter = 0;
1458 dev->wd_pending = 0;
1459 } else if (file_pos == &dev->iamthif_file_ext)
1460 dev->iamthif_timer = 0;
1462 /* prepare disconnect response */
1463 heci_hdr =
1464 (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
1465 heci_hdr->host_addr = 0;
1466 heci_hdr->me_addr = 0;
1467 heci_hdr->length =
1468 sizeof(struct hbm_client_connect_response);
1469 heci_hdr->msg_complete = 1;
1470 heci_hdr->reserved = 0;
1472 disconnect_res =
1473 (struct hbm_client_connect_response *)
1474 &dev->ext_msg_buf[1];
1475 disconnect_res->host_addr = file_pos->host_client_id;
1476 disconnect_res->me_addr = file_pos->me_client_id;
1477 *(__u8 *) (&disconnect_res->cmd) =
1478 CLIENT_DISCONNECT_RES_CMD;
1479 disconnect_res->status = 0;
1480 dev->extra_write_index = 2;
1481 break;
1487 * heci_timer - timer function.
1489 * @data: pointer to the device structure
1491 * NOTE: This function is called by timer interrupt work
1493 void heci_wd_timer(unsigned long data)
1495 struct iamt_heci_device *dev = (struct iamt_heci_device *) data;
1497 DBG("send watchdog.\n");
1498 spin_lock_bh(&dev->device_lock);
1499 if (dev->heci_state != HECI_ENABLED) {
1500 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1501 spin_unlock_bh(&dev->device_lock);
1502 return;
1504 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
1505 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1506 spin_unlock_bh(&dev->device_lock);
1507 return;
1509 /* Watchdog */
1510 if ((dev->wd_due_counter != 0) && (dev->wd_bypass == 0)) {
1511 if (--dev->wd_due_counter == 0) {
1512 if (dev->host_buffer_is_empty &&
1513 flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1514 dev->host_buffer_is_empty = 0;
1515 if (!heci_send_wd(dev)) {
1516 DBG("wd send failed.\n");
1517 } else {
1518 flow_ctrl_reduce(dev,
1519 &dev->wd_file_ext);
1522 if (dev->wd_timeout != 0)
1523 dev->wd_due_counter = 2;
1524 else
1525 dev->wd_due_counter = 0;
1527 } else
1528 dev->wd_pending = 1;
1532 if (dev->iamthif_stall_timer != 0) {
1533 if (--dev->iamthif_stall_timer == 0) {
1534 DBG("reseting because of hang to PTHI.\n");
1535 heci_reset(dev, 1);
1536 dev->iamthif_msg_buf_size = 0;
1537 dev->iamthif_msg_buf_index = 0;
1538 dev->iamthif_canceled = 0;
1539 dev->iamthif_ioctl = 1;
1540 dev->iamthif_state = HECI_IAMTHIF_IDLE;
1541 dev->iamthif_timer = 0;
1542 spin_unlock_bh(&dev->device_lock);
1544 if (dev->iamthif_current_cb)
1545 heci_free_cb_private(dev->iamthif_current_cb);
1547 spin_lock_bh(&dev->device_lock);
1548 dev->iamthif_file_object = NULL;
1549 dev->iamthif_current_cb = NULL;
1550 run_next_iamthif_cmd(dev);
1553 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1554 spin_unlock_bh(&dev->device_lock);