cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fb_ddc.c (2824B)


      1/*
      2 * drivers/video/fb_ddc.c - DDC/EDID read support.
      3 *
      4 *  Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
      5 *
      6 * This file is subject to the terms and conditions of the GNU General Public
      7 * License.  See the file COPYING in the main directory of this archive
      8 * for more details.
      9 */
     10
     11#include <linux/delay.h>
     12#include <linux/device.h>
     13#include <linux/module.h>
     14#include <linux/fb.h>
     15#include <linux/i2c-algo-bit.h>
     16#include <linux/slab.h>
     17
     18#include "../edid.h"
     19
     20#define DDC_ADDR	0x50
     21
     22static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
     23{
     24	unsigned char start = 0x0;
     25	unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
     26	struct i2c_msg msgs[] = {
     27		{
     28			.addr	= DDC_ADDR,
     29			.flags	= 0,
     30			.len	= 1,
     31			.buf	= &start,
     32		}, {
     33			.addr	= DDC_ADDR,
     34			.flags	= I2C_M_RD,
     35			.len	= EDID_LENGTH,
     36			.buf	= buf,
     37		}
     38	};
     39
     40	if (!buf) {
     41		dev_warn(&adapter->dev, "unable to allocate memory for EDID "
     42			 "block.\n");
     43		return NULL;
     44	}
     45
     46	if (i2c_transfer(adapter, msgs, 2) == 2)
     47		return buf;
     48
     49	dev_warn(&adapter->dev, "unable to read EDID block.\n");
     50	kfree(buf);
     51	return NULL;
     52}
     53
     54unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
     55{
     56	struct i2c_algo_bit_data *algo_data = adapter->algo_data;
     57	unsigned char *edid = NULL;
     58	int i, j;
     59
     60	algo_data->setscl(algo_data->data, 1);
     61
     62	for (i = 0; i < 3; i++) {
     63		/* For some old monitors we need the
     64		 * following process to initialize/stop DDC
     65		 */
     66		algo_data->setsda(algo_data->data, 1);
     67		msleep(13);
     68
     69		algo_data->setscl(algo_data->data, 1);
     70		if (algo_data->getscl) {
     71			for (j = 0; j < 5; j++) {
     72				msleep(10);
     73				if (algo_data->getscl(algo_data->data))
     74					break;
     75			}
     76			if (j == 5)
     77				continue;
     78		} else {
     79			udelay(algo_data->udelay);
     80		}
     81
     82		algo_data->setsda(algo_data->data, 0);
     83		msleep(15);
     84		algo_data->setscl(algo_data->data, 0);
     85		msleep(15);
     86		algo_data->setsda(algo_data->data, 1);
     87		msleep(15);
     88
     89		/* Do the real work */
     90		edid = fb_do_probe_ddc_edid(adapter);
     91		algo_data->setsda(algo_data->data, 0);
     92		algo_data->setscl(algo_data->data, 0);
     93		msleep(15);
     94
     95		algo_data->setscl(algo_data->data, 1);
     96		if (algo_data->getscl) {
     97			for (j = 0; j < 10; j++) {
     98				msleep(10);
     99				if (algo_data->getscl(algo_data->data))
    100					break;
    101			}
    102		} else {
    103			udelay(algo_data->udelay);
    104		}
    105
    106		algo_data->setsda(algo_data->data, 1);
    107		msleep(15);
    108		algo_data->setscl(algo_data->data, 0);
    109		algo_data->setsda(algo_data->data, 0);
    110		if (edid)
    111			break;
    112	}
    113	/* Release the DDC lines when done or the Apple Cinema HD display
    114	 * will switch off
    115	 */
    116	algo_data->setsda(algo_data->data, 1);
    117	algo_data->setscl(algo_data->data, 1);
    118
    119	adapter->class |= I2C_CLASS_DDC;
    120	return edid;
    121}
    122
    123EXPORT_SYMBOL_GPL(fb_ddc_read);
    124
    125MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
    126MODULE_DESCRIPTION("DDC/EDID reading support");
    127MODULE_LICENSE("GPL");