ps3av.c
来自「linux 内核源代码」· C语言 代码 · 共 1,113 行 · 第 1/2 页
C
1,113 行
/* vesa mode */ ps3av_set_videomode_packet(2); /* 480P */ } vesa = 1; /* Retail PS3 product doesn't support this */ if (id & PS3AV_MODE_HDCP_OFF) { res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) dev_dbg(&ps3av->dev->core, "Not supported\n"); else if (res) dev_dbg(&ps3av->dev->core, "ps3av_cmd_av_hdmi_mode failed\n"); } else if (old_id & PS3AV_MODE_HDCP_OFF) { res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) dev_dbg(&ps3av->dev->core, "ps3av_cmd_av_hdmi_mode failed\n"); } ps3av_set_videomode_packet(id); msleep(1500); /* av video mute */ ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);}static void ps3avd(struct work_struct *work){ ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old); complete(&ps3av->done);}#define SHIFT_50 0#define SHIFT_60 4#define SHIFT_VESA 8static const struct { unsigned mask : 19; unsigned id : 4;} ps3av_preferred_modes[] = { { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 }, { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 }, { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 }, { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 }, { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 }, { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 }, { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 }, { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 }, { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 }, { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 }, { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 },};static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa){ unsigned int i; u32 res_all; /* * We mask off the resolution bits we care about and combine the * results in one bitfield, so make sure there's no overlap */ BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & PS3AV_RES_MASK_60 << SHIFT_60); BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & PS3AV_RES_MASK_VESA << SHIFT_VESA); BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 & PS3AV_RES_MASK_VESA << SHIFT_VESA); res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 | (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 | (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA; if (!res_all) return 0; for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++) if (res_all & ps3av_preferred_modes[i].mask) return ps3av_preferred_modes[i].id; return 0;}static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info){ int id; if (safe_mode) return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; /* check native resolution */ id = ps3av_resbit2id(info->res_50.native, info->res_60.native, info->res_vesa.native); if (id) { pr_debug("%s: Using native mode %d\n", __func__, id); return id; } /* check supported resolutions */ id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits, info->res_vesa.res_bits); if (id) { pr_debug("%s: Using supported mode %d\n", __func__, id); return id; } if (ps3av->region & PS3AV_REGION_60) id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; else id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50; pr_debug("%s: Using default mode %d\n", __func__, id); return id;}static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info){ const struct ps3av_info_monitor *info = &monitor_info->info; const struct ps3av_info_audio *audio = info->audio; char id[sizeof(info->monitor_id)*3+1]; int i; pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size); pr_debug("avport: %02x\n", info->avport); for (i = 0; i < sizeof(info->monitor_id); i++) sprintf(&id[i*3], " %02x", info->monitor_id[i]); pr_debug("monitor_id: %s\n", id); pr_debug("monitor_type: %02x\n", info->monitor_type); pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name), info->monitor_name); /* resolution */ pr_debug("resolution_60: bits: %08x native: %08x\n", info->res_60.res_bits, info->res_60.native); pr_debug("resolution_50: bits: %08x native: %08x\n", info->res_50.res_bits, info->res_50.native); pr_debug("resolution_other: bits: %08x native: %08x\n", info->res_other.res_bits, info->res_other.native); pr_debug("resolution_vesa: bits: %08x native: %08x\n", info->res_vesa.res_bits, info->res_vesa.native); /* color space */ pr_debug("color space rgb: %02x\n", info->cs.rgb); pr_debug("color space yuv444: %02x\n", info->cs.yuv444); pr_debug("color space yuv422: %02x\n", info->cs.yuv422); /* color info */ pr_debug("color info red: X %04x Y %04x\n", info->color.red_x, info->color.red_y); pr_debug("color info green: X %04x Y %04x\n", info->color.green_x, info->color.green_y); pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x, info->color.blue_y); pr_debug("color info white: X %04x Y %04x\n", info->color.white_x, info->color.white_y); pr_debug("color info gamma: %08x\n", info->color.gamma); /* other info */ pr_debug("supported_AI: %02x\n", info->supported_ai); pr_debug("speaker_info: %02x\n", info->speaker_info); pr_debug("num of audio: %02x\n", info->num_of_audio_block); /* audio block */ for (i = 0; i < info->num_of_audio_block; i++) { pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: " "%02x\n", i, audio->type, audio->max_num_of_ch, audio->fs, audio->sbit); audio++; }}static const struct ps3av_monitor_quirk { const char *monitor_name; u32 clear_60;} ps3av_monitor_quirks[] = { { .monitor_name = "DELL 2007WFP", .clear_60 = PS3AV_RESBIT_1920x1080I }, { .monitor_name = "L226WTQ", .clear_60 = PS3AV_RESBIT_1920x1080I | PS3AV_RESBIT_1920x1080P }, { .monitor_name = "SyncMaster", .clear_60 = PS3AV_RESBIT_1920x1080I }};static void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info){ unsigned int i; const struct ps3av_monitor_quirk *quirk; for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) { quirk = &ps3av_monitor_quirks[i]; if (!strncmp(info->monitor_name, quirk->monitor_name, sizeof(info->monitor_name))) { pr_info("%s: Applying quirk for %s\n", __func__, quirk->monitor_name); info->res_60.res_bits &= ~quirk->clear_60; info->res_60.native &= ~quirk->clear_60; break; } }}static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf){ int i, res, id = 0, dvi = 0, rgb = 0; struct ps3av_pkt_av_get_monitor_info monitor_info; struct ps3av_info_monitor *info; /* get mode id for hdmi */ for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) { res = ps3av_cmd_video_get_monitor_info(&monitor_info, PS3AV_CMD_AVPORT_HDMI_0 + i); if (res < 0) return -1; ps3av_monitor_info_dump(&monitor_info); info = &monitor_info.info; ps3av_fixup_monitor_info(info); switch (info->monitor_type) { case PS3AV_MONITOR_TYPE_DVI: dvi = PS3AV_MODE_DVI; /* fall through */ case PS3AV_MONITOR_TYPE_HDMI: id = ps3av_hdmi_get_id(info); break; } } if (!id) { /* no HDMI interface or HDMI is off */ if (ps3av->region & PS3AV_REGION_60) id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60; else id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50; if (ps3av->region & PS3AV_REGION_RGB) rgb = PS3AV_MODE_RGB; pr_debug("%s: Using avmulti mode %d\n", __func__, id); } return id | dvi | rgb;}static int ps3av_get_hw_conf(struct ps3av *ps3av){ int i, j, k, res; const struct ps3av_pkt_av_get_hw_conf *hw_conf; /* get av_hw_conf */ res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); if (res < 0) return -1; hw_conf = &ps3av->av_hw_conf; pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi); pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti); pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif); for (i = 0; i < PS3AV_HEAD_MAX; i++) ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; for (i = 0; i < hw_conf->num_of_hdmi; i++) ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; for (j = 0; j < hw_conf->num_of_avmulti; j++) ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; for (k = 0; k < hw_conf->num_of_spdif; k++) ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; /* set all audio port */ ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 | PS3AV_CMD_AUDIO_PORT_HDMI_1 | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; return 0;}/* set mode using id */int ps3av_set_video_mode(u32 id){ int size; u32 option; size = ARRAY_SIZE(video_mode_table); if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id); return -EINVAL; } /* auto mode */ option = id & ~PS3AV_MODE_MASK; if ((id & PS3AV_MODE_MASK) == 0) { id = ps3av_auto_videomode(&ps3av->av_hw_conf); if (id < 1) { printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); return -EINVAL; } id |= option; } /* set videomode */ wait_for_completion(&ps3av->done); ps3av->ps3av_mode_old = ps3av->ps3av_mode; ps3av->ps3av_mode = id; if (ps3av_set_videomode()) ps3av->ps3av_mode = ps3av->ps3av_mode_old; return 0;}EXPORT_SYMBOL_GPL(ps3av_set_video_mode);int ps3av_get_auto_mode(void){ return ps3av_auto_videomode(&ps3av->av_hw_conf);}EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);int ps3av_get_mode(void){ return ps3av ? ps3av->ps3av_mode : 0;}EXPORT_SYMBOL_GPL(ps3av_get_mode);int ps3av_get_scanmode(int id){ int size; id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } return video_mode_table[id].interlace;}EXPORT_SYMBOL_GPL(ps3av_get_scanmode);int ps3av_get_refresh_rate(int id){ int size; id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } return video_mode_table[id].freq;}EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);/* get resolution by video_mode */int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres){ int size; id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } *xres = video_mode_table[id].x; *yres = video_mode_table[id].y; return 0;}EXPORT_SYMBOL_GPL(ps3av_video_mode2res);/* mute */int ps3av_video_mute(int mute){ return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON : PS3AV_CMD_MUTE_OFF);}EXPORT_SYMBOL_GPL(ps3av_video_mute);int ps3av_audio_mute(int mute){ return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON : PS3AV_CMD_MUTE_OFF);}EXPORT_SYMBOL_GPL(ps3av_audio_mute);void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), void *flip_data){ mutex_lock(&ps3av->mutex); ps3av->flip_ctl = flip_ctl; ps3av->flip_data = flip_data; mutex_unlock(&ps3av->mutex);}EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);void ps3av_flip_ctl(int on){ mutex_lock(&ps3av->mutex); if (ps3av->flip_ctl) ps3av->flip_ctl(on, ps3av->flip_data); mutex_unlock(&ps3av->mutex);}static int ps3av_probe(struct ps3_system_bus_device *dev){ int res; u32 id; dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); dev_dbg(&dev->core, " timeout=%d\n", timeout); if (ps3av) { dev_err(&dev->core, "Only one ps3av device is supported\n"); return -EBUSY; } ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL); if (!ps3av) return -ENOMEM; mutex_init(&ps3av->mutex); ps3av->ps3av_mode = 0; ps3av->dev = dev; INIT_WORK(&ps3av->work, ps3avd); init_completion(&ps3av->done); complete(&ps3av->done); ps3av->wq = create_singlethread_workqueue("ps3avd"); if (!ps3av->wq) goto fail; switch (ps3_os_area_get_av_multi_out()) { case PS3_PARAM_AV_MULTI_OUT_NTSC: ps3av->region = PS3AV_REGION_60; break; case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: case PS3_PARAM_AV_MULTI_OUT_SECAM: ps3av->region = PS3AV_REGION_50; break; case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB; break; default: ps3av->region = PS3AV_REGION_60; break; } /* init avsetting modules */ res = ps3av_cmd_init(); if (res < 0) printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, res); ps3av_get_hw_conf(ps3av);#ifdef CONFIG_FB if (fb_mode_option && !strcmp(fb_mode_option, "safe")) safe_mode = 1;#endif /* CONFIG_FB */ id = ps3av_auto_videomode(&ps3av->av_hw_conf); safe_mode = 0; mutex_lock(&ps3av->mutex); ps3av->ps3av_mode = id; mutex_unlock(&ps3av->mutex); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); return 0;fail: kfree(ps3av); ps3av = NULL; return -ENOMEM;}static int ps3av_remove(struct ps3_system_bus_device *dev){ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); if (ps3av) { ps3av_cmd_fin(); if (ps3av->wq) destroy_workqueue(ps3av->wq); kfree(ps3av); ps3av = NULL; } dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); return 0;}static void ps3av_shutdown(struct ps3_system_bus_device *dev){ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); ps3av_remove(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);}static struct ps3_vuart_port_driver ps3av_driver = { .core.match_id = PS3_MATCH_ID_AV_SETTINGS, .core.core.name = "ps3_av", .probe = ps3av_probe, .remove = ps3av_remove, .shutdown = ps3av_shutdown,};static int ps3av_module_init(void){ int error; if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) return -ENODEV; pr_debug(" -> %s:%d\n", __func__, __LINE__); error = ps3_vuart_port_driver_register(&ps3av_driver); if (error) { printk(KERN_ERR "%s: ps3_vuart_port_driver_register failed %d\n", __func__, error); return error; } pr_debug(" <- %s:%d\n", __func__, __LINE__); return error;}static void __exit ps3av_module_exit(void){ pr_debug(" -> %s:%d\n", __func__, __LINE__); ps3_vuart_port_driver_unregister(&ps3av_driver); pr_debug(" <- %s:%d\n", __func__, __LINE__);}subsys_initcall(ps3av_module_init);module_exit(ps3av_module_exit);MODULE_LICENSE("GPL v2");MODULE_DESCRIPTION("PS3 AV Settings Driver");MODULE_AUTHOR("Sony Computer Entertainment Inc.");MODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?