vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / nvidia / engine / nv_i2c.c
blob0393230f87a4bf8a338d9197c8cf3dd32538ce8a
1 /*
2 * i2c interface.
3 * Bus should be run at max. 100kHz: see original Philips I2C specification
4 *
5 * Rudolf Cornelissen 12/2002-10/2009
6 */
8 #define MODULE_BIT 0x00004000
10 #include "nv_std.h"
12 static void i2c_DumpSpecsEDID(edid_specs* specs);
14 char i2c_flag_error (char ErrNo)
15 //error code list:
16 //0 - OK status
17 //1 - SCL locked low by device (bus is still busy)
18 //2 - SDA locked low by device (bus is still busy)
19 //3 - No Acknowledge from device (no handshake)
20 //4 - SDA not released for master to generate STOP bit
22 static char I2CError = 0;
24 if (!I2CError) I2CError = ErrNo;
25 if (ErrNo == -1) I2CError = 0;
26 return I2CError;
29 static void i2c_select_bus_set(bool set)
31 /* I/O pins set selection is only valid on dualhead cards */
32 if (!si->ps.secondary_head) return;
34 /* select GPU I/O pins set to connect to I2C 'registers' */
35 if (set) {
36 /* this setup wires the 'I2C registers' to unknown I/O pins on the GPU? */
37 NV_REG32(NV32_FUNCSEL) &= ~0x00000010;
38 NV_REG32(NV32_2FUNCSEL) |= 0x00000010;
39 } else {
40 /* this setup wires the 'I2C registers' to the I2C buses */
41 NV_REG32(NV32_2FUNCSEL) &= ~0x00000010;
42 NV_REG32(NV32_FUNCSEL) |= 0x00000010;
46 static void OutSCL(uint8 BusNR, bool Bit)
48 uint8 data;
50 switch (BusNR) {
51 case 0:
52 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
53 if (Bit)
54 CRTCW(WR_I2CBUS_0, (data | 0x20));
55 else
56 CRTCW(WR_I2CBUS_0, (data & ~0x20));
57 break;
58 case 1:
59 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
60 if (Bit)
61 CRTCW(WR_I2CBUS_1, (data | 0x20));
62 else
63 CRTCW(WR_I2CBUS_1, (data & ~0x20));
64 break;
65 case 2:
66 data = (CRTCR(WR_I2CBUS_2) & 0xf0) | 0x01;
67 if (Bit)
68 CRTCW(WR_I2CBUS_2, (data | 0x20));
69 else
70 CRTCW(WR_I2CBUS_2, (data & ~0x20));
71 break;
75 static void OutSDA(uint8 BusNR, bool Bit)
77 uint8 data;
79 switch (BusNR) {
80 case 0:
81 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
82 if (Bit)
83 CRTCW(WR_I2CBUS_0, (data | 0x10));
84 else
85 CRTCW(WR_I2CBUS_0, (data & ~0x10));
86 break;
87 case 1:
88 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
89 if (Bit)
90 CRTCW(WR_I2CBUS_1, (data | 0x10));
91 else
92 CRTCW(WR_I2CBUS_1, (data & ~0x10));
93 break;
94 case 2:
95 data = (CRTCR(WR_I2CBUS_2) & 0xf0) | 0x01;
96 if (Bit)
97 CRTCW(WR_I2CBUS_2, (data | 0x10));
98 else
99 CRTCW(WR_I2CBUS_2, (data & ~0x10));
100 break;
104 static bool InSCL(uint8 BusNR)
106 switch (BusNR) {
107 case 0:
108 if ((CRTCR(RD_I2CBUS_0) & 0x04)) return true;
109 break;
110 case 1:
111 if ((CRTCR(RD_I2CBUS_1) & 0x04)) return true;
112 break;
113 case 2:
114 if ((CRTCR(RD_I2CBUS_2) & 0x04)) return true;
115 break;
118 return false;
121 static bool InSDA(uint8 BusNR)
123 switch (BusNR) {
124 case 0:
125 if ((CRTCR(RD_I2CBUS_0) & 0x08)) return true;
126 break;
127 case 1:
128 if ((CRTCR(RD_I2CBUS_1) & 0x08)) return true;
129 break;
130 case 2:
131 if ((CRTCR(RD_I2CBUS_2) & 0x08)) return true;
132 break;
135 return false;
138 static void TXBit (uint8 BusNR, bool Bit)
140 /* send out databit */
141 if (Bit) {
142 OutSDA(BusNR, true);
143 snooze(3);
144 if (!InSDA(BusNR)) i2c_flag_error (2);
145 } else {
146 OutSDA(BusNR, false);
148 /* generate clock pulse */
149 snooze(6);
150 OutSCL(BusNR, true);
151 snooze(3);
152 if (!InSCL(BusNR)) i2c_flag_error (1);
153 snooze(6);
154 OutSCL(BusNR, false);
155 snooze(6);
158 static uint8 RXBit (uint8 BusNR)
160 uint8 Bit = 0;
162 /* set SDA so input is possible */
163 OutSDA(BusNR, true);
164 /* generate clock pulse */
165 snooze(6);
166 OutSCL(BusNR, true);
167 snooze(3);
168 if (!InSCL(BusNR)) i2c_flag_error (1);
169 snooze(3);
170 /* read databit */
171 if (InSDA(BusNR)) Bit = 1;
172 /* finish clockpulse */
173 OutSCL(BusNR, false);
174 snooze(6);
176 return Bit;
179 void i2c_bstart (uint8 BusNR)
181 /* enable access to primary head */
182 set_crtc_owner(0);
184 /* make sure SDA is high */
185 OutSDA(BusNR, true);
186 snooze(3);
187 OutSCL(BusNR, true);
188 snooze(3);
189 if (!InSCL(BusNR)) i2c_flag_error (1);
190 snooze(6);
191 /* clear SDA while SCL set (bus-start condition) */
192 OutSDA(BusNR, false);
193 snooze(6);
194 OutSCL(BusNR, false);
195 snooze(6);
197 LOG(4,("I2C: START condition generated on bus %d; status is %d\n",
198 BusNR, i2c_flag_error (0)));
201 void i2c_bstop (uint8 BusNR)
203 /* enable access to primary head */
204 set_crtc_owner(0);
206 /* make sure SDA is low */
207 OutSDA(BusNR, false);
208 snooze(3);
209 OutSCL(BusNR, true);
210 snooze(3);
211 if (!InSCL(BusNR)) i2c_flag_error (1);
212 snooze(6);
213 /* set SDA while SCL set (bus-stop condition) */
214 OutSDA(BusNR, true);
215 snooze(3);
216 if (!InSDA(BusNR)) i2c_flag_error (4);
217 snooze(3);
219 LOG(4,("I2C: STOP condition generated on bus %d; status is %d\n",
220 BusNR, i2c_flag_error (0)));
223 uint8 i2c_readbyte(uint8 BusNR, bool Ack)
225 uint8 cnt, bit, byte = 0;
227 /* enable access to primary head */
228 set_crtc_owner(0);
230 /* read data */
231 for (cnt = 8; cnt > 0; cnt--) {
232 byte <<= 1;
233 bit = RXBit (BusNR);
234 byte += bit;
236 /* send acknowledge */
237 TXBit (BusNR, Ack);
239 LOG(4,("I2C: read byte ($%02x) from bus #%d; status is %d\n",
240 byte, BusNR, i2c_flag_error(0)));
242 return byte;
245 bool i2c_writebyte (uint8 BusNR, uint8 byte)
247 uint8 cnt;
248 bool bit;
249 uint8 tmp = byte;
251 /* enable access to primary head */
252 set_crtc_owner(0);
254 /* write data */
255 for (cnt = 8; cnt > 0; cnt--) {
256 bit = (tmp & 0x80);
257 TXBit (BusNR, bit);
258 tmp <<= 1;
260 /* read acknowledge */
261 bit = RXBit (BusNR);
262 if (bit) i2c_flag_error (3);
264 LOG(4,("I2C: written byte ($%02x) to bus #%d; status is %d\n",
265 byte, BusNR, i2c_flag_error(0)));
267 return bit;
270 void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size)
272 uint8 cnt;
274 for (cnt = 0; cnt < size; cnt++)
275 buf[cnt] = i2c_readbyte(BusNR, buf[cnt]);
278 void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size)
280 uint8 cnt;
282 for (cnt = 0; cnt < size; cnt++)
283 i2c_writebyte(BusNR, buf[cnt]);
286 status_t i2c_init(void)
288 uint8 bus, buses;
289 bool *i2c_bus = &(si->ps.i2c_bus0);
290 status_t result = B_ERROR;
292 LOG(4,("I2C: searching for wired I2C buses...\n"));
294 /* select GPU I/O pins for I2C buses */
295 i2c_select_bus_set(false);
297 /* enable access to primary head */
298 set_crtc_owner(0);
300 /* on some NV40 architecture cards the i2c busses can be disabled: enable them */
301 if (si->ps.card_arch == NV40A)
302 CRTCW(I2C_LOCK ,(CRTCR(I2C_LOCK) | 0x04));
304 /* preset no board wired buses */
305 si->ps.i2c_bus0 = false;
306 si->ps.i2c_bus1 = false;
307 si->ps.i2c_bus2 = false;
309 /* set number of buses to test for */
310 buses = 2;
312 /* newer cards (can) have a third bus.. */
313 if (((si->ps.card_arch == NV10A) && (si->ps.card_type >= NV17)) || (si->ps.card_arch >= NV30A))
314 buses = 3;
316 /* find existing buses */
317 for (bus = 0; bus < buses; bus++) {
318 /* reset status */
319 i2c_flag_error (-1);
320 snooze(6);
321 /* init and/or stop I2C bus */
322 i2c_bstop(bus);
323 /* check for hardware coupling of SCL and SDA -out and -in lines */
324 snooze(6);
325 OutSCL(bus, false);
326 snooze(3);
327 OutSDA(bus, true);
328 snooze(3);
329 if (InSCL(bus) || !InSDA(bus)) continue;
330 snooze(3);
331 OutSCL(bus, true);
332 snooze(3);
333 OutSDA(bus, false);
334 snooze(3);
335 if (!InSCL(bus) || InSDA(bus)) continue;
336 i2c_bus[bus] = true;
337 snooze(3);
338 /* re-init bus */
339 i2c_bstop(bus);
342 for (bus = 0; bus < buses; bus++) {
343 if (i2c_bus[bus]) {
344 LOG(4,("I2C: bus #%d wiring check: passed\n", bus));
345 result = B_OK;
346 } else {
347 LOG(4,("I2C: bus #%d wiring check: failed\n", bus));
351 i2c_DetectScreens();
352 LOG(4,("I2C: dumping EDID specs for connector 1:\n"));
353 i2c_DumpSpecsEDID(&si->ps.con1_screen);
354 LOG(4,("I2C: dumping EDID specs for connector 2:\n"));
355 i2c_DumpSpecsEDID(&si->ps.con2_screen);
357 return result;
360 /*** DDC/EDID library use ***/
361 typedef struct {
362 uint8 port;
363 } ddc_port_info;
365 /* Dump EDID info in driver's logfile */
366 static void
367 i2c_DumpEDID(edid1_info *edid)
369 int i, j;
371 LOG(4,("Vendor: %s\n", edid->vendor.manufacturer));
372 LOG(4,("Product ID: %d\n", (int)edid->vendor.prod_id));
373 LOG(4,("Serial #: %d\n", (int)edid->vendor.serial));
374 LOG(4,("Produced in week/year: %d/%d\n", edid->vendor.week, edid->vendor.year));
376 LOG(4,("EDID version: %d.%d\n", edid->version.version, edid->version.revision));
378 LOG(4,("Type: %s\n", edid->display.input_type ? "Digital" : "Analog"));
379 LOG(4,("Size: %d cm x %d cm\n", edid->display.h_size, edid->display.v_size));
380 LOG(4,("Gamma=%.3f\n", (edid->display.gamma + 100) / 100.0));
381 LOG(4,("White (X,Y)=(%.3f,%.3f)\n", edid->display.white_x / 1024.0,
382 edid->display.white_y / 1024.0));
384 LOG(4,("Supported Future Video Modes:\n"));
385 for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
386 if (edid->std_timing[i].h_size <= 256)
387 continue;
389 LOG(4,("%dx%d@%dHz (id=%d)\n",
390 edid->std_timing[i].h_size, edid->std_timing[i].v_size,
391 edid->std_timing[i].refresh, edid->std_timing[i].id));
394 LOG(4,("Supported VESA Video Modes:\n"));
395 if (edid->established_timing.res_720x400x70)
396 LOG(4,("720x400@70\n"));
397 if (edid->established_timing.res_720x400x88)
398 LOG(4,("720x400@88\n"));
399 if (edid->established_timing.res_640x480x60)
400 LOG(4,("640x480@60\n"));
401 if (edid->established_timing.res_640x480x67)
402 LOG(4,("640x480x67\n"));
403 if (edid->established_timing.res_640x480x72)
404 LOG(4,("640x480x72\n"));
405 if (edid->established_timing.res_640x480x75)
406 LOG(4,("640x480x75\n"));
407 if (edid->established_timing.res_800x600x56)
408 LOG(4,("800x600@56\n"));
409 if (edid->established_timing.res_800x600x60)
410 LOG(4,("800x600@60\n"));
412 if (edid->established_timing.res_800x600x72)
413 LOG(4,("800x600@72\n"));
414 if (edid->established_timing.res_800x600x75)
415 LOG(4,("800x600@75\n"));
416 if (edid->established_timing.res_832x624x75)
417 LOG(4,("832x624@75\n"));
418 if (edid->established_timing.res_1024x768x87i)
419 LOG(4,("1024x768@87 interlaced\n"));
420 if (edid->established_timing.res_1024x768x60)
421 LOG(4,("1024x768@60\n"));
422 if (edid->established_timing.res_1024x768x70)
423 LOG(4,("1024x768@70\n"));
424 if (edid->established_timing.res_1024x768x75)
425 LOG(4,("1024x768@75\n"));
426 if (edid->established_timing.res_1280x1024x75)
427 LOG(4,("1280x1024@75\n"));
429 if (edid->established_timing.res_1152x870x75)
430 LOG(4,("1152x870@75\n"));
432 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
433 edid1_detailed_monitor *monitor = &edid->detailed_monitor[i];
435 switch(monitor->monitor_desc_type) {
436 case EDID1_SERIAL_NUMBER:
437 LOG(4,("Serial Number: %s\n", monitor->data.serial_number));
438 break;
440 case EDID1_ASCII_DATA:
441 LOG(4,("Ascii Data: %s\n", monitor->data.ascii_data));
442 break;
444 case EDID1_MONITOR_RANGES:
446 edid1_monitor_range monitor_range = monitor->data.monitor_range;
448 LOG(4,("Horizontal frequency range = %d..%d kHz\n",
449 monitor_range.min_h, monitor_range.max_h));
450 LOG(4,("Vertical frequency range = %d..%d Hz\n",
451 monitor_range.min_v, monitor_range.max_v));
452 LOG(4,("Maximum pixel clock = %d MHz\n", (uint16)monitor_range.max_clock * 10));
453 break;
456 case EDID1_MONITOR_NAME:
457 LOG(4,("Monitor Name: %s\n", monitor->data.monitor_name));
458 break;
460 case EDID1_ADD_COLOUR_POINTER:
462 for (j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j) {
463 edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j];
465 if (whitepoint->index == 0)
466 continue;
468 LOG(4,("Additional whitepoint: (X,Y)=(%f,%f) gamma=%f index=%i\n",
469 whitepoint->white_x / 1024.0,
470 whitepoint->white_y / 1024.0,
471 (whitepoint->gamma + 100) / 100.0,
472 whitepoint->index));
474 break;
477 case EDID1_ADD_STD_TIMING:
479 for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) {
480 edid1_std_timing *timing = &monitor->data.std_timing[j];
482 if (timing->h_size <= 256)
483 continue;
485 LOG(4,("%dx%d@%dHz (id=%d)\n",
486 timing->h_size, timing->v_size,
487 timing->refresh, timing->id));
489 break;
492 case EDID1_IS_DETAILED_TIMING:
494 edid1_detailed_timing *timing = &monitor->data.detailed_timing;
496 LOG(4,("Additional Video Mode:\n"));
497 LOG(4,("clock=%f MHz\n", timing->pixel_clock / 100.0));
498 LOG(4,("h: (%d, %d, %d, %d)\n",
499 timing->h_active, timing->h_active + timing->h_sync_off,
500 timing->h_active + timing->h_sync_off + timing->h_sync_width,
501 timing->h_active + timing->h_blank));
502 LOG(4,("v: (%d, %d, %d, %d)\n",
503 timing->v_active, timing->v_active + timing->v_sync_off,
504 timing->v_active + timing->v_sync_off + timing->v_sync_width,
505 timing->v_active + timing->v_blank));
506 LOG(4,("size: %.1f cm x %.1f cm\n",
507 timing->h_size / 10.0, timing->v_size / 10.0));
508 LOG(4,("border: %.1f cm x %.1f cm\n",
509 timing->h_border / 10.0, timing->v_border / 10.0));
510 break;
516 /* callback for getting signals from I2C bus */
517 static status_t
518 get_signals(void *cookie, int *clk, int *data)
520 ddc_port_info *info = (ddc_port_info *)cookie;
522 *clk = *data = 0x0000;
523 if (InSCL(info->port)) *clk = 0x0001;
524 if (InSDA(info->port)) *data = 0x0001;
526 return B_OK;
529 /* callback for setting signals on I2C bus */
530 static status_t
531 set_signals(void *cookie, int clk, int data)
533 ddc_port_info *info = (ddc_port_info *)cookie;
535 if (clk)
536 OutSCL(info->port, true);
537 else
538 OutSCL(info->port, false);
540 if (data)
541 OutSDA(info->port, true);
542 else
543 OutSDA(info->port, false);
545 return B_OK;
548 /* Read EDID information from monitor via the display data channel (DDC) */
549 static status_t
550 i2c_ReadEDID(uint8 BusNR, edid1_info *edid)
552 i2c_bus bus;
553 ddc_port_info info;
555 info.port = BusNR;
557 bus.cookie = &info;
558 bus.set_signals = &set_signals;
559 bus.get_signals = &get_signals;
560 ddc2_init_timing(&bus);
562 /* select GPU I/O pins for I2C buses */
563 i2c_select_bus_set(false);
565 /* enable access to primary head */
566 set_crtc_owner(0);
568 if (ddc2_read_edid1(&bus, edid, NULL, NULL) == B_OK) {
569 LOG(4,("I2C: EDID succesfully read from monitor at bus %d\n", BusNR));
570 LOG(4,("I2C: EDID dump follows (bus %d):\n", BusNR));
571 i2c_DumpEDID(edid);
572 LOG(4,("I2C: end EDID dump (bus %d).\n", BusNR));
573 } else {
574 LOG(4,("I2C: reading EDID failed at bus %d!\n", BusNR));
575 return B_ERROR;
578 return B_OK;
581 void i2c_TestEDID(void)
583 uint8 bus;
584 edid1_info edid;
585 bool *i2c_bus = &(si->ps.i2c_bus0);
587 /* test wired bus(es) */
588 for (bus = 0; bus < 3; bus++) {
589 if (i2c_bus[bus])
590 i2c_ReadEDID(bus, &edid);
594 static status_t
595 i2c_ExtractSpecsEDID(edid1_info* edid, edid_specs* specs)
597 uint32 i;
598 edid1_detailed_timing edid_timing;
600 specs->have_full_edid = false;
601 specs->have_native_edid = false;
602 specs->timing.h_display = 0;
603 specs->timing.v_display = 0;
605 /* find the optimum (native) modeline */
606 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
607 switch(edid->detailed_monitor[i].monitor_desc_type) {
608 case EDID1_IS_DETAILED_TIMING:
609 // TODO: handle flags correctly!
610 edid_timing = edid->detailed_monitor[i].data.detailed_timing;
612 if (edid_timing.pixel_clock <= 0/* || edid_timing.sync != 3*/)
613 break;
615 /* we want the optimum (native) modeline only, widescreen if possible.
616 * So only check for horizontal display, not for vertical display. */
617 if (edid_timing.h_active <= specs->timing.h_display)
618 break;
620 specs->timing.pixel_clock = edid_timing.pixel_clock * 10;
621 specs->timing.h_display = edid_timing.h_active;
622 specs->timing.h_sync_start = edid_timing.h_active + edid_timing.h_sync_off;
623 specs->timing.h_sync_end = specs->timing.h_sync_start + edid_timing.h_sync_width;
624 specs->timing.h_total = specs->timing.h_display + edid_timing.h_blank;
625 specs->timing.v_display = edid_timing.v_active;
626 specs->timing.v_sync_start = edid_timing.v_active + edid_timing.v_sync_off;
627 specs->timing.v_sync_end = specs->timing.v_sync_start + edid_timing.v_sync_width;
628 specs->timing.v_total = specs->timing.v_display + edid_timing.v_blank;
629 specs->timing.flags = 0;
630 if (edid_timing.sync == 3) {
631 if (edid_timing.misc & 1)
632 specs->timing.flags |= B_POSITIVE_HSYNC;
633 if (edid_timing.misc & 2)
634 specs->timing.flags |= B_POSITIVE_VSYNC;
636 if (edid_timing.interlaced)
637 specs->timing.flags |= B_TIMING_INTERLACED;
638 break;
642 /* check if we actually got a modeline */
643 if (!specs->timing.h_display || !specs->timing.v_display) return B_ERROR;
645 /* check if the mode is at least VGA. If it's not, ignore specs */
646 if ((specs->timing.h_display < 640) || (specs->timing.v_display < 480)) {
647 LOG(4,("I2C: specsEDID: screen reports lower than VGA native mode, ignoring specs!\n"));
648 return B_ERROR;
651 /* determine screen aspect ratio */
652 specs->aspect =
653 (specs->timing.h_display / ((float)specs->timing.v_display));
655 /* determine connection type */
656 specs->digital = false;
657 if (edid->display.input_type) specs->digital = true;
659 /* and also copy full edid1_info for reference */
660 memcpy(&(specs->full_edid), edid, sizeof(specs->full_edid));
662 /* we succesfully fetched the specs we need */
663 specs->have_native_edid = true;
664 /* we also got full and valid EDID via DDC */
665 specs->have_full_edid = true;
667 return B_OK;
670 /* Dump EDID info in driver's logfile */
671 static void
672 i2c_DumpSpecsEDID(edid_specs* specs)
674 LOG(4,("I2C: specsEDID: have_native_edid: %s\n", specs->have_native_edid ? "True" : "False"));
675 if (!specs->have_native_edid) return;
676 LOG(4,("I2C: specsEDID: timing.pixel_clock %.3f Mhz\n", specs->timing.pixel_clock / 1000.0));
677 LOG(4,("I2C: specsEDID: timing.h_display %d\n", specs->timing.h_display));
678 LOG(4,("I2C: specsEDID: timing.h_sync_start %d\n", specs->timing.h_sync_start));
679 LOG(4,("I2C: specsEDID: timing.h_sync_end %d\n", specs->timing.h_sync_end));
680 LOG(4,("I2C: specsEDID: timing.h_total %d\n", specs->timing.h_total));
681 LOG(4,("I2C: specsEDID: timing.v_display %d\n", specs->timing.v_display));
682 LOG(4,("I2C: specsEDID: timing.v_sync_start %d\n", specs->timing.v_sync_start));
683 LOG(4,("I2C: specsEDID: timing.v_sync_end %d\n", specs->timing.v_sync_end));
684 LOG(4,("I2C: specsEDID: timing.v_total %d\n", specs->timing.v_total));
685 LOG(4,("I2C: specsEDID: timing.flags $%08x\n", specs->timing.flags));
686 LOG(4,("I2C: specsEDID: aspect: %1.2f\n", specs->aspect));
687 LOG(4,("I2C: specsEDID: digital: %s\n", specs->digital ? "True" : "False"));
690 /* notes:
691 * - con1 resides closest to the mainboard on for example NV25 and NV28, while for
692 * example on NV34 con2 sits closest to the mainboard.
693 * - i2c bus0 is connected to con1, and i2c bus1 is connected to con2 on all pre-NV40
694 * architecture cards. On later cards it's vice versa. These connections do not depend
695 * on the analog VGA switch setting (see nv_general_output_select()). It also does
696 * not depend on the way screens are connected to the cards (DVI/VGA, 1 or 2 screens).
697 * - on some NV40 architecture cards i2c bus2 connects to con2 instead of i2c bus0. This
698 * is confirmed on GeForce FX 6600 (NV43, id 0x0141) and GeForce 7300 (G72, id 0x01d1).
699 * - on pre-NV40 laptops i2c bus2 can connect to con2 as well: confirmed on a Geforce FX
700 * 5200 Go (NV34, id 0x0324).
701 * - con1 has CRTC1 and DAC1, and con2 has CRTC2 and DAC2 if nv_general_output_select()
702 * is set to 'straight' and there are only VGA type screens connected. */
703 void i2c_DetectScreens(void)
705 edid1_info edid;
707 si->ps.con1_screen.have_native_edid = false;
708 si->ps.con2_screen.have_native_edid = false;
709 si->ps.con1_screen.have_full_edid = false;
710 si->ps.con2_screen.have_full_edid = false;
711 si->ps.con1_screen.aspect = 0;
712 si->ps.con2_screen.aspect = 0;
714 /* check existance of bus 0 */
715 if (si->ps.i2c_bus0) {
716 /* check I2C bus 0 for an EDID capable screen */
717 if (i2c_ReadEDID(0, &edid) == B_OK) {
718 /* fetch optimum (native) modeline */
719 switch (si->ps.card_arch) {
720 case NV40A:
721 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
722 break;
723 default:
724 i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen);
725 break;
730 /* check existance of bus 1 */
731 if (si->ps.i2c_bus1) {
732 /* check I2C bus 1 for an EDID screen */
733 if (i2c_ReadEDID(1, &edid) == B_OK) {
734 /* fetch optimum (native) modeline */
735 switch (si->ps.card_arch) {
736 case NV40A:
737 i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen);
738 break;
739 default:
740 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
741 break;
746 /* check existance of bus 2 */
747 if (si->ps.i2c_bus2) {
748 /* check I2C bus 2 for an EDID screen */
749 if (i2c_ReadEDID(2, &edid) == B_OK) {
750 /* fetch optimum (native) modeline */
751 switch (si->ps.card_arch) {
752 case NV40A:
753 if (!si->ps.con2_screen.have_native_edid) {
754 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
755 } else {
756 LOG(4,("I2C: DetectScreens: WARNING, unexpected behaviour detected!\n"));
758 break;
759 default:
760 if (!si->ps.con2_screen.have_native_edid && si->ps.laptop) {
761 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen);
762 } else {
763 LOG(4,("I2C: DetectScreens: WARNING, unexpected behaviour detected!\n"));
765 break;