2
* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
5
* Copyright (C) 2009 NVIDIA Corporation.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of Version 2 of the GNU General Public
9
* License as published by the Free Software Foundation.
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 Version 2
14
* of the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the:
19
* Free Software Foundation, Inc.
20
* 59 Temple Place - Suite 330
21
* Boston, MA 02111-1307, USA
29
#include <NvCtrlAttributes.h>
38
#include "ctkbanner.h"
40
#define DEFAULT_UPDATE_VIDEO_FORMAT_INFO_TIME_INTERVAL 1000
42
static gboolean update_sdi_input_info(gpointer);
44
GType ctk_gvi_get_type(void)
46
static GType ctk_gvi_type = 0;
49
static const GTypeInfo ctk_gvi_info = {
52
NULL, /* base_finalize */
53
NULL, /* constructor */
54
NULL, /* class_finalize */
55
NULL, /* class_data */
58
NULL, /* instance_init */
62
g_type_register_static(GTK_TYPE_VBOX, "CtkGvi",
68
} /* ctk_gvi_get_type() */
70
static const GvioFormatName samplingFormatNames[] = {
71
{ NV_CTRL_GVI_COMPONENT_SAMPLING_4444, "4:4:4:4"},
72
{ NV_CTRL_GVI_COMPONENT_SAMPLING_4224, "4:2:2:4"},
73
{ NV_CTRL_GVI_COMPONENT_SAMPLING_444, "4:4:4" },
74
{ NV_CTRL_GVI_COMPONENT_SAMPLING_422, "4:2:2" },
75
{ NV_CTRL_GVI_COMPONENT_SAMPLING_420, "4:2:0" },
79
static const GvioFormatName bitFormatNames[] = {
80
{ NV_CTRL_GVI_BITS_PER_COMPONENT_8, "8 bpc" },
81
{ NV_CTRL_GVI_BITS_PER_COMPONENT_10, "10 bpc"},
82
{ NV_CTRL_GVI_BITS_PER_COMPONENT_12, "12 bpc"},
86
static const GvioFormatName colorSpaceFormatNames[] = {
87
{ NV_CTRL_GVI_COLOR_SPACE_GBR, "GBR" },
88
{ NV_CTRL_GVI_COLOR_SPACE_GBRA, "GBRA" },
89
{ NV_CTRL_GVI_COLOR_SPACE_GBRD, "GBRD" },
90
{ NV_CTRL_GVI_COLOR_SPACE_YCBCR, "YCbCr" },
91
{ NV_CTRL_GVI_COLOR_SPACE_YCBCRA, "YCbCrA"},
92
{ NV_CTRL_GVI_COLOR_SPACE_YCBCRD, "YCbCrD"},
96
extern const GvioFormatName videoFormatNames[];
99
static gboolean update_sdi_input_info(gpointer user_data);
102
* ctk_gvio_get_format_name() - retrun name of format.
104
const char * ctk_gvio_get_format_name(const GvioFormatName *formatTable,
108
for (i = 0; formatTable[i].name; i++) {
109
if (formatTable[i].format == format) {
110
return formatTable[i].name;
119
* update_sdi_input_info() - Update SDI input information.
124
int component_sampling;
131
static void query_channel_info(CtkGvi *ctk_gvi, int jack, int channel, ChannelInfo *channel_info)
134
unsigned int jack_channel = ((channel & 0xFFFF) << 16);
135
jack_channel |= (jack & 0xFFFF);
138
ret = NvCtrlGetDisplayAttribute(ctk_gvi->handle,
140
NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT,
141
&(channel_info->video_format));
142
if (ret != NvCtrlSuccess) {
143
channel_info->video_format = NV_CTRL_GVIO_VIDEO_FORMAT_NONE;
146
ret = NvCtrlGetDisplayAttribute(ctk_gvi->handle,
148
NV_CTRL_GVI_DETECTED_CHANNEL_COMPONENT_SAMPLING,
149
&(channel_info->component_sampling));
150
if (ret != NvCtrlSuccess) {
151
channel_info->component_sampling =
152
NV_CTRL_GVI_COMPONENT_SAMPLING_UNKNOWN;
155
ret = NvCtrlGetDisplayAttribute(ctk_gvi->handle,
157
NV_CTRL_GVI_DETECTED_CHANNEL_COLOR_SPACE,
158
&(channel_info->color_space));
159
if (ret != NvCtrlSuccess) {
160
channel_info->color_space = NV_CTRL_GVI_COLOR_SPACE_UNKNOWN;
163
ret = NvCtrlGetDisplayAttribute(ctk_gvi->handle,
165
NV_CTRL_GVI_DETECTED_CHANNEL_BITS_PER_COMPONENT,
166
&(channel_info->bpc));
167
if (ret != NvCtrlSuccess) {
168
channel_info->bpc = NV_CTRL_GVI_BITS_PER_COMPONENT_UNKNOWN;
171
ret = NvCtrlGetDisplayAttribute(ctk_gvi->handle,
173
NV_CTRL_GVI_DETECTED_CHANNEL_LINK_ID,
174
&(channel_info->link_id));
175
if (ret != NvCtrlSuccess) {
176
channel_info->link_id = NV_CTRL_GVI_LINK_ID_UNKNOWN;
181
static void update_sdi_input_info_simple(CtkGvi *ctk_gvi)
183
GtkBox *vbox = GTK_BOX(ctk_gvi->input_info_vbox);
188
const char *vidfmt_str;
189
GtkWidget *box = NULL;
192
/* If not showing detailed information,
193
* Show single entry for active jack/channel pairs as:
195
* Jack #, Channel #: VIDEO FORMAT
198
for (jack = 0; jack < ctk_gvi->num_jacks; jack++) {
199
ChannelInfo channel_infos[ctk_gvi->max_channels_per_jack];
200
ChannelInfo *channel_info;
201
int num_active_channels = 0;
202
int show_channel = 0; /* When 0 or 1 active channel detected */
204
/* Get information for each channel in the jack. */
205
for (channel = 0; channel < ctk_gvi->max_channels_per_jack;
208
channel_info = channel_infos + channel;
209
query_channel_info(ctk_gvi, jack, channel, channel_info);
210
if (channel_info->video_format != NV_CTRL_GVIO_VIDEO_FORMAT_NONE) {
211
show_channel = channel;
212
num_active_channels++;
216
/* Populate the info table */
218
if (num_active_channels > 1) {
219
box = gtk_vbox_new(FALSE, 0);
220
gtk_box_pack_start(vbox, box, FALSE, FALSE, 0);
222
label_str = g_strdup_printf("Jack %d:", jack+1);
223
label = gtk_label_new(label_str);
225
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
226
gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
229
for (channel = 0; channel < ctk_gvi->max_channels_per_jack;
231
channel_info = channel_infos + channel;
233
vidfmt_str = ctk_gvio_get_format_name(videoFormatNames,
234
channel_info->video_format);
236
if (num_active_channels <= 1) {
237
if (channel != show_channel) continue;
238
label_str = g_strdup_printf("Jack %d: %s", jack+1, vidfmt_str);
239
label = gtk_label_new(label_str);
241
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
242
gtk_box_pack_start(vbox, label, FALSE, FALSE, 0);
245
label_str = g_strdup_printf("Channel %d: %s",
246
channel+1, vidfmt_str);
247
label = gtk_label_new(label_str);
249
gtk_misc_set_padding(GTK_MISC(label), 5, 0);
250
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
251
gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
258
static void jack_channel_changed(GtkOptionMenu *optionmenu,
261
CtkGvi *ctk_gvi = CTK_GVI(user_data);
263
GtkWidget *menu_item;
265
/* Track new selection */
266
menu = gtk_option_menu_get_menu(optionmenu);
267
menu_item = gtk_menu_get_active(GTK_MENU(menu));
269
ctk_gvi->cur_jack_channel =
270
GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(menu_item),
273
update_sdi_input_info(ctk_gvi);
277
static GtkWidget *create_jack_channel_menu(CtkGvi *ctk_gvi)
281
GtkWidget *menu_item;
286
unsigned int jack_channel;
287
gint selected_idx = 0;
289
/* Create the menu */
291
omenu = gtk_option_menu_new();
293
menu = gtk_menu_new();
295
/* Just show all jack/channel pairs in dropdown */
298
for (jack = 0; jack < ctk_gvi->num_jacks; jack++) {
299
for (channel = 0; channel < ctk_gvi->max_channels_per_jack;
302
jack_channel = ((channel & 0xFFFF) << 16);
303
jack_channel |= (jack & 0xFFFF);
306
label_str = g_strdup_printf("Jack %d, Channel %d",
308
menu_item = gtk_menu_item_new_with_label(label_str);
311
g_object_set_data(G_OBJECT(menu_item),
313
GUINT_TO_POINTER(jack_channel));
315
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
316
gtk_widget_show(menu_item);
318
if (jack_channel == ctk_gvi->cur_jack_channel) {
326
gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu);
328
gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), selected_idx);
330
g_signal_connect(G_OBJECT(omenu), "changed",
331
G_CALLBACK(jack_channel_changed),
338
static void update_sdi_input_info_all(CtkGvi *ctk_gvi)
340
GtkBox *vbox = GTK_BOX(ctk_gvi->input_info_vbox);
349
ChannelInfo channel_info;
351
jack = ctk_gvi->cur_jack_channel & 0xFFFF;
352
channel = (ctk_gvi->cur_jack_channel >> 16) & 0xFFFF;
354
query_channel_info(ctk_gvi, jack, channel, &channel_info);
356
box = gtk_hbox_new(FALSE, 0);
357
gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
359
table = gtk_table_new(5, 2, FALSE);
360
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
361
gtk_table_set_col_spacings(GTK_TABLE(table), 5);
363
gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 0);
365
/* Show channel's information in table format */
367
label = gtk_label_new("Video Format:");
368
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
369
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
371
str = ctk_gvio_get_format_name(videoFormatNames,
372
channel_info.video_format);
373
label_str = g_strdup_printf("%s", str);
374
label = gtk_label_new(label_str);
375
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
376
gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
380
label = gtk_label_new("Component Sampling:");
381
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
382
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
384
str = ctk_gvio_get_format_name(samplingFormatNames,
385
channel_info.component_sampling);
386
label_str = g_strdup_printf("%s", str);
387
label = gtk_label_new(label_str);
388
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
389
gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
393
label = gtk_label_new("Color Space:");
394
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
395
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
397
str = ctk_gvio_get_format_name(colorSpaceFormatNames,
398
channel_info.color_space);
399
label_str = g_strdup_printf("%s", str);
400
label = gtk_label_new(label_str);
401
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
402
gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
406
label = gtk_label_new("Bits Per Component:");
407
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
408
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
410
str = ctk_gvio_get_format_name(bitFormatNames,
412
label_str = g_strdup_printf("%s", str);
413
label = gtk_label_new(label_str);
414
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
415
gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 3, 4);
419
label = gtk_label_new("Link ID:");
420
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
421
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5);
423
if (channel_info.link_id == NV_CTRL_GVI_LINK_ID_UNKNOWN) {
424
label_str = g_strdup_printf("Unknown");
426
label_str = g_strdup_printf("%d", channel_info.link_id);
428
label = gtk_label_new(label_str);
429
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
430
gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 4, 5);
435
static gboolean update_sdi_input_info(gpointer user_data)
437
CtkGvi *ctk_gvi = CTK_GVI(user_data);
438
gboolean show_detailed_info;
441
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
442
(ctk_gvi->show_detailed_info_btn));
444
/* Dump out the old list */
446
ctk_empty_container(ctk_gvi->input_info_vbox);
448
if (!show_detailed_info) {
449
gtk_widget_hide_all(GTK_WIDGET(ctk_gvi->jack_channel_omenu));
450
update_sdi_input_info_simple(ctk_gvi);
452
gtk_widget_show_all(GTK_WIDGET(ctk_gvi->jack_channel_omenu));
453
update_sdi_input_info_all(ctk_gvi);
456
gtk_widget_show_all(ctk_gvi->input_info_vbox);
461
static void show_detailed_info_button_toggled(GtkWidget *button,
464
CtkGvi *ctk_gvi = CTK_GVI(user_data);
467
active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
470
gtk_button_set_label(GTK_BUTTON(button), "Show Condensed Input Info");
472
gtk_button_set_label(GTK_BUTTON(button), "Show Detailed Input Info");
475
update_sdi_input_info(ctk_gvi);
479
GtkWidget* ctk_gvi_new(NvCtrlAttributeHandle *handle,
480
CtkConfig *ctk_config)
484
GtkWidget *hbox, *vbox, *hsep, *hseparator, *table, *button;
485
GtkWidget *banner, *label;
486
gchar *bus, *pci_bus_id, *irq;
489
gchar *firmware_version;
492
/* make sure we have a handle */
494
g_return_val_if_fail(handle != NULL, NULL);
497
* get the static data that we will display below
500
/* Firmware Version */
502
ret = NvCtrlGetStringAttribute(handle,
503
NV_CTRL_STRING_GVIO_FIRMWARE_VERSION,
505
if (ret != NvCtrlSuccess) {
506
firmware_version = g_strdup("Unable to determine");
509
/* Get Bus related information */
511
get_bus_related_info(handle, &bus, &pci_bus_id);
515
ret = NvCtrlGetAttribute(handle, NV_CTRL_IRQ, &tmp);
516
if (ret != NvCtrlSuccess) {
519
irq = g_strdup_printf("%d", tmp);
522
/* create the CtkGvi object */
524
object = g_object_new(CTK_TYPE_GVI, NULL);
526
ctk_gvi = CTK_GVI(object);
527
ctk_gvi->handle = handle;
528
ctk_gvi->ctk_config = ctk_config;
530
/* Query static GVI properties */
532
ret = NvCtrlGetAttribute(handle, NV_CTRL_GVI_NUM_JACKS,
533
&(ctk_gvi->num_jacks));
534
if (ret != NvCtrlSuccess) {
535
ctk_gvi->num_jacks = 0;
538
ret = NvCtrlGetAttribute(handle, NV_CTRL_GVI_MAX_CHANNELS_PER_JACK,
539
&(ctk_gvi->max_channels_per_jack));
540
if (ret != NvCtrlSuccess) {
541
ctk_gvi->max_channels_per_jack = 0;
544
/* set container properties for the CtkGvi widget */
546
gtk_box_set_spacing(GTK_BOX(ctk_gvi), 5);
550
banner = ctk_banner_image_new(BANNER_ARTWORK_GVI);
551
gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0);
554
vbox = gtk_vbox_new(FALSE, 5);
555
gtk_box_pack_start(GTK_BOX(object), vbox, TRUE, TRUE, 0);
557
hbox = gtk_hbox_new(FALSE, 0);
558
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
560
label = gtk_label_new("GVI Device Information");
561
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
563
hseparator = gtk_hseparator_new();
564
gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5);
566
table = gtk_table_new(6, 2, FALSE);
567
gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
568
gtk_table_set_row_spacings(GTK_TABLE(table), 3);
569
gtk_table_set_col_spacings(GTK_TABLE(table), 15);
570
gtk_container_set_border_width(GTK_CONTAINER(table), 5);
572
add_table_row(table, 0,
573
0, 0.5, "Firmware Version:",
574
0, 0.5, firmware_version);
576
add_table_row(table, 2,
579
add_table_row(table, 3,
583
add_table_row(table, 5,
586
g_free(firmware_version);
592
hbox = gtk_hbox_new(FALSE, 0);
593
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
595
label = gtk_label_new("Input Information");
596
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
598
hsep = gtk_hseparator_new();
599
gtk_box_pack_start(GTK_BOX(hbox), hsep, TRUE, TRUE, 5);
601
/* Jack+Channel selection dropdown (hidden in condensed view) */
603
ctk_gvi->jack_channel_omenu = create_jack_channel_menu(ctk_gvi);
604
gtk_box_pack_start(GTK_BOX(vbox),
605
ctk_gvi->jack_channel_omenu, FALSE, FALSE, 0);
607
/* Jack input info box */
609
ctk_gvi->input_info_vbox = gtk_vbox_new(FALSE, 10);
610
gtk_container_set_border_width(GTK_CONTAINER(ctk_gvi->input_info_vbox), 5);
611
gtk_box_pack_start(GTK_BOX(vbox),
612
ctk_gvi->input_info_vbox, FALSE, FALSE, 0);
614
/* Register a timer callback to update the video format info */
615
s = g_strdup_printf("Graphics Video In (GVI %d)",
616
NvCtrlGetTargetId(handle));
618
ctk_config_add_timer(ctk_gvi->ctk_config,
619
DEFAULT_UPDATE_VIDEO_FORMAT_INFO_TIME_INTERVAL,
621
(GSourceFunc) update_sdi_input_info,
625
/* Condensed/Detailed view toggle button */
627
button = gtk_toggle_button_new_with_label("Show Detailed Input Info");
628
ctk_gvi->show_detailed_info_btn = button;
630
hbox = gtk_hbox_new(FALSE, 5);
632
gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 5);
633
gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
635
g_signal_connect(G_OBJECT(button), "toggled",
636
G_CALLBACK(show_detailed_info_button_toggled),
637
GTK_OBJECT(ctk_gvi));
639
gtk_widget_show_all(GTK_WIDGET(ctk_gvi));
641
update_sdi_input_info(ctk_gvi);
643
return GTK_WIDGET(ctk_gvi);
646
GtkTextBuffer *ctk_gvi_create_help(GtkTextTagTable *table,
652
b = gtk_text_buffer_new(table);
654
gtk_text_buffer_get_iter_at_offset(b, &i, 0);
656
ctk_help_title(b, &i, "GVI Device Information Help");
657
ctk_help_para(b, &i, "This page in the NVIDIA "
658
"X Server Control Panel describes basic "
659
"information about the Graphics Video In "
662
ctk_help_heading(b, &i, "Firmware Version");
663
ctk_help_para(b, &i, "The Firmware Version reports the version "
664
"of the firmware running on the GVI device.");
666
ctk_help_heading(b, &i, "Bus Type");
667
ctk_help_para(b, &i, "This is the bus type which is "
668
"used to connect the NVIDIA GVI device to the rest of "
669
"your computer; possible values are AGP, PCI, "
670
"PCI Express and Integrated.");
672
ctk_help_heading(b, &i, "Bus ID");
673
ctk_help_para(b, &i, "This is the GVI device's PCI identification string, "
674
"reported in the form 'bus:device:function'. It uniquely "
675
"identifies the GVI device's location in the host system.");
677
ctk_help_heading(b, &i, "IRQ");
678
ctk_help_para(b, &i, "This is the interrupt request line assigned to "
681
ctk_help_heading(b, &i, "Fill A");
682
ctk_help_para(b, &i, "This reports the detected incoming video format on "
683
"first jack on the GVI device.");
685
ctk_help_heading(b, &i, "Key A");
686
ctk_help_para(b, &i, "This reports the detected incoming video format on "
687
"second jack on the GVI device.");
689
ctk_help_heading(b, &i, "Fill B");
690
ctk_help_para(b, &i, "This reports the detected incoming video format on "
691
"third jack on the GVI device.");
693
ctk_help_heading(b, &i, "Key B");
694
ctk_help_para(b, &i, "This reports the detected incoming video format on "
695
"fourth jack on the GVI device.");
697
ctk_help_heading(b, &i, "Sync Output");
698
ctk_help_para(b, &i, "This reports the output sync signal from "
706
void ctk_gvi_start_timer(GtkWidget *widget)
708
CtkGvi *ctk_gvi = CTK_GVI(widget);
710
/* Start the GVI timer */
712
ctk_config_start_timer(ctk_gvi->ctk_config,
713
(GSourceFunc) update_sdi_input_info,
717
void ctk_gvi_stop_timer(GtkWidget *widget)
719
CtkGvi *ctk_gvi = CTK_GVI(widget);
721
/* Stop the GVI timer */
723
ctk_config_stop_timer(ctk_gvi->ctk_config,
724
(GSourceFunc) update_sdi_input_info,