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 * | |-- connected 41 * | |-- depth 42 * | |-- events 43 * | |-- height 44 * | `-- width 45 * . 46 * . 47 * . 48 * `-- n 49 * |-- command 50 * |-- event 51 * |-- reverse_heartbeat 52 * `-- remote_video 53 * |-- connected 54 * |-- depth 55 * |-- events 56 * |-- height 57 * `-- width 58 * 59 * For each service processor the following files are created: 60 * 61 * command: execute dot commands 62 * write: execute a dot command on the service processor 63 * read: return the result of a previously executed dot command 64 * 65 * events: listen for service processor events 66 * read: sleep (interruptible) until an event occurs 67 * write: wakeup sleeping event listener 68 * 69 * reverse_heartbeat: send a heartbeat to the service processor 70 * read: sleep (interruptible) until the reverse heartbeat fails 71 * write: wakeup sleeping heartbeat listener 72 * 73 * remote_video/width 74 * remote_video/height 75 * remote_video/width: control remote display settings 76 * write: set value 77 * read: read value 78 * 79 * remote_video/connected 80 * read: return "1" if web browser VNC java applet is connected, 81 * "0" otherwise 82 * 83 * remote_video/events 84 * read: sleep until a remote mouse or keyboard event occurs, then return 85 * then event. 86 */ 87 88 #include <linux/fs.h> 89 #include <linux/pagemap.h> 90 #include <asm/uaccess.h> 91 #include <asm/io.h> 92 #include "ibmasm.h" 93 #include "remote.h" 94 #include "dot_command.h" 95 96 #define IBMASMFS_MAGIC 0x66726f67 97 98 static LIST_HEAD(service_processors); 99 100 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode); 101 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); 102 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); 103 104 105 static struct super_block *ibmasmfs_get_super(struct file_system_type *fst, 106 int flags, const char *name, void *data) 107 { 108 return get_sb_single(fst, flags, data, ibmasmfs_fill_super); 109 } 110 111 static struct super_operations ibmasmfs_s_ops = { 112 .statfs = simple_statfs, 113 .drop_inode = generic_delete_inode, 114 }; 115 116 static struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations; 117 118 static struct file_system_type ibmasmfs_type = { 119 .owner = THIS_MODULE, 120 .name = "ibmasmfs", 121 .get_sb = ibmasmfs_get_super, 122 .kill_sb = kill_litter_super, 123 }; 124 125 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent) 126 { 127 struct inode *root; 128 struct dentry *root_dentry; 129 130 sb->s_blocksize = PAGE_CACHE_SIZE; 131 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 132 sb->s_magic = IBMASMFS_MAGIC; 133 sb->s_op = &ibmasmfs_s_ops; 134 sb->s_time_gran = 1; 135 136 root = ibmasmfs_make_inode (sb, S_IFDIR | 0500); 137 if (!root) 138 return -ENOMEM; 139 140 root->i_op = &simple_dir_inode_operations; 141 root->i_fop = ibmasmfs_dir_ops; 142 143 root_dentry = d_alloc_root(root); 144 if (!root_dentry) { 145 iput(root); 146 return -ENOMEM; 147 } 148 sb->s_root = root_dentry; 149 150 ibmasmfs_create_files(sb, root_dentry); 151 return 0; 152 } 153 154 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode) 155 { 156 struct inode *ret = new_inode(sb); 157 158 if (ret) { 159 ret->i_mode = mode; 160 ret->i_uid = ret->i_gid = 0; 161 ret->i_blksize = PAGE_CACHE_SIZE; 162 ret->i_blocks = 0; 163 ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; 164 } 165 return ret; 166 } 167 168 static struct dentry *ibmasmfs_create_file (struct super_block *sb, 169 struct dentry *parent, 170 const char *name, 171 struct file_operations *fops, 172 void *data, 173 int mode) 174 { 175 struct dentry *dentry; 176 struct inode *inode; 177 178 dentry = d_alloc_name(parent, name); 179 if (!dentry) 180 return NULL; 181 182 inode = ibmasmfs_make_inode(sb, S_IFREG | mode); 183 if (!inode) { 184 dput(dentry); 185 return NULL; 186 } 187 188 inode->i_fop = fops; 189 inode->u.generic_ip = data; 190 191 d_add(dentry, inode); 192 return dentry; 193 } 194 195 static struct dentry *ibmasmfs_create_dir (struct super_block *sb, 196 struct dentry *parent, 197 const char *name) 198 { 199 struct dentry *dentry; 200 struct inode *inode; 201 202 dentry = d_alloc_name(parent, name); 203 if (!dentry) 204 return NULL; 205 206 inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500); 207 if (!inode) { 208 dput(dentry); 209 return NULL; 210 } 211 212 inode->i_op = &simple_dir_inode_operations; 213 inode->i_fop = ibmasmfs_dir_ops; 214 215 d_add(dentry, inode); 216 return dentry; 217 } 218 219 int ibmasmfs_register(void) 220 { 221 return register_filesystem(&ibmasmfs_type); 222 } 223 224 void ibmasmfs_unregister(void) 225 { 226 unregister_filesystem(&ibmasmfs_type); 227 } 228 229 void ibmasmfs_add_sp(struct service_processor *sp) 230 { 231 list_add(&sp->node, &service_processors); 232 } 233 234 /* struct to save state between command file operations */ 235 struct ibmasmfs_command_data { 236 struct service_processor *sp; 237 struct command *command; 238 }; 239 240 /* struct to save state between event file operations */ 241 struct ibmasmfs_event_data { 242 struct service_processor *sp; 243 struct event_reader reader; 244 int active; 245 }; 246 247 /* struct to save state between reverse heartbeat file operations */ 248 struct ibmasmfs_heartbeat_data { 249 struct service_processor *sp; 250 struct reverse_heartbeat heartbeat; 251 int active; 252 }; 253 254 static int command_file_open(struct inode *inode, struct file *file) 255 { 256 struct ibmasmfs_command_data *command_data; 257 258 if (!inode->u.generic_ip) 259 return -ENODEV; 260 261 command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL); 262 if (!command_data) 263 return -ENOMEM; 264 265 command_data->command = NULL; 266 command_data->sp = inode->u.generic_ip; 267 file->private_data = command_data; 268 return 0; 269 } 270 271 static int command_file_close(struct inode *inode, struct file *file) 272 { 273 struct ibmasmfs_command_data *command_data = file->private_data; 274 275 if (command_data->command) 276 command_put(command_data->command); 277 278 kfree(command_data); 279 return 0; 280 } 281 282 static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 283 { 284 struct ibmasmfs_command_data *command_data = file->private_data; 285 struct command *cmd; 286 int len; 287 unsigned long flags; 288 289 if (*offset < 0) 290 return -EINVAL; 291 if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE) 292 return 0; 293 if (*offset != 0) 294 return 0; 295 296 spin_lock_irqsave(&command_data->sp->lock, flags); 297 cmd = command_data->command; 298 if (cmd == NULL) { 299 spin_unlock_irqrestore(&command_data->sp->lock, flags); 300 return 0; 301 } 302 command_data->command = NULL; 303 spin_unlock_irqrestore(&command_data->sp->lock, flags); 304 305 if (cmd->status != IBMASM_CMD_COMPLETE) { 306 command_put(cmd); 307 return -EIO; 308 } 309 len = min(count, cmd->buffer_size); 310 if (copy_to_user(buf, cmd->buffer, len)) { 311 command_put(cmd); 312 return -EFAULT; 313 } 314 command_put(cmd); 315 316 return len; 317 } 318 319 static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) 320 { 321 struct ibmasmfs_command_data *command_data = file->private_data; 322 struct command *cmd; 323 unsigned long flags; 324 325 if (*offset < 0) 326 return -EINVAL; 327 if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE) 328 return 0; 329 if (*offset != 0) 330 return 0; 331 332 /* commands are executed sequentially, only one command at a time */ 333 if (command_data->command) 334 return -EAGAIN; 335 336 cmd = ibmasm_new_command(count); 337 if (!cmd) 338 return -ENOMEM; 339 340 if (copy_from_user(cmd->buffer, ubuff, count)) { 341 command_put(cmd); 342 return -EFAULT; 343 } 344 345 spin_lock_irqsave(&command_data->sp->lock, flags); 346 if (command_data->command) { 347 spin_unlock_irqrestore(&command_data->sp->lock, flags); 348 command_put(cmd); 349 return -EAGAIN; 350 } 351 command_data->command = cmd; 352 spin_unlock_irqrestore(&command_data->sp->lock, flags); 353 354 ibmasm_exec_command(command_data->sp, cmd); 355 ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer)); 356 357 return count; 358 } 359 360 static int event_file_open(struct inode *inode, struct file *file) 361 { 362 struct ibmasmfs_event_data *event_data; 363 struct service_processor *sp; 364 365 if (!inode->u.generic_ip) 366 return -ENODEV; 367 368 sp = inode->u.generic_ip; 369 370 event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL); 371 if (!event_data) 372 return -ENOMEM; 373 374 ibmasm_event_reader_register(sp, &event_data->reader); 375 376 event_data->sp = sp; 377 file->private_data = event_data; 378 return 0; 379 } 380 381 static int event_file_close(struct inode *inode, struct file *file) 382 { 383 struct ibmasmfs_event_data *event_data = file->private_data; 384 385 ibmasm_event_reader_unregister(event_data->sp, &event_data->reader); 386 kfree(event_data); 387 return 0; 388 } 389 390 static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 391 { 392 struct ibmasmfs_event_data *event_data = file->private_data; 393 struct event_reader *reader = &event_data->reader; 394 int ret; 395 396 if (*offset < 0) 397 return -EINVAL; 398 if (count == 0 || count > IBMASM_EVENT_MAX_SIZE) 399 return 0; 400 if (*offset != 0) 401 return 0; 402 403 ret = ibmasm_get_next_event(event_data->sp, reader); 404 if (ret <= 0) 405 return ret; 406 407 if (count < reader->data_size) 408 return -EINVAL; 409 410 if (copy_to_user(buf, reader->data, reader->data_size)) 411 return -EFAULT; 412 413 return reader->data_size; 414 } 415 416 static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) 417 { 418 struct ibmasmfs_event_data *event_data = file->private_data; 419 420 if (*offset < 0) 421 return -EINVAL; 422 if (count != 1) 423 return 0; 424 if (*offset != 0) 425 return 0; 426 427 wake_up_interruptible(&event_data->reader.wait); 428 return 0; 429 } 430 431 static int r_heartbeat_file_open(struct inode *inode, struct file *file) 432 { 433 struct ibmasmfs_heartbeat_data *rhbeat; 434 435 if (!inode->u.generic_ip) 436 return -ENODEV; 437 438 rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL); 439 if (!rhbeat) 440 return -ENOMEM; 441 442 rhbeat->sp = (struct service_processor *)inode->u.generic_ip; 443 rhbeat->active = 0; 444 ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat); 445 file->private_data = rhbeat; 446 return 0; 447 } 448 449 static int r_heartbeat_file_close(struct inode *inode, struct file *file) 450 { 451 struct ibmasmfs_heartbeat_data *rhbeat = file->private_data; 452 453 kfree(rhbeat); 454 return 0; 455 } 456 457 static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 458 { 459 struct ibmasmfs_heartbeat_data *rhbeat = file->private_data; 460 unsigned long flags; 461 int result; 462 463 if (*offset < 0) 464 return -EINVAL; 465 if (count == 0 || count > 1024) 466 return 0; 467 if (*offset != 0) 468 return 0; 469 470 /* allow only one reverse heartbeat per process */ 471 spin_lock_irqsave(&rhbeat->sp->lock, flags); 472 if (rhbeat->active) { 473 spin_unlock_irqrestore(&rhbeat->sp->lock, flags); 474 return -EBUSY; 475 } 476 rhbeat->active = 1; 477 spin_unlock_irqrestore(&rhbeat->sp->lock, flags); 478 479 result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat); 480 rhbeat->active = 0; 481 482 return result; 483 } 484 485 static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) 486 { 487 struct ibmasmfs_heartbeat_data *rhbeat = file->private_data; 488 489 if (*offset < 0) 490 return -EINVAL; 491 if (count != 1) 492 return 0; 493 if (*offset != 0) 494 return 0; 495 496 if (rhbeat->active) 497 ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat); 498 499 return 1; 500 } 501 502 static int remote_settings_file_open(struct inode *inode, struct file *file) 503 { 504 file->private_data = inode->u.generic_ip; 505 return 0; 506 } 507 508 static int remote_settings_file_close(struct inode *inode, struct file *file) 509 { 510 return 0; 511 } 512 513 static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 514 { 515 void __iomem *address = (void __iomem *)file->private_data; 516 unsigned char *page; 517 int retval; 518 int len = 0; 519 unsigned int value; 520 521 if (*offset < 0) 522 return -EINVAL; 523 if (count == 0 || count > 1024) 524 return 0; 525 if (*offset != 0) 526 return 0; 527 528 page = (unsigned char *)__get_free_page(GFP_KERNEL); 529 if (!page) 530 return -ENOMEM; 531 532 value = readl(address); 533 len = sprintf(page, "%d\n", value); 534 535 if (copy_to_user(buf, page, len)) { 536 retval = -EFAULT; 537 goto exit; 538 } 539 *offset += len; 540 retval = len; 541 542 exit: 543 free_page((unsigned long)page); 544 return retval; 545 } 546 547 static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) 548 { 549 void __iomem *address = (void __iomem *)file->private_data; 550 char *buff; 551 unsigned int value; 552 553 if (*offset < 0) 554 return -EINVAL; 555 if (count == 0 || count > 1024) 556 return 0; 557 if (*offset != 0) 558 return 0; 559 560 buff = kmalloc (count + 1, GFP_KERNEL); 561 if (!buff) 562 return -ENOMEM; 563 564 memset(buff, 0x0, count + 1); 565 566 if (copy_from_user(buff, ubuff, count)) { 567 kfree(buff); 568 return -EFAULT; 569 } 570 571 value = simple_strtoul(buff, NULL, 10); 572 writel(value, address); 573 kfree(buff); 574 575 return count; 576 } 577 578 static int remote_event_file_open(struct inode *inode, struct file *file) 579 { 580 struct service_processor *sp; 581 unsigned long flags; 582 struct remote_queue *q; 583 584 file->private_data = inode->u.generic_ip; 585 sp = file->private_data; 586 q = &sp->remote_queue; 587 588 /* allow only one event reader */ 589 spin_lock_irqsave(&sp->lock, flags); 590 if (q->open) { 591 spin_unlock_irqrestore(&sp->lock, flags); 592 return -EBUSY; 593 } 594 q->open = 1; 595 spin_unlock_irqrestore(&sp->lock, flags); 596 597 enable_mouse_interrupts(sp); 598 599 return 0; 600 } 601 602 static int remote_event_file_close(struct inode *inode, struct file *file) 603 { 604 struct service_processor *sp = file->private_data; 605 606 disable_mouse_interrupts(sp); 607 wake_up_interruptible(&sp->remote_queue.wait); 608 sp->remote_queue.open = 0; 609 610 return 0; 611 } 612 613 static ssize_t remote_event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 614 { 615 struct service_processor *sp = file->private_data; 616 struct remote_queue *q = &sp->remote_queue; 617 size_t data_size; 618 struct remote_event *reader = q->reader; 619 size_t num_events; 620 621 if (*offset < 0) 622 return -EINVAL; 623 if (count == 0 || count > 1024) 624 return 0; 625 if (*offset != 0) 626 return 0; 627 628 if (wait_event_interruptible(q->wait, q->reader != q->writer)) 629 return -ERESTARTSYS; 630 631 /* only get multiples of struct remote_event */ 632 num_events = min((count/sizeof(struct remote_event)), ibmasm_events_available(q)); 633 if (!num_events) 634 return 0; 635 636 data_size = num_events * sizeof(struct remote_event); 637 638 if (copy_to_user(buf, reader, data_size)) 639 return -EFAULT; 640 641 ibmasm_advance_reader(q, num_events); 642 643 return data_size; 644 } 645 646 647 static struct file_operations command_fops = { 648 .open = command_file_open, 649 .release = command_file_close, 650 .read = command_file_read, 651 .write = command_file_write, 652 }; 653 654 static struct file_operations event_fops = { 655 .open = event_file_open, 656 .release = event_file_close, 657 .read = event_file_read, 658 .write = event_file_write, 659 }; 660 661 static struct file_operations r_heartbeat_fops = { 662 .open = r_heartbeat_file_open, 663 .release = r_heartbeat_file_close, 664 .read = r_heartbeat_file_read, 665 .write = r_heartbeat_file_write, 666 }; 667 668 static struct file_operations remote_settings_fops = { 669 .open = remote_settings_file_open, 670 .release = remote_settings_file_close, 671 .read = remote_settings_file_read, 672 .write = remote_settings_file_write, 673 }; 674 675 static struct file_operations remote_event_fops = { 676 .open = remote_event_file_open, 677 .release = remote_event_file_close, 678 .read = remote_event_file_read, 679 }; 680 681 682 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) 683 { 684 struct list_head *entry; 685 struct service_processor *sp; 686 687 list_for_each(entry, &service_processors) { 688 struct dentry *dir; 689 struct dentry *remote_dir; 690 sp = list_entry(entry, struct service_processor, node); 691 dir = ibmasmfs_create_dir(sb, root, sp->dirname); 692 if (!dir) 693 continue; 694 695 ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR); 696 ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR); 697 ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR); 698 699 remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video"); 700 if (!remote_dir) 701 continue; 702 703 ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR); 704 ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR); 705 ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR); 706 ibmasmfs_create_file(sb, remote_dir, "connected", &remote_settings_fops, (void *)vnc_status(sp), S_IRUSR); 707 ibmasmfs_create_file(sb, remote_dir, "events", &remote_event_fops, (void *)sp, S_IRUSR); 708 } 709 } 710