1 /* 2 * PS3 System Manager. 3 * 4 * Copyright (C) 2007 Sony Computer Entertainment Inc. 5 * Copyright 2007 Sony Corp. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #include <linux/kernel.h> 22 #include <linux/module.h> 23 #include <linux/workqueue.h> 24 #include <linux/reboot.h> 25 26 #include <asm/firmware.h> 27 #include <asm/ps3.h> 28 29 #include "vuart.h" 30 31 MODULE_AUTHOR("Sony Corporation"); 32 MODULE_LICENSE("GPL v2"); 33 MODULE_DESCRIPTION("PS3 System Manager"); 34 35 /** 36 * ps3_sys_manager - PS3 system manager driver. 37 * 38 * The system manager provides an asynchronous system event notification 39 * mechanism for reporting events like thermal alert and button presses to 40 * guests. It also provides support to control system shutdown and startup. 41 * 42 * The actual system manager is implemented as an application running in the 43 * system policy module in lpar_1. Guests communicate with the system manager 44 * through port 2 of the vuart using a simple packet message protocol. 45 * Messages are comprised of a fixed field header followed by a message 46 * specific payload. 47 */ 48 49 /** 50 * struct ps3_sys_manager_header - System manager message header. 51 * @version: Header version, currently 1. 52 * @size: Header size in bytes, curently 16. 53 * @payload_size: Message payload size in bytes. 54 * @service_id: Message type, one of enum ps3_sys_manager_service_id. 55 * @request_tag: Unique number to identify reply. 56 */ 57 58 struct ps3_sys_manager_header { 59 /* version 1 */ 60 u8 version; 61 u8 size; 62 u16 reserved_1; 63 u32 payload_size; 64 u16 service_id; 65 u16 reserved_2; 66 u32 request_tag; 67 }; 68 69 #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 70 static void __maybe_unused _dump_sm_header( 71 const struct ps3_sys_manager_header *h, const char *func, int line) 72 { 73 pr_debug("%s:%d: version: %xh\n", func, line, h->version); 74 pr_debug("%s:%d: size: %xh\n", func, line, h->size); 75 pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 76 pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 77 pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 78 } 79 80 /** 81 * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 82 * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 83 * 84 * Currently all messages received from the system manager are either 85 * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 86 * + 16 bytes payload = 32 bytes). This knowlege is used to simplify 87 * the logic. 88 */ 89 90 enum { 91 PS3_SM_RX_MSG_LEN_MIN = 24, 92 PS3_SM_RX_MSG_LEN_MAX = 32, 93 }; 94 95 /** 96 * enum ps3_sys_manager_service_id - Message header service_id. 97 * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 98 * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 99 * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 100 * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 101 * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 102 * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 103 * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 104 * 105 * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 106 * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 107 * a REQUEST message is sent at the wrong time. 108 */ 109 110 enum ps3_sys_manager_service_id { 111 /* version 1 */ 112 PS3_SM_SERVICE_ID_REQUEST = 1, 113 PS3_SM_SERVICE_ID_RESPONSE = 2, 114 PS3_SM_SERVICE_ID_COMMAND = 3, 115 PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 116 PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 117 PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 118 PS3_SM_SERVICE_ID_SET_ATTR = 8, 119 }; 120 121 /** 122 * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 123 * @PS3_SM_ATTR_POWER: Power button. 124 * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 125 * @PS3_SM_ATTR_THERMAL: Sytem thermal alert. 126 * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 127 * @PS3_SM_ATTR_ALL: Logical OR of all. 128 * 129 * The guest tells the system manager which events it is interested in receiving 130 * notice of by sending the system manager a logical OR of notification 131 * attributes via the ps3_sys_manager_send_attr() routine. 132 */ 133 134 enum ps3_sys_manager_attr { 135 /* version 1 */ 136 PS3_SM_ATTR_POWER = 1, 137 PS3_SM_ATTR_RESET = 2, 138 PS3_SM_ATTR_THERMAL = 4, 139 PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ 140 PS3_SM_ATTR_ALL = 0x0f, 141 }; 142 143 /** 144 * enum ps3_sys_manager_event - External event type, reported by system manager. 145 * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used. 146 * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 147 * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used. 148 * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 149 * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 150 * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 151 */ 152 153 enum ps3_sys_manager_event { 154 /* version 1 */ 155 PS3_SM_EVENT_POWER_PRESSED = 3, 156 PS3_SM_EVENT_POWER_RELEASED = 4, 157 PS3_SM_EVENT_RESET_PRESSED = 5, 158 PS3_SM_EVENT_RESET_RELEASED = 6, 159 PS3_SM_EVENT_THERMAL_ALERT = 7, 160 PS3_SM_EVENT_THERMAL_CLEARED = 8, 161 /* no info on controller events */ 162 }; 163 164 /** 165 * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 166 */ 167 168 enum ps3_sys_manager_next_op { 169 /* version 3 */ 170 PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 171 PS3_SM_NEXT_OP_SYS_REBOOT = 2, 172 PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 173 }; 174 175 /** 176 * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 177 * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR 178 * controller, and bluetooth controller. 179 * @PS3_SM_WAKE_RTC: 180 * @PS3_SM_WAKE_RTC_ERROR: 181 * @PS3_SM_WAKE_P_O_R: Power on reset. 182 * 183 * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 184 * System will always wake from the PS3_SM_WAKE_DEFAULT sources. 185 */ 186 187 enum ps3_sys_manager_wake_source { 188 /* version 3 */ 189 PS3_SM_WAKE_DEFAULT = 0, 190 PS3_SM_WAKE_RTC = 0x00000040, 191 PS3_SM_WAKE_RTC_ERROR = 0x00000080, 192 PS3_SM_WAKE_P_O_R = 0x10000000, 193 }; 194 195 /** 196 * enum ps3_sys_manager_cmd - Command from system manager to guest. 197 * 198 * The guest completes the actions needed, then acks or naks the command via 199 * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 200 * the guest must be fully prepared for a system poweroff prior to acking the 201 * command. 202 */ 203 204 enum ps3_sys_manager_cmd { 205 /* version 1 */ 206 PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 207 }; 208 209 /** 210 * ps3_sm_force_power_off - Poweroff helper. 211 * 212 * A global variable used to force a poweroff when the power button has 213 * been pressed irrespective of how init handles the ctrl_alt_del signal. 214 * 215 */ 216 217 static unsigned int ps3_sm_force_power_off; 218 219 /** 220 * ps3_sys_manager_write - Helper to write a two part message to the vuart. 221 * 222 */ 223 224 static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 225 const struct ps3_sys_manager_header *header, const void *payload) 226 { 227 int result; 228 229 BUG_ON(header->version != 1); 230 BUG_ON(header->size != 16); 231 BUG_ON(header->payload_size != 8 && header->payload_size != 16); 232 BUG_ON(header->service_id > 8); 233 234 result = ps3_vuart_write(dev, header, 235 sizeof(struct ps3_sys_manager_header)); 236 237 if (!result) 238 result = ps3_vuart_write(dev, payload, header->payload_size); 239 240 return result; 241 } 242 243 /** 244 * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 245 * 246 */ 247 248 static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 249 enum ps3_sys_manager_attr attr) 250 { 251 struct ps3_sys_manager_header header; 252 struct { 253 u8 version; 254 u8 reserved_1[3]; 255 u32 attribute; 256 } payload; 257 258 BUILD_BUG_ON(sizeof(payload) != 8); 259 260 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 261 262 memset(&header, 0, sizeof(header)); 263 header.version = 1; 264 header.size = 16; 265 header.payload_size = 16; 266 header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 267 268 memset(&payload, 0, sizeof(payload)); 269 payload.version = 1; 270 payload.attribute = attr; 271 272 return ps3_sys_manager_write(dev, &header, &payload); 273 } 274 275 /** 276 * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 277 * 278 * Tell the system manager what to do after this lpar is destroyed. 279 */ 280 281 static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 282 enum ps3_sys_manager_next_op op, 283 enum ps3_sys_manager_wake_source wake_source) 284 { 285 struct ps3_sys_manager_header header; 286 struct { 287 u8 version; 288 u8 type; 289 u8 gos_id; 290 u8 reserved_1; 291 u32 wake_source; 292 u8 reserved_2[8]; 293 } payload; 294 295 BUILD_BUG_ON(sizeof(payload) != 16); 296 297 dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 298 299 memset(&header, 0, sizeof(header)); 300 header.version = 1; 301 header.size = 16; 302 header.payload_size = 16; 303 header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 304 305 memset(&payload, 0, sizeof(payload)); 306 payload.version = 3; 307 payload.type = op; 308 payload.gos_id = 3; /* other os */ 309 payload.wake_source = wake_source; 310 311 return ps3_sys_manager_write(dev, &header, &payload); 312 } 313 314 /** 315 * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 316 * 317 * The guest sends this message to request an operation or action of the system 318 * manager. The reply is a command message from the system manager. In the 319 * command handler the guest performs the requested operation. The result of 320 * the command is then communicated back to the system manager with a response 321 * message. 322 * 323 * Currently, the only supported request is the 'shutdown self' request. 324 */ 325 326 static int ps3_sys_manager_send_request_shutdown( 327 struct ps3_system_bus_device *dev) 328 { 329 struct ps3_sys_manager_header header; 330 struct { 331 u8 version; 332 u8 type; 333 u8 gos_id; 334 u8 reserved_1[13]; 335 } payload; 336 337 BUILD_BUG_ON(sizeof(payload) != 16); 338 339 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 340 341 memset(&header, 0, sizeof(header)); 342 header.version = 1; 343 header.size = 16; 344 header.payload_size = 16; 345 header.service_id = PS3_SM_SERVICE_ID_REQUEST; 346 347 memset(&payload, 0, sizeof(payload)); 348 payload.version = 1; 349 payload.type = 1; /* shutdown */ 350 payload.gos_id = 0; /* self */ 351 352 return ps3_sys_manager_write(dev, &header, &payload); 353 } 354 355 /** 356 * ps3_sys_manager_send_response - Send a 'response' to the system manager. 357 * @status: zero = success, others fail. 358 * 359 * The guest sends this message to the system manager to acnowledge success or 360 * failure of a command sent by the system manager. 361 */ 362 363 static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 364 u64 status) 365 { 366 struct ps3_sys_manager_header header; 367 struct { 368 u8 version; 369 u8 reserved_1[3]; 370 u8 status; 371 u8 reserved_2[11]; 372 } payload; 373 374 BUILD_BUG_ON(sizeof(payload) != 16); 375 376 dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 377 (status ? "nak" : "ack")); 378 379 memset(&header, 0, sizeof(header)); 380 header.version = 1; 381 header.size = 16; 382 header.payload_size = 16; 383 header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 384 385 memset(&payload, 0, sizeof(payload)); 386 payload.version = 1; 387 payload.status = status; 388 389 return ps3_sys_manager_write(dev, &header, &payload); 390 } 391 392 /** 393 * ps3_sys_manager_handle_event - Second stage event msg handler. 394 * 395 */ 396 397 static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 398 { 399 int result; 400 struct { 401 u8 version; 402 u8 type; 403 u8 reserved_1[2]; 404 u32 value; 405 u8 reserved_2[8]; 406 } event; 407 408 BUILD_BUG_ON(sizeof(event) != 16); 409 410 result = ps3_vuart_read(dev, &event, sizeof(event)); 411 BUG_ON(result && "need to retry here"); 412 413 if (event.version != 1) { 414 dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 415 __func__, __LINE__, event.version); 416 return -EIO; 417 } 418 419 switch (event.type) { 420 case PS3_SM_EVENT_POWER_PRESSED: 421 dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", 422 __func__, __LINE__); 423 ps3_sm_force_power_off = 1; 424 /* 425 * A memory barrier is use here to sync memory since 426 * ps3_sys_manager_final_restart() could be called on 427 * another cpu. 428 */ 429 wmb(); 430 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 431 break; 432 case PS3_SM_EVENT_POWER_RELEASED: 433 dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 434 __func__, __LINE__, event.value); 435 break; 436 case PS3_SM_EVENT_RESET_PRESSED: 437 dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n", 438 __func__, __LINE__); 439 ps3_sm_force_power_off = 0; 440 /* 441 * A memory barrier is use here to sync memory since 442 * ps3_sys_manager_final_restart() could be called on 443 * another cpu. 444 */ 445 wmb(); 446 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 447 break; 448 case PS3_SM_EVENT_RESET_RELEASED: 449 dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 450 __func__, __LINE__, event.value); 451 break; 452 case PS3_SM_EVENT_THERMAL_ALERT: 453 dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 454 __func__, __LINE__, event.value); 455 pr_info("PS3 Thermal Alert Zone %u\n", event.value); 456 break; 457 case PS3_SM_EVENT_THERMAL_CLEARED: 458 dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 459 __func__, __LINE__, event.value); 460 break; 461 default: 462 dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 463 __func__, __LINE__, event.type); 464 return -EIO; 465 } 466 467 return 0; 468 } 469 /** 470 * ps3_sys_manager_handle_cmd - Second stage command msg handler. 471 * 472 * The system manager sends this in reply to a 'request' message from the guest. 473 */ 474 475 static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 476 { 477 int result; 478 struct { 479 u8 version; 480 u8 type; 481 u8 reserved_1[14]; 482 } cmd; 483 484 BUILD_BUG_ON(sizeof(cmd) != 16); 485 486 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 487 488 result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 489 BUG_ON(result && "need to retry here"); 490 491 if (result) 492 return result; 493 494 if (cmd.version != 1) { 495 dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 496 __func__, __LINE__, cmd.version); 497 return -EIO; 498 } 499 500 if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 501 dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 502 __func__, __LINE__, cmd.type); 503 return -EIO; 504 } 505 506 ps3_sys_manager_send_response(dev, 0); 507 return 0; 508 } 509 510 /** 511 * ps3_sys_manager_handle_msg - First stage msg handler. 512 * 513 * Can be called directly to manually poll vuart and pump message handler. 514 */ 515 516 static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 517 { 518 int result; 519 struct ps3_sys_manager_header header; 520 521 result = ps3_vuart_read(dev, &header, 522 sizeof(struct ps3_sys_manager_header)); 523 524 if (result) 525 return result; 526 527 if (header.version != 1) { 528 dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 529 __func__, __LINE__, header.version); 530 dump_sm_header(&header); 531 goto fail_header; 532 } 533 534 BUILD_BUG_ON(sizeof(header) != 16); 535 536 if (header.size != 16 || (header.payload_size != 8 537 && header.payload_size != 16)) { 538 dump_sm_header(&header); 539 BUG(); 540 } 541 542 switch (header.service_id) { 543 case PS3_SM_SERVICE_ID_EXTERN_EVENT: 544 dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 545 return ps3_sys_manager_handle_event(dev); 546 case PS3_SM_SERVICE_ID_COMMAND: 547 dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 548 return ps3_sys_manager_handle_cmd(dev); 549 case PS3_SM_SERVICE_ID_REQUEST_ERROR: 550 dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 551 __LINE__); 552 dump_sm_header(&header); 553 break; 554 default: 555 dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 556 __func__, __LINE__, header.service_id); 557 break; 558 } 559 goto fail_id; 560 561 fail_header: 562 ps3_vuart_clear_rx_bytes(dev, 0); 563 return -EIO; 564 fail_id: 565 ps3_vuart_clear_rx_bytes(dev, header.payload_size); 566 return -EIO; 567 } 568 569 /** 570 * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 571 * 572 * This routine never returns. The routine disables asynchronous vuart reads 573 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 574 * the shutdown command sent from the system manager. Soon after the 575 * acknowledgement is sent the lpar is destroyed by the HV. This routine 576 * should only be called from ps3_power_off() through 577 * ps3_sys_manager_ops.power_off. 578 */ 579 580 static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 581 { 582 BUG_ON(!dev); 583 584 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 585 586 ps3_vuart_cancel_async(dev); 587 588 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 589 PS3_SM_WAKE_DEFAULT); 590 ps3_sys_manager_send_request_shutdown(dev); 591 592 pr_emerg("System Halted, OK to turn off power\n"); 593 594 while (1) 595 ps3_sys_manager_handle_msg(dev); 596 } 597 598 /** 599 * ps3_sys_manager_final_restart - The final platform machine_restart routine. 600 * 601 * This routine never returns. The routine disables asynchronous vuart reads 602 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 603 * the shutdown command sent from the system manager. Soon after the 604 * acknowledgement is sent the lpar is destroyed by the HV. This routine 605 * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 606 */ 607 608 static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 609 { 610 BUG_ON(!dev); 611 612 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 613 614 /* Check if we got here via a power button event. */ 615 616 if (ps3_sm_force_power_off) { 617 dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 618 __func__, __LINE__); 619 ps3_sys_manager_final_power_off(dev); 620 } 621 622 ps3_vuart_cancel_async(dev); 623 624 ps3_sys_manager_send_attr(dev, 0); 625 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, 626 PS3_SM_WAKE_DEFAULT); 627 ps3_sys_manager_send_request_shutdown(dev); 628 629 pr_emerg("System Halted, OK to turn off power\n"); 630 631 while (1) 632 ps3_sys_manager_handle_msg(dev); 633 } 634 635 /** 636 * ps3_sys_manager_work - Asynchronous read handler. 637 * 638 * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 639 */ 640 641 static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 642 { 643 ps3_sys_manager_handle_msg(dev); 644 ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 645 } 646 647 static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 648 { 649 int result; 650 struct ps3_sys_manager_ops ops; 651 652 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 653 654 ops.power_off = ps3_sys_manager_final_power_off; 655 ops.restart = ps3_sys_manager_final_restart; 656 ops.dev = dev; 657 658 /* ps3_sys_manager_register_ops copies ops. */ 659 660 ps3_sys_manager_register_ops(&ops); 661 662 result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 663 BUG_ON(result); 664 665 result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 666 BUG_ON(result); 667 668 return result; 669 } 670 671 static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 672 { 673 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 674 return 0; 675 } 676 677 static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 678 { 679 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 680 } 681 682 static struct ps3_vuart_port_driver ps3_sys_manager = { 683 .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 684 .core.core.name = "ps3_sys_manager", 685 .probe = ps3_sys_manager_probe, 686 .remove = ps3_sys_manager_remove, 687 .shutdown = ps3_sys_manager_shutdown, 688 .work = ps3_sys_manager_work, 689 }; 690 691 static int __init ps3_sys_manager_init(void) 692 { 693 if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 694 return -ENODEV; 695 696 return ps3_vuart_port_driver_register(&ps3_sys_manager); 697 } 698 699 module_init(ps3_sys_manager_init); 700 /* Module remove not supported. */ 701 702 MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); 703