• source navigation • diff markup • identifier search • freetext search •
Version: 2.6.32 2.6.33 2.6.34 2.6.35 2.6.36 2.6.37 2.6.38 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9
Architecture: x86 arm avr32 blackfin m68k m68knommu microblaze mips powerpc sh
1 /* 2 * Part of Intel(R) Manageability Engine Interface Linux driver 3 * 4 * Copyright (c) 2003 - 2008 Intel Corp. 5 * All rights reserved. 6 * 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. 21 * 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. 25 * 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. 38 * 39 */ 40 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> 60 61 #include "heci_data_structures.h" 62 #include "heci.h" 63 #include "heci_interface.h" 64 #include "heci_version.h" 65 66 67 /** 68 * heci_ioctl_get_version - the get driver version IOCTL function 69 * 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 75 * 76 * returns 0 on success, <0 on failure. 77 */ 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) 82 { 83 int rets = 0; 84 struct heci_driver_version *version; 85 struct heci_message_data res_msg; 86 87 if ((if_num != HECI_MINOR_NUMBER) || (!dev) 88 || (!file_ext)) 89 return -ENODEV; 90 91 if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) { 92 DBG("user buffer less than heci_driver_version.\n"); 93 return -EMSGSIZE; 94 } 95 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; 101 } 102 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; 111 112 rets = file_ext->status; 113 /* now copy the data to user space */ 114 if (copy_to_user((void __user *)k_msg.data, res_msg.data, res_msg.size)) { 115 rets = -EFAULT; 116 goto end; 117 } 118 if (put_user(res_msg.size, &u_msg->size)) { 119 rets = -EFAULT; 120 goto end; 121 } 122 end: 123 kfree(res_msg.data); 124 return rets; 125 } 126 127 /** 128 * heci_ioctl_connect_client - the connect to fw client IOCTL function 129 * 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 135 * 136 * returns 0 on success, <0 on failure. 137 */ 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) 142 { 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; 153 154 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file)) 155 return -ENODEV; 156 157 file_ext = file->private_data; 158 if (!file_ext) 159 return -ENODEV; 160 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; 165 } 166 167 if (!k_msg.data) 168 return -EIO; 169 170 req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL); 171 res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL); 172 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; 178 } 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; 184 } 185 req_msg.size = sizeof(struct guid); 186 res_msg.size = sizeof(struct heci_client); 187 188 /* copy the message to kernel space - 189 * use a pointer already copied into kernel space 190 */ 191 if (copy_from_user(req_msg.data, (void __user *)k_msg.data, k_msg.size)) { 192 rets = -EFAULT; 193 goto end; 194 } 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; 200 } 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; 212 } 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; 218 } 219 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; 229 } 230 break; 231 } 232 } 233 /* if we're connecting to PTHI client so we will use the exist 234 * connection 235 */ 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; 242 } 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); 253 } 254 255 } 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); 267 268 /* now copy the data to user space */ 269 if (copy_to_user((void __user *)k_msg.data, 270 res_msg.data, res_msg.size)) { 271 rets = -EFAULT; 272 goto end; 273 } 274 if (put_user(res_msg.size, &u_msg->size)) { 275 rets = -EFAULT; 276 goto end; 277 } 278 goto end; 279 } 280 spin_unlock_bh(&dev->device_lock); 281 282 spin_lock(&file_ext->file_lock); 283 spin_lock_bh(&dev->device_lock); 284 if (file_ext->state != HECI_FILE_CONNECTING) { 285 rets = -ENODEV; 286 spin_unlock_bh(&dev->device_lock); 287 spin_unlock(&file_ext->file_lock); 288 goto end; 289 } 290 /* prepare the output buffer */ 291 client = (struct heci_client *) res_msg.data; 292 client->max_msg_length = dev->me_clients[i].props.max_msg_length; 293 client->protocol_version = dev->me_clients[i].props.protocol_version; 294 if (dev->host_buffer_is_empty 295 && !other_client_is_connecting(dev, file_ext)) { 296 dev->host_buffer_is_empty = 0; 297 if (!heci_connect(dev, file_ext)) { 298 rets = -ENODEV; 299 spin_unlock_bh(&dev->device_lock); 300 spin_unlock(&file_ext->file_lock); 301 goto end; 302 } else { 303 file_ext->timer_count = HECI_CONNECT_TIMEOUT; 304 priv_cb->file_private = file_ext; 305 list_add_tail(&priv_cb->cb_list, 306 &dev->ctrl_rd_list.heci_cb. 307 cb_list); 308 } 309 310 311 } else { 312 priv_cb->file_private = file_ext; 313 DBG("add connect cb to control write list.\n"); 314 list_add_tail(&priv_cb->cb_list, 315 &dev->ctrl_wr_list.heci_cb.cb_list); 316 } 317 spin_unlock_bh(&dev->device_lock); 318 spin_unlock(&file_ext->file_lock); 319 err = wait_event_timeout(dev->wait_recvd_msg, 320 (HECI_FILE_CONNECTED == file_ext->state 321 || HECI_FILE_DISCONNECTED == file_ext->state), 322 timeout * HZ); 323 324 spin_lock_bh(&dev->device_lock); 325 if (HECI_FILE_CONNECTED == file_ext->state) { 326 spin_unlock_bh(&dev->device_lock); 327 DBG("successfully connected to FW client.\n"); 328 rets = file_ext->status; 329 /* now copy the data to user space */ 330 if (copy_to_user((void __user *)k_msg.data, 331 res_msg.data, res_msg.size)) { 332 rets = -EFAULT; 333 goto end; 334 } 335 if (put_user(res_msg.size, &u_msg->size)) { 336 rets = -EFAULT; 337 goto end; 338 } 339 goto end; 340 } else { 341 DBG("failed to connect to FW client.file_ext->state = %d.\n", 342 file_ext->state); 343 spin_unlock_bh(&dev->device_lock); 344 if (!err) { 345 DBG("wait_event_interruptible_timeout failed on client" 346 " connect message fw response message.\n"); 347 } 348 rets = -EFAULT; 349 goto remove_list; 350 } 351 352 remove_list: 353 if (priv_cb) { 354 spin_lock_bh(&dev->device_lock); 355 heci_flush_list(&dev->ctrl_rd_list, file_ext); 356 heci_flush_list(&dev->ctrl_wr_list, file_ext); 357 spin_unlock_bh(&dev->device_lock); 358 } 359 end: 360 DBG("free connect cb memory."); 361 kfree(req_msg.data); 362 kfree(res_msg.data); 363 kfree(priv_cb); 364 return rets; 365 } 366 367 /** 368 * heci_ioctl_wd - the wd IOCTL function 369 * 370 * @dev: Device object for our driver 371 * @if_num: minor number 372 * @k_msg: data in kernel on the stack 373 * @file_ext: private data of the file object 374 * 375 * returns 0 on success, <0 on failure. 376 */ 377 int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, 378 struct heci_message_data k_msg, 379 struct heci_file_private *file_ext) 380 { 381 int rets = 0; 382 struct heci_message_data req_msg; /*in kernel on the stack */ 383 384 if (if_num != HECI_MINOR_NUMBER) 385 return -ENODEV; 386 387 spin_lock(&file_ext->file_lock); 388 if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) { 389 DBG("user buffer has invalid size.\n"); 390 spin_unlock(&file_ext->file_lock); 391 return -EMSGSIZE; 392 } 393 spin_unlock(&file_ext->file_lock); 394 395 req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL); 396 if (!req_msg.data) { 397 DBG("failed allocation request buffer size = %d.\n", 398 HECI_WATCHDOG_DATA_SIZE); 399 return -ENOMEM; 400 } 401 req_msg.size = HECI_WATCHDOG_DATA_SIZE; 402 403 /* copy the message to kernel space - use a pointer already 404 * copied into kernel space 405 */ 406 if (copy_from_user(req_msg.data, 407 (void __user *)k_msg.data, req_msg.size)) { 408 rets = -EFAULT; 409 goto end; 410 } 411 spin_lock_bh(&dev->device_lock); 412 if (dev->heci_state != HECI_ENABLED) { 413 rets = -ENODEV; 414 spin_unlock_bh(&dev->device_lock); 415 goto end; 416 } 417 418 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) { 419 rets = -ENODEV; 420 spin_unlock_bh(&dev->device_lock); 421 goto end; 422 } 423 if (!dev->asf_mode) { 424 rets = -EIO; 425 spin_unlock_bh(&dev->device_lock); 426 goto end; 427 } 428 429 memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data, 430 HECI_WATCHDOG_DATA_SIZE); 431 432 dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0]; 433 dev->wd_pending = 0; 434 dev->wd_due_counter = 1; /* next timer */ 435 if (dev->wd_timeout == 0) { 436 memcpy(dev->wd_data, heci_stop_wd_params, 437 HECI_WD_PARAMS_SIZE); 438 } else { 439 memcpy(dev->wd_data, heci_start_wd_params, 440 HECI_WD_PARAMS_SIZE); 441 mod_timer(&dev->wd_timer, jiffies); 442 } 443 spin_unlock_bh(&dev->device_lock); 444 end: 445 kfree(req_msg.data); 446 return rets; 447 } 448 449 450 /** 451 * heci_ioctl_bypass_wd - the bypass_wd IOCTL function 452 * 453 * @dev: Device object for our driver 454 * @if_num: minor number 455 * @k_msg: data in kernel on the stack 456 * @file_ext: private data of the file object 457 * 458 * returns 0 on success, <0 on failure. 459 */ 460 int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, 461 struct heci_message_data k_msg, 462 struct heci_file_private *file_ext) 463 { 464 __u8 flag = 0; 465 int rets = 0; 466 467 if (if_num != HECI_MINOR_NUMBER) 468 return -ENODEV; 469 470 spin_lock(&file_ext->file_lock); 471 if (k_msg.size < 1) { 472 DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n"); 473 spin_unlock(&file_ext->file_lock); 474 return -EMSGSIZE; 475 } 476 spin_unlock(&file_ext->file_lock); 477 if (copy_from_user(&flag, (void __user *)k_msg.data, 1)) { 478 rets = -EFAULT; 479 goto end; 480 } 481 482 spin_lock_bh(&dev->device_lock); 483 flag = flag ? (1) : (0); 484 dev->wd_bypass = flag; 485 spin_unlock_bh(&dev->device_lock); 486 end: 487 return rets; 488 } 489 490 /** 491 * find_pthi_read_list_entry - finds a PTHIlist entry for current file 492 * 493 * @dev: Device object for our driver 494 * @file: pointer to file object 495 * 496 * returns returned a list entry on success, NULL on failure. 497 */ 498 struct heci_cb_private *find_pthi_read_list_entry( 499 struct iamt_heci_device *dev, 500 struct file *file) 501 { 502 struct heci_file_private *file_ext_temp; 503 struct heci_cb_private *priv_cb_pos = NULL; 504 struct heci_cb_private *priv_cb_next = NULL; 505 506 if ((dev->pthi_read_complete_list.status == 0) && 507 !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) { 508 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 509 &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list) { 510 file_ext_temp = (struct heci_file_private *) 511 priv_cb_pos->file_private; 512 if ((file_ext_temp != NULL) && 513 (file_ext_temp == &dev->iamthif_file_ext) && 514 (priv_cb_pos->file_object == file)) 515 return priv_cb_pos; 516 } 517 } 518 return NULL; 519 } 520 521 /** 522 * pthi_read - read data from pthi client 523 * 524 * @dev: Device object for our driver 525 * @if_num: minor number 526 * @file: pointer to file object 527 * @*ubuf: pointer to user data in user space 528 * @length: data length to read 529 * @offset: data read offset 530 * 531 * returns 532 * returned data length on success, 533 * zero if no data to read, 534 * negative on failure. 535 */ 536 int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file, 537 char __user *ubuf, size_t length, loff_t *offset) 538 { 539 int rets = 0; 540 struct heci_cb_private *priv_cb = NULL; 541 struct heci_file_private *file_ext = file->private_data; 542 __u8 i; 543 unsigned long currtime = get_seconds(); 544 545 if ((if_num != HECI_MINOR_NUMBER) || (!dev)) 546 return -ENODEV; 547 548 if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext)) 549 return -ENODEV; 550 551 spin_lock_bh(&dev->device_lock); 552 for (i = 0; i < dev->num_heci_me_clients; i++) { 553 if (dev->me_clients[i].client_id == 554 dev->iamthif_file_ext.me_client_id) 555 break; 556 } 557 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); 558 if ((i == dev->num_heci_me_clients) 559 || (dev->me_clients[i].client_id != 560 dev->iamthif_file_ext.me_client_id)) { 561 DBG("PTHI client not found.\n"); 562 spin_unlock_bh(&dev->device_lock); 563 return -ENODEV; 564 } 565 priv_cb = find_pthi_read_list_entry(dev, file); 566 if (!priv_cb) { 567 spin_unlock_bh(&dev->device_lock); 568 return 0; /* No more data to read */ 569 } else { 570 if (priv_cb && 571 (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) { 572 /* 15 sec for the message has expired */ 573 list_del(&priv_cb->cb_list); 574 spin_unlock_bh(&dev->device_lock); 575 rets = -ETIMEDOUT; 576 goto free; 577 } 578 /* if the whole message will fit remove it from the list */ 579 if ((priv_cb->information >= *offset) && 580 (length >= (priv_cb->information - *offset))) 581 list_del(&priv_cb->cb_list); 582 else if ((priv_cb->information > 0) && 583 (priv_cb->information <= *offset)) { 584 /* end of the message has been reached */ 585 list_del(&priv_cb->cb_list); 586 rets = 0; 587 spin_unlock_bh(&dev->device_lock); 588 goto free; 589 } 590 /* else means that not full buffer will be read and do not 591 * remove message from deletion list 592 */ 593 } 594 DBG("pthi priv_cb->response_buffer size - %d\n", 595 priv_cb->response_buffer.size); 596 DBG("pthi priv_cb->information - %lu\n", 597 priv_cb->information); 598 spin_unlock_bh(&dev->device_lock); 599 600 /* length is being turncated to PAGE_SIZE, however, 601 * the information may be longer */ 602 length = length < (priv_cb->information - *offset) ? 603 length : (priv_cb->information - *offset); 604 605 if (copy_to_user(ubuf, 606 priv_cb->response_buffer.data + *offset, 607 length)) 608 rets = -EFAULT; 609 else { 610 rets = length; 611 if ((*offset + length) < priv_cb->information) { 612 *offset += length; 613 goto out; 614 } 615 } 616 free: 617 DBG("free pthi cb memory.\n"); 618 *offset = 0; 619 heci_free_cb_private(priv_cb); 620 out: 621 return rets; 622 } 623 624 /** 625 * heci_start_read - the start read client message function. 626 * 627 * @dev: Device object for our driver 628 * @if_num: minor number 629 * @file_ext: private data of the file object 630 * 631 * returns 0 on success, <0 on failure. 632 */ 633 int heci_start_read(struct iamt_heci_device *dev, int if_num, 634 struct heci_file_private *file_ext) 635 { 636 int rets = 0; 637 __u8 i; 638 struct heci_cb_private *priv_cb = NULL; 639 640 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) { 641 DBG("received wrong function input param.\n"); 642 return -ENODEV; 643 } 644 645 spin_lock_bh(&dev->device_lock); 646 if (file_ext->state != HECI_FILE_CONNECTED) { 647 spin_unlock_bh(&dev->device_lock); 648 return -ENODEV; 649 } 650 651 if (dev->heci_state != HECI_ENABLED) { 652 spin_unlock_bh(&dev->device_lock); 653 return -ENODEV; 654 } 655 spin_unlock_bh(&dev->device_lock); 656 DBG("check if read is pending.\n"); 657 spin_lock_bh(&file_ext->read_io_lock); 658 if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) { 659 DBG("read is pending.\n"); 660 spin_unlock_bh(&file_ext->read_io_lock); 661 return -EBUSY; 662 } 663 spin_unlock_bh(&file_ext->read_io_lock); 664 665 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); 666 if (!priv_cb) 667 return -ENOMEM; 668 669 spin_lock_bh(&file_ext->read_io_lock); 670 DBG("allocation call back success\n" 671 "host client = %d, ME client = %d\n", 672 file_ext->host_client_id, file_ext->me_client_id); 673 spin_unlock_bh(&file_ext->read_io_lock); 674 675 spin_lock_bh(&dev->device_lock); 676 spin_lock_bh(&file_ext->read_io_lock); 677 for (i = 0; i < dev->num_heci_me_clients; i++) { 678 if (dev->me_clients[i].client_id == file_ext->me_client_id) 679 break; 680 681 } 682 683 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); 684 spin_unlock_bh(&file_ext->read_io_lock); 685 if (i == dev->num_heci_me_clients) { 686 rets = -ENODEV; 687 goto unlock; 688 } 689 690 priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; 691 spin_unlock_bh(&dev->device_lock); 692 priv_cb->response_buffer.data = 693 kmalloc(priv_cb->response_buffer.size, GFP_KERNEL); 694 if (!priv_cb->response_buffer.data) { 695 rets = -ENOMEM; 696 goto fail; 697 } 698 DBG("allocation call back data success.\n"); 699 priv_cb->major_file_operations = HECI_READ; 700 /* make sure information is zero before we start */ 701 priv_cb->information = 0; 702 priv_cb->file_private = (void *) file_ext; 703 spin_lock_bh(&dev->device_lock); 704 spin_lock_bh(&file_ext->read_io_lock); 705 file_ext->read_cb = priv_cb; 706 if (dev->host_buffer_is_empty) { 707 dev->host_buffer_is_empty = 0; 708 if (!heci_send_flow_control(dev, file_ext)) { 709 rets = -ENODEV; 710 spin_unlock_bh(&file_ext->read_io_lock); 711 goto unlock; 712 } else { 713 list_add_tail(&priv_cb->cb_list, 714 &dev->read_list.heci_cb.cb_list); 715 } 716 } else { 717 list_add_tail(&priv_cb->cb_list, 718 &dev->ctrl_wr_list.heci_cb.cb_list); 719 } 720 spin_unlock_bh(&file_ext->read_io_lock); 721 spin_unlock_bh(&dev->device_lock); 722 return rets; 723 unlock: 724 spin_unlock_bh(&dev->device_lock); 725 fail: 726 heci_free_cb_private(priv_cb); 727 return rets; 728 } 729 730 /** 731 * pthi_write - write iamthif data to pthi client 732 * 733 * @dev: Device object for our driver 734 * @priv_cb: heci call back struct 735 * 736 * returns 0 on success, <0 on failure. 737 */ 738 int pthi_write(struct iamt_heci_device *dev, 739 struct heci_cb_private *priv_cb) 740 { 741 int rets = 0; 742 struct heci_msg_hdr heci_hdr; 743 744 if ((!dev) || (!priv_cb)) 745 return -ENODEV; 746 747 DBG("write data to pthi client.\n"); 748 749 dev->iamthif_state = HECI_IAMTHIF_WRITING; 750 dev->iamthif_current_cb = priv_cb; 751 dev->iamthif_file_object = priv_cb->file_object; 752 dev->iamthif_canceled = 0; 753 dev->iamthif_ioctl = 1; 754 dev->iamthif_msg_buf_size = priv_cb->request_buffer.size; 755 memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data, 756 priv_cb->request_buffer.size); 757 758 if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) && 759 dev->host_buffer_is_empty) { 760 dev->host_buffer_is_empty = 0; 761 if (priv_cb->request_buffer.size > 762 (((dev->host_hw_state & H_CBD) >> 24) * 763 sizeof(__u32)) - sizeof(struct heci_msg_hdr)) { 764 heci_hdr.length = 765 (((dev->host_hw_state & H_CBD) >> 24) * 766 sizeof(__u32)) - sizeof(struct heci_msg_hdr); 767 heci_hdr.msg_complete = 0; 768 } else { 769 heci_hdr.length = priv_cb->request_buffer.size; 770 heci_hdr.msg_complete = 1; 771 } 772 773 heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id; 774 heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id; 775 heci_hdr.reserved = 0; 776 dev->iamthif_msg_buf_index += heci_hdr.length; 777 if (!heci_write_message(dev, &heci_hdr, 778 (unsigned char *)(dev->iamthif_msg_buf), 779 heci_hdr.length)) 780 return -ENODEV; 781 782 if (heci_hdr.msg_complete) { 783 flow_ctrl_reduce(dev, &dev->iamthif_file_ext); 784 dev->iamthif_flow_control_pending = 1; 785 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL; 786 DBG("add pthi cb to write waiting list\n"); 787 dev->iamthif_current_cb = priv_cb; 788 dev->iamthif_file_object = priv_cb->file_object; 789 list_add_tail(&priv_cb->cb_list, 790 &dev->write_waiting_list.heci_cb.cb_list); 791 } else { 792 DBG("message does not complete, " 793 "so add pthi cb to write list.\n"); 794 list_add_tail(&priv_cb->cb_list, 795 &dev->write_list.heci_cb.cb_list); 796 } 797 } else { 798 if (!(dev->host_buffer_is_empty)) 799 DBG("host buffer is not empty"); 800 801 DBG("No flow control credentials, " 802 "so add iamthif cb to write list.\n"); 803 list_add_tail(&priv_cb->cb_list, 804 &dev->write_list.heci_cb.cb_list); 805 } 806 return rets; 807 } 808 809 /** 810 * iamthif_ioctl_send_msg - send cmd data to pthi client 811 * 812 * @dev: Device object for our driver 813 * 814 * returns 0 on success, <0 on failure. 815 */ 816 void run_next_iamthif_cmd(struct iamt_heci_device *dev) 817 { 818 struct heci_file_private *file_ext_tmp; 819 struct heci_cb_private *priv_cb_pos = NULL; 820 struct heci_cb_private *priv_cb_next = NULL; 821 int status = 0; 822 823 if (!dev) 824 return; 825 826 dev->iamthif_msg_buf_size = 0; 827 dev->iamthif_msg_buf_index = 0; 828 dev->iamthif_canceled = 0; 829 dev->iamthif_ioctl = 1; 830 dev->iamthif_state = HECI_IAMTHIF_IDLE; 831 dev->iamthif_timer = 0; 832 dev->iamthif_file_object = NULL; 833 834 if (dev->pthi_cmd_list.status == 0 && 835 !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) { 836 DBG("complete pthi cmd_list cb.\n"); 837 838 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 839 &dev->pthi_cmd_list.heci_cb.cb_list, cb_list) { 840 list_del(&priv_cb_pos->cb_list); 841 file_ext_tmp = (struct heci_file_private *) 842 priv_cb_pos->file_private; 843 844 if ((file_ext_tmp != NULL) && 845 (file_ext_tmp == &dev->iamthif_file_ext)) { 846 status = pthi_write(dev, priv_cb_pos); 847 if (status != 0) { 848 DBG("pthi write failed status = %d\n", 849 status); 850 return; 851 } 852 break; 853 } 854 } 855 } 856 } 857 858 /** 859 * heci_free_cb_private - free heci_cb_private related memory 860 * 861 * @priv_cb: heci callback struct 862 */ 863 void heci_free_cb_private(struct heci_cb_private *priv_cb) 864 { 865 if (priv_cb == NULL) 866 return; 867 868 kfree(priv_cb->request_buffer.data); 869 kfree(priv_cb->response_buffer.data); 870 kfree(priv_cb); 871 } 872 873
This page was automatically generated by LXR 0.3.1 (source). • Linux is a registered trademark of Linus Torvalds