~ubuntu-branches/ubuntu/lucid/linux-rt/lucid

« back to all changes in this revision

Viewing changes to drivers/staging/heci/io_heci.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-08-05 23:00:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090805230052-7xedvqcyk9dnnxb2
Tags: 2.6.31-1.1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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