Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/drivers/staging/heci/io_heci.c

  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  •  Contact us