1 /* 2 * Copyright (C) 2006 Sony Computer Entertainment Inc. 3 * Copyright 2006, 2007 Sony Corporation 4 * 5 * AV backend support for PS3 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published 9 * by the Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include <linux/module.h> 22 #include <linux/delay.h> 23 #include <linux/notifier.h> 24 #include <linux/reboot.h> 25 #include <linux/kernel.h> 26 #include <linux/ioctl.h> 27 #include <asm/lv1call.h> 28 #include <asm/ps3av.h> 29 #include <asm/ps3.h> 30 31 #include "vuart.h" 32 33 #define BUFSIZE 4096 /* vuart buf size */ 34 #define PS3AV_BUF_SIZE 512 /* max packet size */ 35 36 static int timeout = 5000; /* in msec ( 5 sec ) */ 37 module_param(timeout, int, 0644); 38 39 static struct ps3av ps3av; 40 41 static struct ps3_vuart_port_device ps3av_dev = { 42 .match_id = PS3_MATCH_ID_AV_SETTINGS 43 }; 44 45 /* color space */ 46 #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 47 #define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8 48 /* format */ 49 #define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8 50 /* aspect */ 51 #define A_N PS3AV_CMD_AV_ASPECT_4_3 52 #define A_W PS3AV_CMD_AV_ASPECT_16_9 53 static const struct avset_video_mode { 54 u32 cs; 55 u32 fmt; 56 u32 vid; 57 u32 aspect; 58 u32 x; 59 u32 y; 60 u32 interlace; 61 u32 freq; 62 } video_mode_table[] = { 63 { 0, }, /* auto */ 64 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60}, 65 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60}, 66 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60}, 67 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60}, 68 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60}, 69 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50}, 70 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50}, 71 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50}, 72 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50}, 73 {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50}, 74 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60}, 75 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60}, 76 { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60}, 77 }; 78 79 /* supported CIDs */ 80 static u32 cmd_table[] = { 81 /* init */ 82 PS3AV_CID_AV_INIT, 83 PS3AV_CID_AV_FIN, 84 PS3AV_CID_VIDEO_INIT, 85 PS3AV_CID_AUDIO_INIT, 86 87 /* set */ 88 PS3AV_CID_AV_ENABLE_EVENT, 89 PS3AV_CID_AV_DISABLE_EVENT, 90 91 PS3AV_CID_AV_VIDEO_CS, 92 PS3AV_CID_AV_VIDEO_MUTE, 93 PS3AV_CID_AV_VIDEO_DISABLE_SIG, 94 PS3AV_CID_AV_AUDIO_PARAM, 95 PS3AV_CID_AV_AUDIO_MUTE, 96 PS3AV_CID_AV_HDMI_MODE, 97 PS3AV_CID_AV_TV_MUTE, 98 99 PS3AV_CID_VIDEO_MODE, 100 PS3AV_CID_VIDEO_FORMAT, 101 PS3AV_CID_VIDEO_PITCH, 102 103 PS3AV_CID_AUDIO_MODE, 104 PS3AV_CID_AUDIO_MUTE, 105 PS3AV_CID_AUDIO_ACTIVE, 106 PS3AV_CID_AUDIO_INACTIVE, 107 PS3AV_CID_AVB_PARAM, 108 109 /* get */ 110 PS3AV_CID_AV_GET_HW_CONF, 111 PS3AV_CID_AV_GET_MONITOR_INFO, 112 113 /* event */ 114 PS3AV_CID_EVENT_UNPLUGGED, 115 PS3AV_CID_EVENT_PLUGGED, 116 PS3AV_CID_EVENT_HDCP_DONE, 117 PS3AV_CID_EVENT_HDCP_FAIL, 118 PS3AV_CID_EVENT_HDCP_AUTH, 119 PS3AV_CID_EVENT_HDCP_ERROR, 120 121 0 122 }; 123 124 #define PS3AV_EVENT_CMD_MASK 0x10000000 125 #define PS3AV_EVENT_ID_MASK 0x0000ffff 126 #define PS3AV_CID_MASK 0xffffffff 127 #define PS3AV_REPLY_BIT 0x80000000 128 129 #define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff) 130 131 static u32 *ps3av_search_cmd_table(u32 cid, u32 mask) 132 { 133 u32 *table; 134 int i; 135 136 table = cmd_table; 137 for (i = 0;; table++, i++) { 138 if ((*table & mask) == (cid & mask)) 139 break; 140 if (*table == 0) 141 return NULL; 142 } 143 return table; 144 } 145 146 static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) 147 { 148 u32 *table; 149 150 if (hdr->cid & PS3AV_EVENT_CMD_MASK) { 151 table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); 152 if (table) 153 dev_dbg(&ps3av_dev.core, 154 "recv event packet cid:%08x port:0x%x size:%d\n", 155 hdr->cid, ps3av_event_get_port_id(hdr->cid), 156 hdr->size); 157 else 158 printk(KERN_ERR 159 "%s: failed event packet, cid:%08x size:%d\n", 160 __FUNCTION__, hdr->cid, hdr->size); 161 return 1; /* receive event packet */ 162 } 163 return 0; 164 } 165 166 static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, 167 struct ps3av_reply_hdr *recv_buf, int write_len, 168 int read_len) 169 { 170 int res; 171 u32 cmd; 172 int event; 173 174 if (!ps3av.available) 175 return -ENODEV; 176 177 /* send pkt */ 178 res = ps3av_vuart_write(ps3av.dev, send_buf, write_len); 179 if (res < 0) { 180 dev_dbg(&ps3av_dev.core, 181 "%s: ps3av_vuart_write() failed (result=%d)\n", 182 __FUNCTION__, res); 183 return res; 184 } 185 186 /* recv pkt */ 187 cmd = send_buf->cid; 188 do { 189 /* read header */ 190 res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE, 191 timeout); 192 if (res != PS3AV_HDR_SIZE) { 193 dev_dbg(&ps3av_dev.core, 194 "%s: ps3av_vuart_read() failed (result=%d)\n", 195 __FUNCTION__, res); 196 return res; 197 } 198 199 /* read body */ 200 res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid, 201 recv_buf->size, timeout); 202 if (res < 0) { 203 dev_dbg(&ps3av_dev.core, 204 "%s: ps3av_vuart_read() failed (result=%d)\n", 205 __FUNCTION__, res); 206 return res; 207 } 208 res += PS3AV_HDR_SIZE; /* total len */ 209 event = ps3av_parse_event_packet(recv_buf); 210 /* ret > 0 event packet */ 211 } while (event); 212 213 if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { 214 dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", 215 __FUNCTION__, recv_buf->cid); 216 return -EINVAL; 217 } 218 219 return 0; 220 } 221 222 static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, 223 const struct ps3av_reply_hdr *recv_buf, 224 int user_buf_size) 225 { 226 int return_len; 227 228 if (recv_buf->version != PS3AV_VERSION) { 229 dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n", 230 recv_buf->version); 231 return -EFAULT; 232 } 233 return_len = recv_buf->size + PS3AV_HDR_SIZE; 234 if (return_len > user_buf_size) 235 return_len = user_buf_size; 236 memcpy(cmd_buf, recv_buf, return_len); 237 return 0; /* success */ 238 } 239 240 void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr) 241 { 242 hdr->version = PS3AV_VERSION; 243 hdr->size = size - PS3AV_HDR_SIZE; 244 hdr->cid = cid; 245 } 246 247 int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, 248 struct ps3av_send_hdr *buf) 249 { 250 int res = 0; 251 union { 252 struct ps3av_reply_hdr reply_hdr; 253 u8 raw[PS3AV_BUF_SIZE]; 254 } recv_buf; 255 256 u32 *table; 257 258 BUG_ON(!ps3av.available); 259 260 if (down_interruptible(&ps3av.sem)) 261 return -ERESTARTSYS; 262 263 table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); 264 BUG_ON(!table); 265 BUG_ON(send_len < PS3AV_HDR_SIZE); 266 BUG_ON(usr_buf_size < send_len); 267 BUG_ON(usr_buf_size > PS3AV_BUF_SIZE); 268 269 /* create header */ 270 ps3av_set_hdr(cid, send_len, buf); 271 272 /* send packet via vuart */ 273 res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len, 274 usr_buf_size); 275 if (res < 0) { 276 printk(KERN_ERR 277 "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", 278 __FUNCTION__, res); 279 goto err; 280 } 281 282 /* process reply packet */ 283 res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr, 284 usr_buf_size); 285 if (res < 0) { 286 printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", 287 __FUNCTION__, res); 288 goto err; 289 } 290 291 up(&ps3av.sem); 292 return 0; 293 294 err: 295 up(&ps3av.sem); 296 printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res); 297 return res; 298 } 299 300 static int ps3av_set_av_video_mute(u32 mute) 301 { 302 int i, num_of_av_port, res; 303 304 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 305 ps3av.av_hw_conf.num_of_avmulti; 306 /* video mute on */ 307 for (i = 0; i < num_of_av_port; i++) { 308 res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute); 309 if (res < 0) 310 return -1; 311 } 312 313 return 0; 314 } 315 316 static int ps3av_set_video_disable_sig(void) 317 { 318 int i, num_of_hdmi_port, num_of_av_port, res; 319 320 num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi; 321 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 322 ps3av.av_hw_conf.num_of_avmulti; 323 324 /* tv mute */ 325 for (i = 0; i < num_of_hdmi_port; i++) { 326 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], 327 PS3AV_CMD_MUTE_ON); 328 if (res < 0) 329 return -1; 330 } 331 msleep(100); 332 333 /* video mute on */ 334 for (i = 0; i < num_of_av_port; i++) { 335 res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]); 336 if (res < 0) 337 return -1; 338 if (i < num_of_hdmi_port) { 339 res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], 340 PS3AV_CMD_MUTE_OFF); 341 if (res < 0) 342 return -1; 343 } 344 } 345 msleep(300); 346 347 return 0; 348 } 349 350 static int ps3av_set_audio_mute(u32 mute) 351 { 352 int i, num_of_av_port, num_of_opt_port, res; 353 354 num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + 355 ps3av.av_hw_conf.num_of_avmulti; 356 num_of_opt_port = ps3av.av_hw_conf.num_of_spdif; 357 358 for (i = 0; i < num_of_av_port; i++) { 359 res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute); 360 if (res < 0) 361 return -1; 362 } 363 for (i = 0; i < num_of_opt_port; i++) { 364 res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute); 365 if (res < 0) 366 return -1; 367 } 368 369 return 0; 370 } 371 372 int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) 373 { 374 struct ps3av_pkt_avb_param avb_param; 375 int i, num_of_audio, vid, res; 376 struct ps3av_pkt_audio_mode audio_mode; 377 u32 len = 0; 378 379 num_of_audio = ps3av.av_hw_conf.num_of_hdmi + 380 ps3av.av_hw_conf.num_of_avmulti + 381 ps3av.av_hw_conf.num_of_spdif; 382 383 avb_param.num_of_video_pkt = 0; 384 avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ 385 avb_param.num_of_av_video_pkt = 0; 386 avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi; 387 388 vid = video_mode_table[ps3av.ps3av_mode].vid; 389 390 /* audio mute */ 391 ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); 392 393 /* audio inactive */ 394 res = ps3av_cmd_audio_active(0, ps3av.audio_port); 395 if (res < 0) 396 dev_dbg(&ps3av_dev.core, 397 "ps3av_cmd_audio_active OFF failed\n"); 398 399 /* audio_pkt */ 400 for (i = 0; i < num_of_audio; i++) { 401 ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs, 402 word_bits, format, source); 403 if (i < ps3av.av_hw_conf.num_of_hdmi) { 404 /* hdmi only */ 405 len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], 406 ps3av.av_port[i], 407 &audio_mode, vid); 408 } 409 /* audio_mode pkt should be sent separately */ 410 res = ps3av_cmd_audio_mode(&audio_mode); 411 if (res < 0) 412 dev_dbg(&ps3av_dev.core, 413 "ps3av_cmd_audio_mode failed, port:%x\n", i); 414 } 415 416 /* send command using avb pkt */ 417 len += offsetof(struct ps3av_pkt_avb_param, buf); 418 res = ps3av_cmd_avb_param(&avb_param, len); 419 if (res < 0) 420 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); 421 422 /* audio mute */ 423 ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); 424 425 /* audio active */ 426 res = ps3av_cmd_audio_active(1, ps3av.audio_port); 427 if (res < 0) 428 dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n"); 429 430 return 0; 431 } 432 433 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode); 434 435 static int ps3av_set_videomode(void) 436 { 437 /* av video mute */ 438 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); 439 440 /* wake up ps3avd to do the actual video mode setting */ 441 up(&ps3av.ping); 442 443 return 0; 444 } 445 446 static void ps3av_set_videomode_cont(u32 id, u32 old_id) 447 { 448 struct ps3av_pkt_avb_param avb_param; 449 int i; 450 u32 len = 0, av_video_cs; 451 const struct avset_video_mode *video_mode; 452 int res; 453 454 video_mode = &video_mode_table[id & PS3AV_MODE_MASK]; 455 456 avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ 457 avb_param.num_of_audio_pkt = 0; 458 avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi + 459 ps3av.av_hw_conf.num_of_avmulti; 460 avb_param.num_of_av_audio_pkt = 0; 461 462 /* video signal off */ 463 ps3av_set_video_disable_sig(); 464 465 /* Retail PS3 product doesn't support this */ 466 if (id & PS3AV_MODE_HDCP_OFF) { 467 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); 468 if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 469 dev_dbg(&ps3av_dev.core, "Not supported\n"); 470 else if (res) 471 dev_dbg(&ps3av_dev.core, 472 "ps3av_cmd_av_hdmi_mode failed\n"); 473 } else if (old_id & PS3AV_MODE_HDCP_OFF) { 474 res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); 475 if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 476 dev_dbg(&ps3av_dev.core, 477 "ps3av_cmd_av_hdmi_mode failed\n"); 478 } 479 480 /* video_pkt */ 481 for (i = 0; i < avb_param.num_of_video_pkt; i++) 482 len += ps3av_cmd_set_video_mode(&avb_param.buf[len], 483 ps3av.head[i], video_mode->vid, 484 video_mode->fmt, id); 485 /* av_video_pkt */ 486 for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { 487 if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB) 488 av_video_cs = RGB8; 489 else 490 av_video_cs = video_mode->cs; 491 #ifndef PS3AV_HDMI_YUV 492 if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || 493 ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) 494 av_video_cs = RGB8; /* use RGB for HDMI */ 495 #endif 496 len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], 497 ps3av.av_port[i], 498 video_mode->vid, av_video_cs, 499 video_mode->aspect, id); 500 } 501 /* send command using avb pkt */ 502 len += offsetof(struct ps3av_pkt_avb_param, buf); 503 res = ps3av_cmd_avb_param(&avb_param, len); 504 if (res == PS3AV_STATUS_NO_SYNC_HEAD) 505 printk(KERN_WARNING 506 "%s: Command failed. Please try your request again. \n", 507 __FUNCTION__); 508 else if (res) 509 dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); 510 511 msleep(1500); 512 /* av video mute */ 513 ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); 514 } 515 516 static int ps3avd(void *p) 517 { 518 struct ps3av *info = p; 519 520 daemonize("ps3avd"); 521 while (1) { 522 down(&info->ping); 523 ps3av_set_videomode_cont(info->ps3av_mode, 524 info->ps3av_mode_old); 525 up(&info->pong); 526 } 527 return 0; 528 } 529 530 static int ps3av_vid2table_id(int vid) 531 { 532 int i; 533 534 for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) 535 if (video_mode_table[i].vid == vid) 536 return i; 537 return -1; 538 } 539 540 static int ps3av_resbit2vid(u32 res_50, u32 res_60) 541 { 542 int vid = -1; 543 544 if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ 545 if (res_50 & PS3AV_RESBIT_1920x1080P) 546 vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; 547 else if (res_50 & PS3AV_RESBIT_1920x1080I) 548 vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; 549 else if (res_50 & PS3AV_RESBIT_1280x720P) 550 vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; 551 else if (res_50 & PS3AV_RESBIT_720x576P) 552 vid = PS3AV_CMD_VIDEO_VID_576P; 553 else 554 vid = -1; 555 } else { 556 if (res_60 & PS3AV_RESBIT_1920x1080P) 557 vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; 558 else if (res_60 & PS3AV_RESBIT_1920x1080I) 559 vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; 560 else if (res_60 & PS3AV_RESBIT_1280x720P) 561 vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; 562 else if (res_60 & PS3AV_RESBIT_720x480P) 563 vid = PS3AV_CMD_VIDEO_VID_480P; 564 else 565 vid = -1; 566 } 567 return vid; 568 } 569 570 static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) 571 { 572 u32 res_50, res_60; 573 int vid = -1; 574 575 if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) 576 return -1; 577 578 /* check native resolution */ 579 res_50 = info->res_50.native & PS3AV_RES_MASK_50; 580 res_60 = info->res_60.native & PS3AV_RES_MASK_60; 581 if (res_50 || res_60) { 582 vid = ps3av_resbit2vid(res_50, res_60); 583 return vid; 584 } 585 586 /* check resolution */ 587 res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; 588 res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; 589 if (res_50 || res_60) { 590 vid = ps3av_resbit2vid(res_50, res_60); 591 return vid; 592 } 593 594 if (ps3av.region & PS3AV_REGION_60) 595 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 596 else 597 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 598 return vid; 599 } 600 601 static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, 602 int boot) 603 { 604 int i, res, vid = -1, dvi = 0, rgb = 0; 605 struct ps3av_pkt_av_get_monitor_info monitor_info; 606 struct ps3av_info_monitor *info; 607 608 /* get vid for hdmi */ 609 for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { 610 res = ps3av_cmd_video_get_monitor_info(&monitor_info, 611 PS3AV_CMD_AVPORT_HDMI_0 + 612 i); 613 if (res < 0) 614 return -1; 615 616 ps3av_cmd_av_monitor_info_dump(&monitor_info); 617 info = &monitor_info.info; 618 /* check DVI */ 619 if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { 620 dvi = PS3AV_MODE_DVI; 621 break; 622 } 623 /* check HDMI */ 624 vid = ps3av_hdmi_get_vid(info); 625 if (vid != -1) { 626 /* got valid vid */ 627 break; 628 } 629 } 630 631 if (dvi) { 632 /* DVI mode */ 633 vid = PS3AV_DEFAULT_DVI_VID; 634 } else if (vid == -1) { 635 /* no HDMI interface or HDMI is off */ 636 if (ps3av.region & PS3AV_REGION_60) 637 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; 638 else 639 vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; 640 if (ps3av.region & PS3AV_REGION_RGB) 641 rgb = PS3AV_MODE_RGB; 642 } else if (boot) { 643 /* HDMI: using DEFAULT HDMI_VID while booting up */ 644 info = &monitor_info.info; 645 if (ps3av.region & PS3AV_REGION_60) { 646 if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 647 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 648 else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 649 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 650 else { 651 /* default */ 652 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 653 } 654 } else { 655 if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) 656 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 657 else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) 658 vid = PS3AV_DEFAULT_HDMI_VID_REG_60; 659 else { 660 /* default */ 661 vid = PS3AV_DEFAULT_HDMI_VID_REG_50; 662 } 663 } 664 } 665 666 return (ps3av_vid2table_id(vid) | dvi | rgb); 667 } 668 669 static int ps3av_get_hw_conf(struct ps3av *ps3av) 670 { 671 int i, j, k, res; 672 673 /* get av_hw_conf */ 674 res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); 675 if (res < 0) 676 return -1; 677 678 ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf); 679 680 for (i = 0; i < PS3AV_HEAD_MAX; i++) 681 ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; 682 for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) 683 ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; 684 for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++) 685 ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; 686 for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++) 687 ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; 688 for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++) 689 ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; 690 691 /* set all audio port */ 692 ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 693 | PS3AV_CMD_AUDIO_PORT_HDMI_1 694 | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 695 | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; 696 697 return 0; 698 } 699 700 /* set mode using id */ 701 int ps3av_set_video_mode(u32 id, int boot) 702 { 703 int size; 704 u32 option; 705 706 size = ARRAY_SIZE(video_mode_table); 707 if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { 708 dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__, 709 id); 710 return -EINVAL; 711 } 712 713 /* auto mode */ 714 option = id & ~PS3AV_MODE_MASK; 715 if ((id & PS3AV_MODE_MASK) == 0) { 716 id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); 717 if (id < 1) { 718 printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__, 719 id); 720 return -EINVAL; 721 } 722 id |= option; 723 } 724 725 /* set videomode */ 726 down(&ps3av.pong); 727 ps3av.ps3av_mode_old = ps3av.ps3av_mode; 728 ps3av.ps3av_mode = id; 729 if (ps3av_set_videomode()) 730 ps3av.ps3av_mode = ps3av.ps3av_mode_old; 731 732 return 0; 733 } 734 735 EXPORT_SYMBOL_GPL(ps3av_set_video_mode); 736 737 int ps3av_set_mode(u32 id, int boot) 738 { 739 int res; 740 741 res = ps3av_set_video_mode(id, boot); 742 if (res) 743 return res; 744 745 res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, 746 PS3AV_CMD_AUDIO_FS_48K, 747 PS3AV_CMD_AUDIO_WORD_BITS_16, 748 PS3AV_CMD_AUDIO_FORMAT_PCM, 749 PS3AV_CMD_AUDIO_SOURCE_SERIAL); 750 if (res) 751 return res; 752 753 return 0; 754 } 755 756 EXPORT_SYMBOL_GPL(ps3av_set_mode); 757 758 int ps3av_get_mode(void) 759 { 760 return ps3av.ps3av_mode; 761 } 762 763 EXPORT_SYMBOL_GPL(ps3av_get_mode); 764 765 int ps3av_get_scanmode(int id) 766 { 767 int size; 768 769 id = id & PS3AV_MODE_MASK; 770 size = ARRAY_SIZE(video_mode_table); 771 if (id > size - 1 || id < 0) { 772 printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); 773 return -EINVAL; 774 } 775 return video_mode_table[id].interlace; 776 } 777 778 EXPORT_SYMBOL_GPL(ps3av_get_scanmode); 779 780 int ps3av_get_refresh_rate(int id) 781 { 782 int size; 783 784 id = id & PS3AV_MODE_MASK; 785 size = ARRAY_SIZE(video_mode_table); 786 if (id > size - 1 || id < 0) { 787 printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); 788 return -EINVAL; 789 } 790 return video_mode_table[id].freq; 791 } 792 793 EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate); 794 795 /* get resolution by video_mode */ 796 int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) 797 { 798 int size; 799 800 id = id & PS3AV_MODE_MASK; 801 size = ARRAY_SIZE(video_mode_table); 802 if (id > size - 1 || id < 0) { 803 printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); 804 return -EINVAL; 805 } 806 *xres = video_mode_table[id].x; 807 *yres = video_mode_table[id].y; 808 return 0; 809 } 810 811 EXPORT_SYMBOL_GPL(ps3av_video_mode2res); 812 813 /* mute */ 814 int ps3av_video_mute(int mute) 815 { 816 return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON 817 : PS3AV_CMD_MUTE_OFF); 818 } 819 820 EXPORT_SYMBOL_GPL(ps3av_video_mute); 821 822 int ps3av_audio_mute(int mute) 823 { 824 return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON 825 : PS3AV_CMD_MUTE_OFF); 826 } 827 828 EXPORT_SYMBOL_GPL(ps3av_audio_mute); 829 830 int ps3av_dev_open(void) 831 { 832 int status = 0; 833 834 mutex_lock(&ps3av.mutex); 835 if (!ps3av.open_count++) { 836 status = lv1_gpu_open(0); 837 if (status) { 838 printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", 839 __FUNCTION__, status); 840 ps3av.open_count--; 841 } 842 } 843 mutex_unlock(&ps3av.mutex); 844 845 return status; 846 } 847 848 EXPORT_SYMBOL_GPL(ps3av_dev_open); 849 850 int ps3av_dev_close(void) 851 { 852 int status = 0; 853 854 mutex_lock(&ps3av.mutex); 855 if (ps3av.open_count <= 0) { 856 printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__); 857 status = -1; 858 } else if (!--ps3av.open_count) { 859 status = lv1_gpu_close(); 860 if (status) 861 printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", 862 __FUNCTION__, status); 863 } 864 mutex_unlock(&ps3av.mutex); 865 866 return status; 867 } 868 869 EXPORT_SYMBOL_GPL(ps3av_dev_close); 870 871 static int ps3av_probe(struct ps3_vuart_port_device *dev) 872 { 873 int res; 874 u32 id; 875 876 dev_dbg(&ps3av_dev.core, "init ...\n"); 877 dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout); 878 879 memset(&ps3av, 0, sizeof(ps3av)); 880 881 init_MUTEX(&ps3av.sem); 882 init_MUTEX_LOCKED(&ps3av.ping); 883 init_MUTEX(&ps3av.pong); 884 mutex_init(&ps3av.mutex); 885 ps3av.ps3av_mode = 0; 886 ps3av.dev = dev; 887 kernel_thread(ps3avd, &ps3av, CLONE_KERNEL); 888 889 ps3av.available = 1; 890 switch (ps3_os_area_get_av_multi_out()) { 891 case PS3_PARAM_AV_MULTI_OUT_NTSC: 892 ps3av.region = PS3AV_REGION_60; 893 break; 894 case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: 895 case PS3_PARAM_AV_MULTI_OUT_SECAM: 896 ps3av.region = PS3AV_REGION_50; 897 break; 898 case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: 899 ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB; 900 break; 901 default: 902 ps3av.region = PS3AV_REGION_60; 903 break; 904 } 905 906 /* init avsetting modules */ 907 res = ps3av_cmd_init(); 908 if (res < 0) 909 printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__, 910 res); 911 912 ps3av_get_hw_conf(&ps3av); 913 id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1); 914 mutex_lock(&ps3av.mutex); 915 ps3av.ps3av_mode = id; 916 mutex_unlock(&ps3av.mutex); 917 918 dev_dbg(&ps3av_dev.core, "init...done\n"); 919 920 return 0; 921 } 922 923 static int ps3av_remove(struct ps3_vuart_port_device *dev) 924 { 925 if (ps3av.available) { 926 ps3av_cmd_fin(); 927 ps3av.available = 0; 928 } 929 930 return 0; 931 } 932 933 static void ps3av_shutdown(struct ps3_vuart_port_device *dev) 934 { 935 ps3av_remove(dev); 936 } 937 938 static struct ps3_vuart_port_driver ps3av_driver = { 939 .match_id = PS3_MATCH_ID_AV_SETTINGS, 940 .core = { 941 .name = "ps3_av", 942 }, 943 .probe = ps3av_probe, 944 .remove = ps3av_remove, 945 .shutdown = ps3av_shutdown, 946 }; 947 948 static int ps3av_module_init(void) 949 { 950 int error = ps3_vuart_port_driver_register(&ps3av_driver); 951 if (error) { 952 printk(KERN_ERR 953 "%s: ps3_vuart_port_driver_register failed %d\n", 954 __FUNCTION__, error); 955 return error; 956 } 957 958 error = ps3_vuart_port_device_register(&ps3av_dev); 959 if (error) 960 printk(KERN_ERR 961 "%s: ps3_vuart_port_device_register failed %d\n", 962 __FUNCTION__, error); 963 964 return error; 965 } 966 967 static void __exit ps3av_module_exit(void) 968 { 969 device_unregister(&ps3av_dev.core); 970 ps3_vuart_port_driver_unregister(&ps3av_driver); 971 } 972 973 subsys_initcall(ps3av_module_init); 974 module_exit(ps3av_module_exit); 975