hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
 */
/*
 * generic EDID driver
 */
 
#include <linux/slab.h>
#include <linux/fb.h>
#include "via_aux.h"
#include "../edid.h"
 
 
static const char *name = "EDID";
 
 
static void query_edid(struct via_aux_drv *drv)
{
   struct fb_monspecs *spec = drv->data;
   unsigned char edid[EDID_LENGTH];
   bool valid = false;
 
   if (spec) {
       fb_destroy_modedb(spec->modedb);
   } else {
       spec = kmalloc(sizeof(*spec), GFP_KERNEL);
       if (!spec)
           return;
   }
 
   spec->version = spec->revision = 0;
   if (via_aux_read(drv, 0x00, edid, EDID_LENGTH)) {
       fb_edid_to_monspecs(edid, spec);
       valid = spec->version || spec->revision;
   }
 
   if (!valid) {
       kfree(spec);
       spec = NULL;
   } else
       printk(KERN_DEBUG "EDID: %s %s\n", spec->manufacturer, spec->monitor);
 
   drv->data = spec;
}
 
static const struct fb_videomode *get_preferred_mode(struct via_aux_drv *drv)
{
   struct fb_monspecs *spec = drv->data;
   int i;
 
   if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL))
       return NULL;
 
   for (i = 0; i < spec->modedb_len; i++) {
       if (spec->modedb[i].flag & FB_MODE_IS_FIRST &&
           spec->modedb[i].flag & FB_MODE_IS_DETAILED)
           return &spec->modedb[i];
   }
 
   return NULL;
}
 
static void cleanup(struct via_aux_drv *drv)
{
   struct fb_monspecs *spec = drv->data;
 
   if (spec)
       fb_destroy_modedb(spec->modedb);
}
 
void via_aux_edid_probe(struct via_aux_bus *bus)
{
   struct via_aux_drv drv = {
       .bus    =    bus,
       .addr    =    0x50,
       .name    =    name,
       .cleanup    =    cleanup,
       .get_preferred_mode    =    get_preferred_mode};
 
   query_edid(&drv);
 
   /* as EDID devices can be connected/disconnected just add the driver */
   via_aux_add(&drv);
}