162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PS3 AV backend support. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007 Sony Computer Entertainment Inc. 662306a36Sopenharmony_ci * Copyright 2007 Sony Corp. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/notifier.h> 1362306a36Sopenharmony_ci#include <linux/ioctl.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/firmware.h> 1762306a36Sopenharmony_ci#include <asm/ps3av.h> 1862306a36Sopenharmony_ci#include <asm/ps3.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <video/cmdline.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "vuart.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define BUFSIZE 4096 /* vuart buf size */ 2562306a36Sopenharmony_ci#define PS3AV_BUF_SIZE 512 /* max packet size */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int safe_mode; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int timeout = 5000; /* in msec ( 5 sec ) */ 3062306a36Sopenharmony_cimodule_param(timeout, int, 0644); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic struct ps3av { 3362306a36Sopenharmony_ci struct mutex mutex; 3462306a36Sopenharmony_ci struct work_struct work; 3562306a36Sopenharmony_ci struct completion done; 3662306a36Sopenharmony_ci int open_count; 3762306a36Sopenharmony_ci struct ps3_system_bus_device *dev; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci int region; 4062306a36Sopenharmony_ci struct ps3av_pkt_av_get_hw_conf av_hw_conf; 4162306a36Sopenharmony_ci u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; 4262306a36Sopenharmony_ci u32 opt_port[PS3AV_OPT_PORT_MAX]; 4362306a36Sopenharmony_ci u32 head[PS3AV_HEAD_MAX]; 4462306a36Sopenharmony_ci u32 audio_port; 4562306a36Sopenharmony_ci int ps3av_mode; 4662306a36Sopenharmony_ci int ps3av_mode_old; 4762306a36Sopenharmony_ci union { 4862306a36Sopenharmony_ci struct ps3av_reply_hdr reply_hdr; 4962306a36Sopenharmony_ci u8 raw[PS3AV_BUF_SIZE]; 5062306a36Sopenharmony_ci } recv_buf; 5162306a36Sopenharmony_ci} *ps3av; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* color space */ 5462306a36Sopenharmony_ci#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 5562306a36Sopenharmony_ci#define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8 5662306a36Sopenharmony_ci/* format */ 5762306a36Sopenharmony_ci#define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8 5862306a36Sopenharmony_ci/* aspect */ 5962306a36Sopenharmony_ci#define A_N PS3AV_CMD_AV_ASPECT_4_3 6062306a36Sopenharmony_ci#define A_W PS3AV_CMD_AV_ASPECT_16_9 6162306a36Sopenharmony_cistatic const struct avset_video_mode { 6262306a36Sopenharmony_ci u32 cs; 6362306a36Sopenharmony_ci u32 fmt; 6462306a36Sopenharmony_ci u32 vid; 6562306a36Sopenharmony_ci u32 aspect; 6662306a36Sopenharmony_ci u32 x; 6762306a36Sopenharmony_ci u32 y; 6862306a36Sopenharmony_ci} video_mode_table[] = { 6962306a36Sopenharmony_ci { 0, }, /* auto */ 7062306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, 7162306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, 7262306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720}, 7362306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, 7462306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, 7562306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, 7662306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, 7762306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720}, 7862306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, 7962306a36Sopenharmony_ci {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, 8062306a36Sopenharmony_ci { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, 8162306a36Sopenharmony_ci { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024}, 8262306a36Sopenharmony_ci { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200}, 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* supported CIDs */ 8662306a36Sopenharmony_cistatic u32 cmd_table[] = { 8762306a36Sopenharmony_ci /* init */ 8862306a36Sopenharmony_ci PS3AV_CID_AV_INIT, 8962306a36Sopenharmony_ci PS3AV_CID_AV_FIN, 9062306a36Sopenharmony_ci PS3AV_CID_VIDEO_INIT, 9162306a36Sopenharmony_ci PS3AV_CID_AUDIO_INIT, 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* set */ 9462306a36Sopenharmony_ci PS3AV_CID_AV_ENABLE_EVENT, 9562306a36Sopenharmony_ci PS3AV_CID_AV_DISABLE_EVENT, 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci PS3AV_CID_AV_VIDEO_CS, 9862306a36Sopenharmony_ci PS3AV_CID_AV_VIDEO_MUTE, 9962306a36Sopenharmony_ci PS3AV_CID_AV_VIDEO_DISABLE_SIG, 10062306a36Sopenharmony_ci PS3AV_CID_AV_AUDIO_PARAM, 10162306a36Sopenharmony_ci PS3AV_CID_AV_AUDIO_MUTE, 10262306a36Sopenharmony_ci PS3AV_CID_AV_HDMI_MODE, 10362306a36Sopenharmony_ci PS3AV_CID_AV_TV_MUTE, 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci PS3AV_CID_VIDEO_MODE, 10662306a36Sopenharmony_ci PS3AV_CID_VIDEO_FORMAT, 10762306a36Sopenharmony_ci PS3AV_CID_VIDEO_PITCH, 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci PS3AV_CID_AUDIO_MODE, 11062306a36Sopenharmony_ci PS3AV_CID_AUDIO_MUTE, 11162306a36Sopenharmony_ci PS3AV_CID_AUDIO_ACTIVE, 11262306a36Sopenharmony_ci PS3AV_CID_AUDIO_INACTIVE, 11362306a36Sopenharmony_ci PS3AV_CID_AVB_PARAM, 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* get */ 11662306a36Sopenharmony_ci PS3AV_CID_AV_GET_HW_CONF, 11762306a36Sopenharmony_ci PS3AV_CID_AV_GET_MONITOR_INFO, 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* event */ 12062306a36Sopenharmony_ci PS3AV_CID_EVENT_UNPLUGGED, 12162306a36Sopenharmony_ci PS3AV_CID_EVENT_PLUGGED, 12262306a36Sopenharmony_ci PS3AV_CID_EVENT_HDCP_DONE, 12362306a36Sopenharmony_ci PS3AV_CID_EVENT_HDCP_FAIL, 12462306a36Sopenharmony_ci PS3AV_CID_EVENT_HDCP_AUTH, 12562306a36Sopenharmony_ci PS3AV_CID_EVENT_HDCP_ERROR, 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci 0 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define PS3AV_EVENT_CMD_MASK 0x10000000 13162306a36Sopenharmony_ci#define PS3AV_EVENT_ID_MASK 0x0000ffff 13262306a36Sopenharmony_ci#define PS3AV_CID_MASK 0xffffffff 13362306a36Sopenharmony_ci#define PS3AV_REPLY_BIT 0x80000000 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic u32 *ps3av_search_cmd_table(u32 cid, u32 mask) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci u32 *table; 14062306a36Sopenharmony_ci int i; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci table = cmd_table; 14362306a36Sopenharmony_ci for (i = 0;; table++, i++) { 14462306a36Sopenharmony_ci if ((*table & mask) == (cid & mask)) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci if (*table == 0) 14762306a36Sopenharmony_ci return NULL; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci return table; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u32 *table; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (hdr->cid & PS3AV_EVENT_CMD_MASK) { 15762306a36Sopenharmony_ci table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); 15862306a36Sopenharmony_ci if (table) 15962306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 16062306a36Sopenharmony_ci "recv event packet cid:%08x port:0x%x size:%d\n", 16162306a36Sopenharmony_ci hdr->cid, ps3av_event_get_port_id(hdr->cid), 16262306a36Sopenharmony_ci hdr->size); 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci printk(KERN_ERR 16562306a36Sopenharmony_ci "%s: failed event packet, cid:%08x size:%d\n", 16662306a36Sopenharmony_ci __func__, hdr->cid, hdr->size); 16762306a36Sopenharmony_ci return 1; /* receive event packet */ 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define POLLING_INTERVAL 25 /* in msec */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int ps3av_vuart_write(struct ps3_system_bus_device *dev, 17662306a36Sopenharmony_ci const void *buf, unsigned long size) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci int error; 17962306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 18062306a36Sopenharmony_ci error = ps3_vuart_write(dev, buf, size); 18162306a36Sopenharmony_ci dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 18262306a36Sopenharmony_ci return error ? error : size; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int ps3av_vuart_read(struct ps3_system_bus_device *dev, void *buf, 18662306a36Sopenharmony_ci unsigned long size, int timeout) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int error; 18962306a36Sopenharmony_ci int loopcnt = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 19262306a36Sopenharmony_ci timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL; 19362306a36Sopenharmony_ci while (loopcnt++ <= timeout) { 19462306a36Sopenharmony_ci error = ps3_vuart_read(dev, buf, size); 19562306a36Sopenharmony_ci if (!error) 19662306a36Sopenharmony_ci return size; 19762306a36Sopenharmony_ci if (error != -EAGAIN) { 19862306a36Sopenharmony_ci printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", 19962306a36Sopenharmony_ci __func__, error); 20062306a36Sopenharmony_ci return error; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci msleep(POLLING_INTERVAL); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci return -EWOULDBLOCK; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, 20862306a36Sopenharmony_ci struct ps3av_reply_hdr *recv_buf, int write_len, 20962306a36Sopenharmony_ci int read_len) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int res; 21262306a36Sopenharmony_ci u32 cmd; 21362306a36Sopenharmony_ci int event; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!ps3av) 21662306a36Sopenharmony_ci return -ENODEV; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* send pkt */ 21962306a36Sopenharmony_ci res = ps3av_vuart_write(ps3av->dev, send_buf, write_len); 22062306a36Sopenharmony_ci if (res < 0) { 22162306a36Sopenharmony_ci dev_warn(&ps3av->dev->core, 22262306a36Sopenharmony_ci "%s:%d: ps3av_vuart_write() failed: %s\n", __func__, 22362306a36Sopenharmony_ci __LINE__, ps3_result(res)); 22462306a36Sopenharmony_ci return res; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* recv pkt */ 22862306a36Sopenharmony_ci cmd = send_buf->cid; 22962306a36Sopenharmony_ci do { 23062306a36Sopenharmony_ci /* read header */ 23162306a36Sopenharmony_ci res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE, 23262306a36Sopenharmony_ci timeout); 23362306a36Sopenharmony_ci if (res != PS3AV_HDR_SIZE) { 23462306a36Sopenharmony_ci dev_warn(&ps3av->dev->core, 23562306a36Sopenharmony_ci "%s:%d: ps3av_vuart_read() failed: %s\n", __func__, 23662306a36Sopenharmony_ci __LINE__, ps3_result(res)); 23762306a36Sopenharmony_ci return res; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* read body */ 24162306a36Sopenharmony_ci res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid, 24262306a36Sopenharmony_ci recv_buf->size, timeout); 24362306a36Sopenharmony_ci if (res < 0) { 24462306a36Sopenharmony_ci dev_warn(&ps3av->dev->core, 24562306a36Sopenharmony_ci "%s:%d: ps3av_vuart_read() failed: %s\n", __func__, 24662306a36Sopenharmony_ci __LINE__, ps3_result(res)); 24762306a36Sopenharmony_ci return res; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci res += PS3AV_HDR_SIZE; /* total len */ 25062306a36Sopenharmony_ci event = ps3av_parse_event_packet(recv_buf); 25162306a36Sopenharmony_ci /* ret > 0 event packet */ 25262306a36Sopenharmony_ci } while (event); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { 25562306a36Sopenharmony_ci dev_warn(&ps3av->dev->core, "%s:%d: reply err: %x\n", __func__, 25662306a36Sopenharmony_ci __LINE__, recv_buf->cid); 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, 26462306a36Sopenharmony_ci const struct ps3av_reply_hdr *recv_buf, 26562306a36Sopenharmony_ci int user_buf_size) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci int return_len; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (recv_buf->version != PS3AV_VERSION) { 27062306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, "reply_packet invalid version:%x\n", 27162306a36Sopenharmony_ci recv_buf->version); 27262306a36Sopenharmony_ci return -EFAULT; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci return_len = recv_buf->size + PS3AV_HDR_SIZE; 27562306a36Sopenharmony_ci if (return_len > user_buf_size) 27662306a36Sopenharmony_ci return_len = user_buf_size; 27762306a36Sopenharmony_ci memcpy(cmd_buf, recv_buf, return_len); 27862306a36Sopenharmony_ci return 0; /* success */ 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_civoid ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci hdr->version = PS3AV_VERSION; 28462306a36Sopenharmony_ci hdr->size = size - PS3AV_HDR_SIZE; 28562306a36Sopenharmony_ci hdr->cid = cid; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciint ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, 28962306a36Sopenharmony_ci struct ps3av_send_hdr *buf) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci int res = 0; 29262306a36Sopenharmony_ci u32 *table; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci BUG_ON(!ps3av); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mutex_lock(&ps3av->mutex); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); 29962306a36Sopenharmony_ci BUG_ON(!table); 30062306a36Sopenharmony_ci BUG_ON(send_len < PS3AV_HDR_SIZE); 30162306a36Sopenharmony_ci BUG_ON(usr_buf_size < send_len); 30262306a36Sopenharmony_ci BUG_ON(usr_buf_size > PS3AV_BUF_SIZE); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* create header */ 30562306a36Sopenharmony_ci ps3av_set_hdr(cid, send_len, buf); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* send packet via vuart */ 30862306a36Sopenharmony_ci res = ps3av_send_cmd_pkt(buf, &ps3av->recv_buf.reply_hdr, send_len, 30962306a36Sopenharmony_ci usr_buf_size); 31062306a36Sopenharmony_ci if (res < 0) { 31162306a36Sopenharmony_ci printk(KERN_ERR 31262306a36Sopenharmony_ci "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", 31362306a36Sopenharmony_ci __func__, res); 31462306a36Sopenharmony_ci goto err; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* process reply packet */ 31862306a36Sopenharmony_ci res = ps3av_process_reply_packet(buf, &ps3av->recv_buf.reply_hdr, 31962306a36Sopenharmony_ci usr_buf_size); 32062306a36Sopenharmony_ci if (res < 0) { 32162306a36Sopenharmony_ci printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", 32262306a36Sopenharmony_ci __func__, res); 32362306a36Sopenharmony_ci goto err; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mutex_unlock(&ps3av->mutex); 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cierr: 33062306a36Sopenharmony_ci mutex_unlock(&ps3av->mutex); 33162306a36Sopenharmony_ci printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); 33262306a36Sopenharmony_ci return res; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int ps3av_set_av_video_mute(u32 mute) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int i, num_of_av_port, res; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 34062306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_avmulti; 34162306a36Sopenharmony_ci /* video mute on */ 34262306a36Sopenharmony_ci for (i = 0; i < num_of_av_port; i++) { 34362306a36Sopenharmony_ci res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute); 34462306a36Sopenharmony_ci if (res < 0) 34562306a36Sopenharmony_ci return -1; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int ps3av_set_video_disable_sig(void) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci int i, num_of_hdmi_port, num_of_av_port, res; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci num_of_hdmi_port = ps3av->av_hw_conf.num_of_hdmi; 35662306a36Sopenharmony_ci num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 35762306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_avmulti; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* tv mute */ 36062306a36Sopenharmony_ci for (i = 0; i < num_of_hdmi_port; i++) { 36162306a36Sopenharmony_ci res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], 36262306a36Sopenharmony_ci PS3AV_CMD_MUTE_ON); 36362306a36Sopenharmony_ci if (res < 0) 36462306a36Sopenharmony_ci return -1; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci msleep(100); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* video mute on */ 36962306a36Sopenharmony_ci for (i = 0; i < num_of_av_port; i++) { 37062306a36Sopenharmony_ci res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]); 37162306a36Sopenharmony_ci if (res < 0) 37262306a36Sopenharmony_ci return -1; 37362306a36Sopenharmony_ci if (i < num_of_hdmi_port) { 37462306a36Sopenharmony_ci res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], 37562306a36Sopenharmony_ci PS3AV_CMD_MUTE_OFF); 37662306a36Sopenharmony_ci if (res < 0) 37762306a36Sopenharmony_ci return -1; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci msleep(300); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int ps3av_set_audio_mute(u32 mute) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci int i, num_of_av_port, num_of_opt_port, res; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + 39062306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_avmulti; 39162306a36Sopenharmony_ci num_of_opt_port = ps3av->av_hw_conf.num_of_spdif; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci for (i = 0; i < num_of_av_port; i++) { 39462306a36Sopenharmony_ci res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute); 39562306a36Sopenharmony_ci if (res < 0) 39662306a36Sopenharmony_ci return -1; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci for (i = 0; i < num_of_opt_port; i++) { 39962306a36Sopenharmony_ci res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute); 40062306a36Sopenharmony_ci if (res < 0) 40162306a36Sopenharmony_ci return -1; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciint ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct ps3av_pkt_avb_param avb_param; 41062306a36Sopenharmony_ci int i, num_of_audio, vid, res; 41162306a36Sopenharmony_ci struct ps3av_pkt_audio_mode audio_mode; 41262306a36Sopenharmony_ci u32 len = 0; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci num_of_audio = ps3av->av_hw_conf.num_of_hdmi + 41562306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_avmulti + 41662306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_spdif; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci avb_param.num_of_video_pkt = 0; 41962306a36Sopenharmony_ci avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ 42062306a36Sopenharmony_ci avb_param.num_of_av_video_pkt = 0; 42162306a36Sopenharmony_ci avb_param.num_of_av_audio_pkt = ps3av->av_hw_conf.num_of_hdmi; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci vid = video_mode_table[ps3av->ps3av_mode].vid; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* audio mute */ 42662306a36Sopenharmony_ci ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* audio inactive */ 42962306a36Sopenharmony_ci res = ps3av_cmd_audio_active(0, ps3av->audio_port); 43062306a36Sopenharmony_ci if (res < 0) 43162306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 43262306a36Sopenharmony_ci "ps3av_cmd_audio_active OFF failed\n"); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* audio_pkt */ 43562306a36Sopenharmony_ci for (i = 0; i < num_of_audio; i++) { 43662306a36Sopenharmony_ci ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch, 43762306a36Sopenharmony_ci fs, word_bits, format, source); 43862306a36Sopenharmony_ci if (i < ps3av->av_hw_conf.num_of_hdmi) { 43962306a36Sopenharmony_ci /* hdmi only */ 44062306a36Sopenharmony_ci len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], 44162306a36Sopenharmony_ci ps3av->av_port[i], 44262306a36Sopenharmony_ci &audio_mode, vid); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci /* audio_mode pkt should be sent separately */ 44562306a36Sopenharmony_ci res = ps3av_cmd_audio_mode(&audio_mode); 44662306a36Sopenharmony_ci if (res < 0) 44762306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 44862306a36Sopenharmony_ci "ps3av_cmd_audio_mode failed, port:%x\n", i); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* send command using avb pkt */ 45262306a36Sopenharmony_ci len += offsetof(struct ps3av_pkt_avb_param, buf); 45362306a36Sopenharmony_ci res = ps3av_cmd_avb_param(&avb_param, len); 45462306a36Sopenharmony_ci if (res < 0) 45562306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* audio mute */ 45862306a36Sopenharmony_ci ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* audio active */ 46162306a36Sopenharmony_ci res = ps3av_cmd_audio_active(1, ps3av->audio_port); 46262306a36Sopenharmony_ci if (res < 0) 46362306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 46462306a36Sopenharmony_ci "ps3av_cmd_audio_active ON failed\n"); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_set_audio_mode); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int ps3av_set_videomode(void) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci /* av video mute */ 47362306a36Sopenharmony_ci ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* wake up ps3avd to do the actual video mode setting */ 47662306a36Sopenharmony_ci schedule_work(&ps3av->work); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic void ps3av_set_videomode_packet(u32 id) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct ps3av_pkt_avb_param avb_param; 48462306a36Sopenharmony_ci unsigned int i; 48562306a36Sopenharmony_ci u32 len = 0, av_video_cs; 48662306a36Sopenharmony_ci const struct avset_video_mode *video_mode; 48762306a36Sopenharmony_ci int res; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci video_mode = &video_mode_table[id & PS3AV_MODE_MASK]; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ 49262306a36Sopenharmony_ci avb_param.num_of_audio_pkt = 0; 49362306a36Sopenharmony_ci avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi + 49462306a36Sopenharmony_ci ps3av->av_hw_conf.num_of_avmulti; 49562306a36Sopenharmony_ci avb_param.num_of_av_audio_pkt = 0; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* video_pkt */ 49862306a36Sopenharmony_ci for (i = 0; i < avb_param.num_of_video_pkt; i++) 49962306a36Sopenharmony_ci len += ps3av_cmd_set_video_mode(&avb_param.buf[len], 50062306a36Sopenharmony_ci ps3av->head[i], video_mode->vid, 50162306a36Sopenharmony_ci video_mode->fmt, id); 50262306a36Sopenharmony_ci /* av_video_pkt */ 50362306a36Sopenharmony_ci for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { 50462306a36Sopenharmony_ci if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB) 50562306a36Sopenharmony_ci av_video_cs = RGB8; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci av_video_cs = video_mode->cs; 50862306a36Sopenharmony_ci#ifndef PS3AV_HDMI_YUV 50962306a36Sopenharmony_ci if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || 51062306a36Sopenharmony_ci ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) 51162306a36Sopenharmony_ci av_video_cs = RGB8; /* use RGB for HDMI */ 51262306a36Sopenharmony_ci#endif 51362306a36Sopenharmony_ci len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], 51462306a36Sopenharmony_ci ps3av->av_port[i], 51562306a36Sopenharmony_ci video_mode->vid, av_video_cs, 51662306a36Sopenharmony_ci video_mode->aspect, id); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci /* send command using avb pkt */ 51962306a36Sopenharmony_ci len += offsetof(struct ps3av_pkt_avb_param, buf); 52062306a36Sopenharmony_ci res = ps3av_cmd_avb_param(&avb_param, len); 52162306a36Sopenharmony_ci if (res == PS3AV_STATUS_NO_SYNC_HEAD) 52262306a36Sopenharmony_ci printk(KERN_WARNING 52362306a36Sopenharmony_ci "%s: Command failed. Please try your request again.\n", 52462306a36Sopenharmony_ci __func__); 52562306a36Sopenharmony_ci else if (res) 52662306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic void ps3av_set_videomode_cont(u32 id, u32 old_id) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci static int vesa; 53262306a36Sopenharmony_ci int res; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* video signal off */ 53562306a36Sopenharmony_ci ps3av_set_video_disable_sig(); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* 53862306a36Sopenharmony_ci * AV backend needs non-VESA mode setting at least one time 53962306a36Sopenharmony_ci * when VESA mode is used. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) { 54262306a36Sopenharmony_ci /* vesa mode */ 54362306a36Sopenharmony_ci ps3av_set_videomode_packet(PS3AV_MODE_480P); 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci vesa = 1; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Retail PS3 product doesn't support this */ 54862306a36Sopenharmony_ci if (id & PS3AV_MODE_HDCP_OFF) { 54962306a36Sopenharmony_ci res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); 55062306a36Sopenharmony_ci if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 55162306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, "Not supported\n"); 55262306a36Sopenharmony_ci else if (res) 55362306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 55462306a36Sopenharmony_ci "ps3av_cmd_av_hdmi_mode failed\n"); 55562306a36Sopenharmony_ci } else if (old_id & PS3AV_MODE_HDCP_OFF) { 55662306a36Sopenharmony_ci res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); 55762306a36Sopenharmony_ci if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) 55862306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, 55962306a36Sopenharmony_ci "ps3av_cmd_av_hdmi_mode failed\n"); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ps3av_set_videomode_packet(id); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci msleep(1500); 56562306a36Sopenharmony_ci /* av video mute */ 56662306a36Sopenharmony_ci ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic void ps3avd(struct work_struct *work) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old); 57262306a36Sopenharmony_ci complete(&ps3av->done); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci#define SHIFT_50 0 57662306a36Sopenharmony_ci#define SHIFT_60 4 57762306a36Sopenharmony_ci#define SHIFT_VESA 8 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic const struct { 58062306a36Sopenharmony_ci unsigned mask:19; 58162306a36Sopenharmony_ci unsigned id:4; 58262306a36Sopenharmony_ci} ps3av_preferred_modes[] = { 58362306a36Sopenharmony_ci { PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA }, 58462306a36Sopenharmony_ci { PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 }, 58562306a36Sopenharmony_ci { PS3AV_RESBIT_1920x1080P << SHIFT_50, PS3AV_MODE_1080P50 }, 58662306a36Sopenharmony_ci { PS3AV_RESBIT_1920x1080I << SHIFT_60, PS3AV_MODE_1080I60 }, 58762306a36Sopenharmony_ci { PS3AV_RESBIT_1920x1080I << SHIFT_50, PS3AV_MODE_1080I50 }, 58862306a36Sopenharmony_ci { PS3AV_RESBIT_SXGA << SHIFT_VESA, PS3AV_MODE_SXGA }, 58962306a36Sopenharmony_ci { PS3AV_RESBIT_WXGA << SHIFT_VESA, PS3AV_MODE_WXGA }, 59062306a36Sopenharmony_ci { PS3AV_RESBIT_1280x720P << SHIFT_60, PS3AV_MODE_720P60 }, 59162306a36Sopenharmony_ci { PS3AV_RESBIT_1280x720P << SHIFT_50, PS3AV_MODE_720P50 }, 59262306a36Sopenharmony_ci { PS3AV_RESBIT_720x480P << SHIFT_60, PS3AV_MODE_480P }, 59362306a36Sopenharmony_ci { PS3AV_RESBIT_720x576P << SHIFT_50, PS3AV_MODE_576P }, 59462306a36Sopenharmony_ci}; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60, 59762306a36Sopenharmony_ci u32 res_vesa) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci unsigned int i; 60062306a36Sopenharmony_ci u32 res_all; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * We mask off the resolution bits we care about and combine the 60462306a36Sopenharmony_ci * results in one bitfield, so make sure there's no overlap 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & 60762306a36Sopenharmony_ci PS3AV_RES_MASK_60 << SHIFT_60); 60862306a36Sopenharmony_ci BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & 60962306a36Sopenharmony_ci PS3AV_RES_MASK_VESA << SHIFT_VESA); 61062306a36Sopenharmony_ci BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 & 61162306a36Sopenharmony_ci PS3AV_RES_MASK_VESA << SHIFT_VESA); 61262306a36Sopenharmony_ci res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 | 61362306a36Sopenharmony_ci (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 | 61462306a36Sopenharmony_ci (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (!res_all) 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++) 62062306a36Sopenharmony_ci if (res_all & ps3av_preferred_modes[i].mask) 62162306a36Sopenharmony_ci return ps3av_preferred_modes[i].id; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci enum ps3av_mode_num id; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (safe_mode) 63162306a36Sopenharmony_ci return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* check native resolution */ 63462306a36Sopenharmony_ci id = ps3av_resbit2id(info->res_50.native, info->res_60.native, 63562306a36Sopenharmony_ci info->res_vesa.native); 63662306a36Sopenharmony_ci if (id) { 63762306a36Sopenharmony_ci pr_debug("%s: Using native mode %d\n", __func__, id); 63862306a36Sopenharmony_ci return id; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* check supported resolutions */ 64262306a36Sopenharmony_ci id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits, 64362306a36Sopenharmony_ci info->res_vesa.res_bits); 64462306a36Sopenharmony_ci if (id) { 64562306a36Sopenharmony_ci pr_debug("%s: Using supported mode %d\n", __func__, id); 64662306a36Sopenharmony_ci return id; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (ps3av->region & PS3AV_REGION_60) 65062306a36Sopenharmony_ci id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; 65162306a36Sopenharmony_ci else 65262306a36Sopenharmony_ci id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50; 65362306a36Sopenharmony_ci pr_debug("%s: Using default mode %d\n", __func__, id); 65462306a36Sopenharmony_ci return id; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void ps3av_monitor_info_dump( 65862306a36Sopenharmony_ci const struct ps3av_pkt_av_get_monitor_info *monitor_info) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci const struct ps3av_info_monitor *info = &monitor_info->info; 66162306a36Sopenharmony_ci const struct ps3av_info_audio *audio = info->audio; 66262306a36Sopenharmony_ci char id[sizeof(info->monitor_id)*3+1]; 66362306a36Sopenharmony_ci int i; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci pr_debug("avport: %02x\n", info->avport); 66862306a36Sopenharmony_ci for (i = 0; i < sizeof(info->monitor_id); i++) 66962306a36Sopenharmony_ci sprintf(&id[i*3], " %02x", info->monitor_id[i]); 67062306a36Sopenharmony_ci pr_debug("monitor_id: %s\n", id); 67162306a36Sopenharmony_ci pr_debug("monitor_type: %02x\n", info->monitor_type); 67262306a36Sopenharmony_ci pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name), 67362306a36Sopenharmony_ci info->monitor_name); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* resolution */ 67662306a36Sopenharmony_ci pr_debug("resolution_60: bits: %08x native: %08x\n", 67762306a36Sopenharmony_ci info->res_60.res_bits, info->res_60.native); 67862306a36Sopenharmony_ci pr_debug("resolution_50: bits: %08x native: %08x\n", 67962306a36Sopenharmony_ci info->res_50.res_bits, info->res_50.native); 68062306a36Sopenharmony_ci pr_debug("resolution_other: bits: %08x native: %08x\n", 68162306a36Sopenharmony_ci info->res_other.res_bits, info->res_other.native); 68262306a36Sopenharmony_ci pr_debug("resolution_vesa: bits: %08x native: %08x\n", 68362306a36Sopenharmony_ci info->res_vesa.res_bits, info->res_vesa.native); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* color space */ 68662306a36Sopenharmony_ci pr_debug("color space rgb: %02x\n", info->cs.rgb); 68762306a36Sopenharmony_ci pr_debug("color space yuv444: %02x\n", info->cs.yuv444); 68862306a36Sopenharmony_ci pr_debug("color space yuv422: %02x\n", info->cs.yuv422); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* color info */ 69162306a36Sopenharmony_ci pr_debug("color info red: X %04x Y %04x\n", info->color.red_x, 69262306a36Sopenharmony_ci info->color.red_y); 69362306a36Sopenharmony_ci pr_debug("color info green: X %04x Y %04x\n", info->color.green_x, 69462306a36Sopenharmony_ci info->color.green_y); 69562306a36Sopenharmony_ci pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x, 69662306a36Sopenharmony_ci info->color.blue_y); 69762306a36Sopenharmony_ci pr_debug("color info white: X %04x Y %04x\n", info->color.white_x, 69862306a36Sopenharmony_ci info->color.white_y); 69962306a36Sopenharmony_ci pr_debug("color info gamma: %08x\n", info->color.gamma); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* other info */ 70262306a36Sopenharmony_ci pr_debug("supported_AI: %02x\n", info->supported_ai); 70362306a36Sopenharmony_ci pr_debug("speaker_info: %02x\n", info->speaker_info); 70462306a36Sopenharmony_ci pr_debug("num of audio: %02x\n", info->num_of_audio_block); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* audio block */ 70762306a36Sopenharmony_ci for (i = 0; i < info->num_of_audio_block; i++) { 70862306a36Sopenharmony_ci pr_debug( 70962306a36Sopenharmony_ci "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n", 71062306a36Sopenharmony_ci i, audio->type, audio->max_num_of_ch, audio->fs, 71162306a36Sopenharmony_ci audio->sbit); 71262306a36Sopenharmony_ci audio++; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic const struct ps3av_monitor_quirk { 71762306a36Sopenharmony_ci const char *monitor_name; 71862306a36Sopenharmony_ci u32 clear_60; 71962306a36Sopenharmony_ci} ps3av_monitor_quirks[] = { 72062306a36Sopenharmony_ci { 72162306a36Sopenharmony_ci .monitor_name = "DELL 2007WFP", 72262306a36Sopenharmony_ci .clear_60 = PS3AV_RESBIT_1920x1080I 72362306a36Sopenharmony_ci }, { 72462306a36Sopenharmony_ci .monitor_name = "L226WTQ", 72562306a36Sopenharmony_ci .clear_60 = PS3AV_RESBIT_1920x1080I | 72662306a36Sopenharmony_ci PS3AV_RESBIT_1920x1080P 72762306a36Sopenharmony_ci }, { 72862306a36Sopenharmony_ci .monitor_name = "SyncMaster", 72962306a36Sopenharmony_ci .clear_60 = PS3AV_RESBIT_1920x1080I 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci}; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci unsigned int i; 73662306a36Sopenharmony_ci const struct ps3av_monitor_quirk *quirk; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) { 73962306a36Sopenharmony_ci quirk = &ps3av_monitor_quirks[i]; 74062306a36Sopenharmony_ci if (!strncmp(info->monitor_name, quirk->monitor_name, 74162306a36Sopenharmony_ci sizeof(info->monitor_name))) { 74262306a36Sopenharmony_ci pr_info("%s: Applying quirk for %s\n", __func__, 74362306a36Sopenharmony_ci quirk->monitor_name); 74462306a36Sopenharmony_ci info->res_60.res_bits &= ~quirk->clear_60; 74562306a36Sopenharmony_ci info->res_60.native &= ~quirk->clear_60; 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci int i, res, id = 0, dvi = 0, rgb = 0; 75462306a36Sopenharmony_ci struct ps3av_pkt_av_get_monitor_info monitor_info; 75562306a36Sopenharmony_ci struct ps3av_info_monitor *info; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* get mode id for hdmi */ 75862306a36Sopenharmony_ci for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) { 75962306a36Sopenharmony_ci res = ps3av_cmd_video_get_monitor_info(&monitor_info, 76062306a36Sopenharmony_ci PS3AV_CMD_AVPORT_HDMI_0 + 76162306a36Sopenharmony_ci i); 76262306a36Sopenharmony_ci if (res < 0) 76362306a36Sopenharmony_ci return -1; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ps3av_monitor_info_dump(&monitor_info); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci info = &monitor_info.info; 76862306a36Sopenharmony_ci ps3av_fixup_monitor_info(info); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci switch (info->monitor_type) { 77162306a36Sopenharmony_ci case PS3AV_MONITOR_TYPE_DVI: 77262306a36Sopenharmony_ci dvi = PS3AV_MODE_DVI; 77362306a36Sopenharmony_ci fallthrough; 77462306a36Sopenharmony_ci case PS3AV_MONITOR_TYPE_HDMI: 77562306a36Sopenharmony_ci id = ps3av_hdmi_get_id(info); 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (!id) { 78162306a36Sopenharmony_ci /* no HDMI interface or HDMI is off */ 78262306a36Sopenharmony_ci if (ps3av->region & PS3AV_REGION_60) 78362306a36Sopenharmony_ci id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60; 78462306a36Sopenharmony_ci else 78562306a36Sopenharmony_ci id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50; 78662306a36Sopenharmony_ci if (ps3av->region & PS3AV_REGION_RGB) 78762306a36Sopenharmony_ci rgb = PS3AV_MODE_RGB; 78862306a36Sopenharmony_ci pr_debug("%s: Using avmulti mode %d\n", __func__, id); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return id | dvi | rgb; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int ps3av_get_hw_conf(struct ps3av *ps3av) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci int i, j, k, res; 79762306a36Sopenharmony_ci const struct ps3av_pkt_av_get_hw_conf *hw_conf; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* get av_hw_conf */ 80062306a36Sopenharmony_ci res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); 80162306a36Sopenharmony_ci if (res < 0) 80262306a36Sopenharmony_ci return -1; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci hw_conf = &ps3av->av_hw_conf; 80562306a36Sopenharmony_ci pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi); 80662306a36Sopenharmony_ci pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti); 80762306a36Sopenharmony_ci pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci for (i = 0; i < PS3AV_HEAD_MAX; i++) 81062306a36Sopenharmony_ci ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; 81162306a36Sopenharmony_ci for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) 81262306a36Sopenharmony_ci ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; 81362306a36Sopenharmony_ci for (i = 0; i < hw_conf->num_of_hdmi; i++) 81462306a36Sopenharmony_ci ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; 81562306a36Sopenharmony_ci for (j = 0; j < hw_conf->num_of_avmulti; j++) 81662306a36Sopenharmony_ci ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; 81762306a36Sopenharmony_ci for (k = 0; k < hw_conf->num_of_spdif; k++) 81862306a36Sopenharmony_ci ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* set all audio port */ 82162306a36Sopenharmony_ci ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 82262306a36Sopenharmony_ci | PS3AV_CMD_AUDIO_PORT_HDMI_1 82362306a36Sopenharmony_ci | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 82462306a36Sopenharmony_ci | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci/* set mode using id */ 83062306a36Sopenharmony_ciint ps3av_set_video_mode(int id) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci int size; 83362306a36Sopenharmony_ci u32 option; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci size = ARRAY_SIZE(video_mode_table); 83662306a36Sopenharmony_ci if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { 83762306a36Sopenharmony_ci dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id); 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* auto mode */ 84262306a36Sopenharmony_ci option = id & ~PS3AV_MODE_MASK; 84362306a36Sopenharmony_ci if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) { 84462306a36Sopenharmony_ci id = ps3av_auto_videomode(&ps3av->av_hw_conf); 84562306a36Sopenharmony_ci if (id < 1) { 84662306a36Sopenharmony_ci printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); 84762306a36Sopenharmony_ci return -EINVAL; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci id |= option; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci /* set videomode */ 85362306a36Sopenharmony_ci wait_for_completion(&ps3av->done); 85462306a36Sopenharmony_ci ps3av->ps3av_mode_old = ps3av->ps3av_mode; 85562306a36Sopenharmony_ci ps3av->ps3av_mode = id; 85662306a36Sopenharmony_ci if (ps3av_set_videomode()) 85762306a36Sopenharmony_ci ps3av->ps3av_mode = ps3av->ps3av_mode_old; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return 0; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_set_video_mode); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ciint ps3av_get_auto_mode(void) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci return ps3av_auto_videomode(&ps3av->av_hw_conf); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_get_auto_mode); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciint ps3av_get_mode(void) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci return ps3av ? ps3av->ps3av_mode : 0; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_get_mode); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/* get resolution by video_mode */ 87662306a36Sopenharmony_ciint ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci int size; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci id = id & PS3AV_MODE_MASK; 88162306a36Sopenharmony_ci size = ARRAY_SIZE(video_mode_table); 88262306a36Sopenharmony_ci if (id > size - 1 || id < 0) { 88362306a36Sopenharmony_ci printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); 88462306a36Sopenharmony_ci return -EINVAL; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci *xres = video_mode_table[id].x; 88762306a36Sopenharmony_ci *yres = video_mode_table[id].y; 88862306a36Sopenharmony_ci return 0; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_video_mode2res); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/* mute */ 89362306a36Sopenharmony_ciint ps3av_video_mute(int mute) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON 89662306a36Sopenharmony_ci : PS3AV_CMD_MUTE_OFF); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_video_mute); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* mute analog output only */ 90162306a36Sopenharmony_ciint ps3av_audio_mute_analog(int mute) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci int i, res; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci for (i = 0; i < ps3av->av_hw_conf.num_of_avmulti; i++) { 90662306a36Sopenharmony_ci res = ps3av_cmd_av_audio_mute(1, 90762306a36Sopenharmony_ci &ps3av->av_port[i + ps3av->av_hw_conf.num_of_hdmi], 90862306a36Sopenharmony_ci mute); 90962306a36Sopenharmony_ci if (res < 0) 91062306a36Sopenharmony_ci return -1; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_audio_mute_analog); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ciint ps3av_audio_mute(int mute) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON 91962306a36Sopenharmony_ci : PS3AV_CMD_MUTE_OFF); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3av_audio_mute); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic int ps3av_probe(struct ps3_system_bus_device *dev) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci const char *mode_option; 92662306a36Sopenharmony_ci int res; 92762306a36Sopenharmony_ci int id; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 93062306a36Sopenharmony_ci dev_dbg(&dev->core, " timeout=%d\n", timeout); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (ps3av) { 93362306a36Sopenharmony_ci dev_err(&dev->core, "Only one ps3av device is supported\n"); 93462306a36Sopenharmony_ci return -EBUSY; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL); 93862306a36Sopenharmony_ci if (!ps3av) 93962306a36Sopenharmony_ci return -ENOMEM; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci mutex_init(&ps3av->mutex); 94262306a36Sopenharmony_ci ps3av->ps3av_mode = PS3AV_MODE_AUTO; 94362306a36Sopenharmony_ci ps3av->dev = dev; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci INIT_WORK(&ps3av->work, ps3avd); 94662306a36Sopenharmony_ci init_completion(&ps3av->done); 94762306a36Sopenharmony_ci complete(&ps3av->done); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci switch (ps3_os_area_get_av_multi_out()) { 95062306a36Sopenharmony_ci case PS3_PARAM_AV_MULTI_OUT_NTSC: 95162306a36Sopenharmony_ci ps3av->region = PS3AV_REGION_60; 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: 95462306a36Sopenharmony_ci case PS3_PARAM_AV_MULTI_OUT_SECAM: 95562306a36Sopenharmony_ci ps3av->region = PS3AV_REGION_50; 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: 95862306a36Sopenharmony_ci ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB; 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci default: 96162306a36Sopenharmony_ci ps3av->region = PS3AV_REGION_60; 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* init avsetting modules */ 96662306a36Sopenharmony_ci res = ps3av_cmd_init(); 96762306a36Sopenharmony_ci if (res < 0) 96862306a36Sopenharmony_ci printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, 96962306a36Sopenharmony_ci res); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ps3av_get_hw_conf(ps3av); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci mode_option = video_get_options(NULL); 97462306a36Sopenharmony_ci if (mode_option && !strcmp(mode_option, "safe")) 97562306a36Sopenharmony_ci safe_mode = 1; 97662306a36Sopenharmony_ci id = ps3av_auto_videomode(&ps3av->av_hw_conf); 97762306a36Sopenharmony_ci if (id < 0) { 97862306a36Sopenharmony_ci printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); 97962306a36Sopenharmony_ci res = -EINVAL; 98062306a36Sopenharmony_ci goto fail; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci safe_mode = 0; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci mutex_lock(&ps3av->mutex); 98662306a36Sopenharmony_ci ps3av->ps3av_mode = id; 98762306a36Sopenharmony_ci mutex_unlock(&ps3av->mutex); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cifail: 99462306a36Sopenharmony_ci kfree(ps3av); 99562306a36Sopenharmony_ci ps3av = NULL; 99662306a36Sopenharmony_ci return res; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic int ps3av_remove(struct ps3_system_bus_device *dev) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 100262306a36Sopenharmony_ci if (ps3av) { 100362306a36Sopenharmony_ci ps3av_cmd_fin(); 100462306a36Sopenharmony_ci flush_work(&ps3av->work); 100562306a36Sopenharmony_ci kfree(ps3av); 100662306a36Sopenharmony_ci ps3av = NULL; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic void ps3av_shutdown(struct ps3_system_bus_device *dev) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 101662306a36Sopenharmony_ci ps3av_remove(dev); 101762306a36Sopenharmony_ci dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic struct ps3_vuart_port_driver ps3av_driver = { 102162306a36Sopenharmony_ci .core.match_id = PS3_MATCH_ID_AV_SETTINGS, 102262306a36Sopenharmony_ci .core.core.name = "ps3_av", 102362306a36Sopenharmony_ci .probe = ps3av_probe, 102462306a36Sopenharmony_ci .remove = ps3av_remove, 102562306a36Sopenharmony_ci .shutdown = ps3av_shutdown, 102662306a36Sopenharmony_ci}; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int __init ps3av_module_init(void) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci int error; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 103362306a36Sopenharmony_ci return -ENODEV; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci pr_debug(" -> %s:%d\n", __func__, __LINE__); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci error = ps3_vuart_port_driver_register(&ps3av_driver); 103862306a36Sopenharmony_ci if (error) { 103962306a36Sopenharmony_ci printk(KERN_ERR 104062306a36Sopenharmony_ci "%s: ps3_vuart_port_driver_register failed %d\n", 104162306a36Sopenharmony_ci __func__, error); 104262306a36Sopenharmony_ci return error; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci pr_debug(" <- %s:%d\n", __func__, __LINE__); 104662306a36Sopenharmony_ci return error; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic void __exit ps3av_module_exit(void) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci pr_debug(" -> %s:%d\n", __func__, __LINE__); 105262306a36Sopenharmony_ci ps3_vuart_port_driver_unregister(&ps3av_driver); 105362306a36Sopenharmony_ci pr_debug(" <- %s:%d\n", __func__, __LINE__); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cisubsys_initcall(ps3av_module_init); 105762306a36Sopenharmony_cimodule_exit(ps3av_module_exit); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 106062306a36Sopenharmony_ciMODULE_DESCRIPTION("PS3 AV Settings Driver"); 106162306a36Sopenharmony_ciMODULE_AUTHOR("Sony Computer Entertainment Inc."); 106262306a36Sopenharmony_ciMODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS); 1063