OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [misc/] [ibmasm/] [ibmasmfs.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * IBM ASM Service Processor Device Driver
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
 *
18
 * Copyright (C) IBM Corporation, 2004
19
 *
20
 * Author: Max Asböck <amax@us.ibm.com>
21
 *
22
 */
23
 
24
/*
25
 * Parts of this code are based on an article by Jonathan Corbet
26
 * that appeared in Linux Weekly News.
27
 */
28
 
29
 
30
/*
31
 * The IBMASM file virtual filesystem. It creates the following hierarchy
32
 * dymamically when mounted from user space:
33
 *
34
 *    /ibmasm
35
 *    |-- 0
36
 *    |   |-- command
37
 *    |   |-- event
38
 *    |   |-- reverse_heartbeat
39
 *    |   `-- remote_video
40
 *    |       |-- depth
41
 *    |       |-- height
42
 *    |       `-- width
43
 *    .
44
 *    .
45
 *    .
46
 *    `-- n
47
 *        |-- command
48
 *        |-- event
49
 *        |-- reverse_heartbeat
50
 *        `-- remote_video
51
 *            |-- depth
52
 *            |-- height
53
 *            `-- width
54
 *
55
 * For each service processor the following files are created:
56
 *
57
 * command: execute dot commands
58
 *      write: execute a dot command on the service processor
59
 *      read: return the result of a previously executed dot command
60
 *
61
 * events: listen for service processor events
62
 *      read: sleep (interruptible) until an event occurs
63
 *      write: wakeup sleeping event listener
64
 *
65
 * reverse_heartbeat: send a heartbeat to the service processor
66
 *      read: sleep (interruptible) until the reverse heartbeat fails
67
 *      write: wakeup sleeping heartbeat listener
68
 *
69
 * remote_video/width
70
 * remote_video/height
71
 * remote_video/width: control remote display settings
72
 *      write: set value
73
 *      read: read value
74
 */
75
 
76
#include <linux/fs.h>
77
#include <linux/pagemap.h>
78
#include <asm/uaccess.h>
79
#include <asm/io.h>
80
#include "ibmasm.h"
81
#include "remote.h"
82
#include "dot_command.h"
83
 
84
#define IBMASMFS_MAGIC 0x66726f67
85
 
86
static LIST_HEAD(service_processors);
87
 
88
static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
89
static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
90
static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
91
 
92
 
93
static int ibmasmfs_get_super(struct file_system_type *fst,
94
                        int flags, const char *name, void *data,
95
                        struct vfsmount *mnt)
96
{
97
        return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt);
98
}
99
 
100
static struct super_operations ibmasmfs_s_ops = {
101
        .statfs         = simple_statfs,
102
        .drop_inode     = generic_delete_inode,
103
};
104
 
105
static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
106
 
107
static struct file_system_type ibmasmfs_type = {
108
        .owner          = THIS_MODULE,
109
        .name           = "ibmasmfs",
110
        .get_sb         = ibmasmfs_get_super,
111
        .kill_sb        = kill_litter_super,
112
};
113
 
114
static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
115
{
116
        struct inode *root;
117
        struct dentry *root_dentry;
118
 
119
        sb->s_blocksize = PAGE_CACHE_SIZE;
120
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
121
        sb->s_magic = IBMASMFS_MAGIC;
122
        sb->s_op = &ibmasmfs_s_ops;
123
        sb->s_time_gran = 1;
124
 
125
        root = ibmasmfs_make_inode (sb, S_IFDIR | 0500);
126
        if (!root)
127
                return -ENOMEM;
128
 
129
        root->i_op = &simple_dir_inode_operations;
130
        root->i_fop = ibmasmfs_dir_ops;
131
 
132
        root_dentry = d_alloc_root(root);
133
        if (!root_dentry) {
134
                iput(root);
135
                return -ENOMEM;
136
        }
137
        sb->s_root = root_dentry;
138
 
139
        ibmasmfs_create_files(sb, root_dentry);
140
        return 0;
141
}
142
 
143
static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
144
{
145
        struct inode *ret = new_inode(sb);
146
 
147
        if (ret) {
148
                ret->i_mode = mode;
149
                ret->i_uid = ret->i_gid = 0;
150
                ret->i_blocks = 0;
151
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
152
        }
153
        return ret;
154
}
155
 
156
static struct dentry *ibmasmfs_create_file (struct super_block *sb,
157
                        struct dentry *parent,
158
                        const char *name,
159
                        const struct file_operations *fops,
160
                        void *data,
161
                        int mode)
162
{
163
        struct dentry *dentry;
164
        struct inode *inode;
165
 
166
        dentry = d_alloc_name(parent, name);
167
        if (!dentry)
168
                return NULL;
169
 
170
        inode = ibmasmfs_make_inode(sb, S_IFREG | mode);
171
        if (!inode) {
172
                dput(dentry);
173
                return NULL;
174
        }
175
 
176
        inode->i_fop = fops;
177
        inode->i_private = data;
178
 
179
        d_add(dentry, inode);
180
        return dentry;
181
}
182
 
183
static struct dentry *ibmasmfs_create_dir (struct super_block *sb,
184
                                struct dentry *parent,
185
                                const char *name)
186
{
187
        struct dentry *dentry;
188
        struct inode *inode;
189
 
190
        dentry = d_alloc_name(parent, name);
191
        if (!dentry)
192
                return NULL;
193
 
194
        inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500);
195
        if (!inode) {
196
                dput(dentry);
197
                return NULL;
198
        }
199
 
200
        inode->i_op = &simple_dir_inode_operations;
201
        inode->i_fop = ibmasmfs_dir_ops;
202
 
203
        d_add(dentry, inode);
204
        return dentry;
205
}
206
 
207
int ibmasmfs_register(void)
208
{
209
        return register_filesystem(&ibmasmfs_type);
210
}
211
 
212
void ibmasmfs_unregister(void)
213
{
214
        unregister_filesystem(&ibmasmfs_type);
215
}
216
 
217
void ibmasmfs_add_sp(struct service_processor *sp)
218
{
219
        list_add(&sp->node, &service_processors);
220
}
221
 
222
/* struct to save state between command file operations */
223
struct ibmasmfs_command_data {
224
        struct service_processor        *sp;
225
        struct command                  *command;
226
};
227
 
228
/* struct to save state between event file operations */
229
struct ibmasmfs_event_data {
230
        struct service_processor        *sp;
231
        struct event_reader             reader;
232
        int                             active;
233
};
234
 
235
/* struct to save state between reverse heartbeat file operations */
236
struct ibmasmfs_heartbeat_data {
237
        struct service_processor        *sp;
238
        struct reverse_heartbeat        heartbeat;
239
        int                             active;
240
};
241
 
242
static int command_file_open(struct inode *inode, struct file *file)
243
{
244
        struct ibmasmfs_command_data *command_data;
245
 
246
        if (!inode->i_private)
247
                return -ENODEV;
248
 
249
        command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
250
        if (!command_data)
251
                return -ENOMEM;
252
 
253
        command_data->command = NULL;
254
        command_data->sp = inode->i_private;
255
        file->private_data = command_data;
256
        return 0;
257
}
258
 
259
static int command_file_close(struct inode *inode, struct file *file)
260
{
261
        struct ibmasmfs_command_data *command_data = file->private_data;
262
 
263
        if (command_data->command)
264
                command_put(command_data->command);
265
 
266
        kfree(command_data);
267
        return 0;
268
}
269
 
270
static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
271
{
272
        struct ibmasmfs_command_data *command_data = file->private_data;
273
        struct command *cmd;
274
        int len;
275
        unsigned long flags;
276
 
277
        if (*offset < 0)
278
                return -EINVAL;
279
        if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
280
                return 0;
281
        if (*offset != 0)
282
                return 0;
283
 
284
        spin_lock_irqsave(&command_data->sp->lock, flags);
285
        cmd = command_data->command;
286
        if (cmd == NULL) {
287
                spin_unlock_irqrestore(&command_data->sp->lock, flags);
288
                return 0;
289
        }
290
        command_data->command = NULL;
291
        spin_unlock_irqrestore(&command_data->sp->lock, flags);
292
 
293
        if (cmd->status != IBMASM_CMD_COMPLETE) {
294
                command_put(cmd);
295
                return -EIO;
296
        }
297
        len = min(count, cmd->buffer_size);
298
        if (copy_to_user(buf, cmd->buffer, len)) {
299
                command_put(cmd);
300
                return -EFAULT;
301
        }
302
        command_put(cmd);
303
 
304
        return len;
305
}
306
 
307
static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
308
{
309
        struct ibmasmfs_command_data *command_data = file->private_data;
310
        struct command *cmd;
311
        unsigned long flags;
312
 
313
        if (*offset < 0)
314
                return -EINVAL;
315
        if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
316
                return 0;
317
        if (*offset != 0)
318
                return 0;
319
 
320
        /* commands are executed sequentially, only one command at a time */
321
        if (command_data->command)
322
                return -EAGAIN;
323
 
324
        cmd = ibmasm_new_command(command_data->sp, count);
325
        if (!cmd)
326
                return -ENOMEM;
327
 
328
        if (copy_from_user(cmd->buffer, ubuff, count)) {
329
                command_put(cmd);
330
                return -EFAULT;
331
        }
332
 
333
        spin_lock_irqsave(&command_data->sp->lock, flags);
334
        if (command_data->command) {
335
                spin_unlock_irqrestore(&command_data->sp->lock, flags);
336
                command_put(cmd);
337
                return -EAGAIN;
338
        }
339
        command_data->command = cmd;
340
        spin_unlock_irqrestore(&command_data->sp->lock, flags);
341
 
342
        ibmasm_exec_command(command_data->sp, cmd);
343
        ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer));
344
 
345
        return count;
346
}
347
 
348
static int event_file_open(struct inode *inode, struct file *file)
349
{
350
        struct ibmasmfs_event_data *event_data;
351
        struct service_processor *sp;
352
 
353
        if (!inode->i_private)
354
                return -ENODEV;
355
 
356
        sp = inode->i_private;
357
 
358
        event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
359
        if (!event_data)
360
                return -ENOMEM;
361
 
362
        ibmasm_event_reader_register(sp, &event_data->reader);
363
 
364
        event_data->sp = sp;
365
        event_data->active = 0;
366
        file->private_data = event_data;
367
        return 0;
368
}
369
 
370
static int event_file_close(struct inode *inode, struct file *file)
371
{
372
        struct ibmasmfs_event_data *event_data = file->private_data;
373
 
374
        ibmasm_event_reader_unregister(event_data->sp, &event_data->reader);
375
        kfree(event_data);
376
        return 0;
377
}
378
 
379
static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
380
{
381
        struct ibmasmfs_event_data *event_data = file->private_data;
382
        struct event_reader *reader = &event_data->reader;
383
        struct service_processor *sp = event_data->sp;
384
        int ret;
385
        unsigned long flags;
386
 
387
        if (*offset < 0)
388
                return -EINVAL;
389
        if (count == 0 || count > IBMASM_EVENT_MAX_SIZE)
390
                return 0;
391
        if (*offset != 0)
392
                return 0;
393
 
394
        spin_lock_irqsave(&sp->lock, flags);
395
        if (event_data->active) {
396
                spin_unlock_irqrestore(&sp->lock, flags);
397
                return -EBUSY;
398
        }
399
        event_data->active = 1;
400
        spin_unlock_irqrestore(&sp->lock, flags);
401
 
402
        ret = ibmasm_get_next_event(sp, reader);
403
        if (ret <= 0)
404
                goto out;
405
 
406
        if (count < reader->data_size) {
407
                ret = -EINVAL;
408
                goto out;
409
        }
410
 
411
        if (copy_to_user(buf, reader->data, reader->data_size)) {
412
                ret = -EFAULT;
413
                goto out;
414
        }
415
        ret = reader->data_size;
416
 
417
out:
418
        event_data->active = 0;
419
        return ret;
420
}
421
 
422
static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
423
{
424
        struct ibmasmfs_event_data *event_data = file->private_data;
425
 
426
        if (*offset < 0)
427
                return -EINVAL;
428
        if (count != 1)
429
                return 0;
430
        if (*offset != 0)
431
                return 0;
432
 
433
        ibmasm_cancel_next_event(&event_data->reader);
434
        return 0;
435
}
436
 
437
static int r_heartbeat_file_open(struct inode *inode, struct file *file)
438
{
439
        struct ibmasmfs_heartbeat_data *rhbeat;
440
 
441
        if (!inode->i_private)
442
                return -ENODEV;
443
 
444
        rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
445
        if (!rhbeat)
446
                return -ENOMEM;
447
 
448
        rhbeat->sp = inode->i_private;
449
        rhbeat->active = 0;
450
        ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
451
        file->private_data = rhbeat;
452
        return 0;
453
}
454
 
455
static int r_heartbeat_file_close(struct inode *inode, struct file *file)
456
{
457
        struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
458
 
459
        kfree(rhbeat);
460
        return 0;
461
}
462
 
463
static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
464
{
465
        struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
466
        unsigned long flags;
467
        int result;
468
 
469
        if (*offset < 0)
470
                return -EINVAL;
471
        if (count == 0 || count > 1024)
472
                return 0;
473
        if (*offset != 0)
474
                return 0;
475
 
476
        /* allow only one reverse heartbeat per process */
477
        spin_lock_irqsave(&rhbeat->sp->lock, flags);
478
        if (rhbeat->active) {
479
                spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
480
                return -EBUSY;
481
        }
482
        rhbeat->active = 1;
483
        spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
484
 
485
        result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
486
        rhbeat->active = 0;
487
 
488
        return result;
489
}
490
 
491
static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
492
{
493
        struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
494
 
495
        if (*offset < 0)
496
                return -EINVAL;
497
        if (count != 1)
498
                return 0;
499
        if (*offset != 0)
500
                return 0;
501
 
502
        if (rhbeat->active)
503
                ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat);
504
 
505
        return 1;
506
}
507
 
508
static int remote_settings_file_open(struct inode *inode, struct file *file)
509
{
510
        file->private_data = inode->i_private;
511
        return 0;
512
}
513
 
514
static int remote_settings_file_close(struct inode *inode, struct file *file)
515
{
516
        return 0;
517
}
518
 
519
static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
520
{
521
        void __iomem *address = (void __iomem *)file->private_data;
522
        unsigned char *page;
523
        int retval;
524
        int len = 0;
525
        unsigned int value;
526
 
527
        if (*offset < 0)
528
                return -EINVAL;
529
        if (count == 0 || count > 1024)
530
                return 0;
531
        if (*offset != 0)
532
                return 0;
533
 
534
        page = (unsigned char *)__get_free_page(GFP_KERNEL);
535
        if (!page)
536
                return -ENOMEM;
537
 
538
        value = readl(address);
539
        len = sprintf(page, "%d\n", value);
540
 
541
        if (copy_to_user(buf, page, len)) {
542
                retval = -EFAULT;
543
                goto exit;
544
        }
545
        *offset += len;
546
        retval = len;
547
 
548
exit:
549
        free_page((unsigned long)page);
550
        return retval;
551
}
552
 
553
static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
554
{
555
        void __iomem *address = (void __iomem *)file->private_data;
556
        char *buff;
557
        unsigned int value;
558
 
559
        if (*offset < 0)
560
                return -EINVAL;
561
        if (count == 0 || count > 1024)
562
                return 0;
563
        if (*offset != 0)
564
                return 0;
565
 
566
        buff = kzalloc (count + 1, GFP_KERNEL);
567
        if (!buff)
568
                return -ENOMEM;
569
 
570
 
571
        if (copy_from_user(buff, ubuff, count)) {
572
                kfree(buff);
573
                return -EFAULT;
574
        }
575
 
576
        value = simple_strtoul(buff, NULL, 10);
577
        writel(value, address);
578
        kfree(buff);
579
 
580
        return count;
581
}
582
 
583
static const struct file_operations command_fops = {
584
        .open =         command_file_open,
585
        .release =      command_file_close,
586
        .read =         command_file_read,
587
        .write =        command_file_write,
588
};
589
 
590
static const struct file_operations event_fops = {
591
        .open =         event_file_open,
592
        .release =      event_file_close,
593
        .read =         event_file_read,
594
        .write =        event_file_write,
595
};
596
 
597
static const struct file_operations r_heartbeat_fops = {
598
        .open =         r_heartbeat_file_open,
599
        .release =      r_heartbeat_file_close,
600
        .read =         r_heartbeat_file_read,
601
        .write =        r_heartbeat_file_write,
602
};
603
 
604
static const struct file_operations remote_settings_fops = {
605
        .open =         remote_settings_file_open,
606
        .release =      remote_settings_file_close,
607
        .read =         remote_settings_file_read,
608
        .write =        remote_settings_file_write,
609
};
610
 
611
 
612
static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
613
{
614
        struct list_head *entry;
615
        struct service_processor *sp;
616
 
617
        list_for_each(entry, &service_processors) {
618
                struct dentry *dir;
619
                struct dentry *remote_dir;
620
                sp = list_entry(entry, struct service_processor, node);
621
                dir = ibmasmfs_create_dir(sb, root, sp->dirname);
622
                if (!dir)
623
                        continue;
624
 
625
                ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR);
626
                ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR);
627
                ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR);
628
 
629
                remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video");
630
                if (!remote_dir)
631
                        continue;
632
 
633
                ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
634
                ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
635
                ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
636
        }
637
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.