Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  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 }
638 
  This page was automatically generated by the LXR engine.