2011-07-30 05:25:29 +04:00
/*
* Copyright 2011 Florian Tobias Schandinat < FlorianSchandinat @ gmx . de >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation ;
* either version 2 , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS ; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/*
* generic EDID driver
*/
# include <linux/slab.h>
2012-01-12 16:52:37 +04:00
# include <linux/fb.h>
2011-07-30 05:25:29 +04:00
# include "via_aux.h"
2012-01-12 16:52:37 +04:00
# include "../edid.h"
2011-07-30 05:25:29 +04:00
static const char * name = " EDID " ;
2012-01-12 16:52:37 +04:00
static void query_edid ( struct via_aux_drv * drv )
{
struct fb_monspecs * spec = drv - > data ;
unsigned char edid [ EDID_LENGTH ] ;
bool valid = false ;
2012-02-17 10:45:01 +04:00
if ( spec ) {
2012-01-12 16:52:37 +04:00
fb_destroy_modedb ( spec - > modedb ) ;
2012-02-17 10:45:01 +04:00
} else {
2012-01-12 16:52:37 +04:00
spec = kmalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
2012-02-17 10:45:01 +04:00
if ( ! spec )
return ;
}
2012-01-12 16:52:37 +04:00
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 ) ;
}
2011-07-30 05:25:29 +04:00
void via_aux_edid_probe ( struct via_aux_bus * bus )
{
struct via_aux_drv drv = {
. bus = bus ,
. addr = 0x50 ,
2012-01-12 16:52:37 +04:00
. name = name ,
. cleanup = cleanup ,
. get_preferred_mode = get_preferred_mode } ;
query_edid ( & drv ) ;
2011-07-30 05:25:29 +04:00
/* as EDID devices can be connected/disconnected just add the driver */
via_aux_add ( & drv ) ;
}