2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / igafb . c - - Frame buffer device for IGA 1682
*
* Copyright ( C ) 1998 Vladimir Roganov and Gleb Raiko
*
* This driver is partly based on the Frame buffer device for ATI Mach64
* and partially on VESA - related code .
*
* Copyright ( C ) 1997 - 1998 Geert Uytterhoeven
* Copyright ( C ) 1998 Bernd Harries
* Copyright ( C ) 1998 Eddie C . Dost ( ecd @ skynet . be )
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*/
/******************************************************************************
TODO :
Despite of IGA Card has advanced graphic acceleration ,
initial version is almost dummy and does not support it .
Support for video modes and acceleration must be added
together with accelerated X - Windows driver implementation .
Most important thing at this moment is that we have working
JavaEngine1 console & X with new console interface .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/nvram.h>
# include <asm/io.h>
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
# include <asm/prom.h>
2005-04-17 02:20:36 +04:00
# include <asm/pcic.h>
# endif
# include <video/iga.h>
struct pci_mmap_map {
unsigned long voff ;
unsigned long poff ;
unsigned long size ;
unsigned long prot_flag ;
unsigned long prot_mask ;
} ;
struct iga_par {
struct pci_mmap_map * mmap_map ;
unsigned long frame_buffer_phys ;
unsigned long io_base ;
} ;
struct fb_info fb_info ;
struct fb_fix_screeninfo igafb_fix __initdata = {
. id = " IGA 1682 " ,
. type = FB_TYPE_PACKED_PIXELS ,
. mmio_len = 1000
} ;
struct fb_var_screeninfo default_var = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
. xres = 640 ,
. yres = 480 ,
. xres_virtual = 640 ,
. yres_virtual = 480 ,
. bits_per_pixel = 8 ,
. red = { 0 , 8 , 0 } ,
. green = { 0 , 8 , 0 } ,
. blue = { 0 , 8 , 0 } ,
. height = - 1 ,
. width = - 1 ,
. accel_flags = FB_ACCEL_NONE ,
. pixclock = 39722 ,
. left_margin = 48 ,
. right_margin = 16 ,
. upper_margin = 33 ,
. lower_margin = 10 ,
. hsync_len = 96 ,
. vsync_len = 2 ,
. vmode = FB_VMODE_NONINTERLACED
} ;
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
2005-04-17 02:20:36 +04:00
struct fb_var_screeninfo default_var_1024x768 __initdata = {
/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
. xres = 1024 ,
. yres = 768 ,
. xres_virtual = 1024 ,
. yres_virtual = 768 ,
. bits_per_pixel = 8 ,
. red = { 0 , 8 , 0 } ,
. green = { 0 , 8 , 0 } ,
. blue = { 0 , 8 , 0 } ,
. height = - 1 ,
. width = - 1 ,
. accel_flags = FB_ACCEL_NONE ,
. pixclock = 12699 ,
. left_margin = 176 ,
. right_margin = 16 ,
. upper_margin = 28 ,
. lower_margin = 1 ,
. hsync_len = 96 ,
. vsync_len = 3 ,
. vmode = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT , FB_VMODE_NONINTERLACED
} ;
struct fb_var_screeninfo default_var_1152x900 __initdata = {
/* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
. xres = 1152 ,
. yres = 900 ,
. xres_virtual = 1152 ,
. yres_virtual = 900 ,
. bits_per_pixel = 8 ,
. red = { 0 , 8 , 0 } ,
. green = { 0 , 8 , 0 } ,
. blue = { 0 , 8 , 0 } ,
. height = - 1 ,
. width = - 1 ,
. accel_flags = FB_ACCEL_NONE ,
. pixclock = 9091 ,
. left_margin = 234 ,
. right_margin = 24 ,
. upper_margin = 34 ,
. lower_margin = 3 ,
. hsync_len = 100 ,
. vsync_len = 3 ,
. vmode = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT , FB_VMODE_NONINTERLACED
} ;
struct fb_var_screeninfo default_var_1280x1024 __initdata = {
/* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
. xres = 1280 ,
. yres = 1024 ,
. xres_virtual = 1280 ,
. yres_virtual = 1024 ,
. bits_per_pixel = 8 ,
. red = { 0 , 8 , 0 } ,
. green = { 0 , 8 , 0 } ,
. blue = { 0 , 8 , 0 } ,
. height = - 1 ,
. width = - 1 ,
. accel_flags = 0 ,
. pixclock = 7408 ,
. left_margin = 248 ,
. right_margin = 16 ,
. upper_margin = 38 ,
. lower_margin = 1 ,
. hsync_len = 144 ,
. vsync_len = 3 ,
. vmode = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT , FB_VMODE_NONINTERLACED
} ;
/*
* Memory - mapped I / O functions for Sparc PCI
*
* On sparc we happen to access I / O with memory mapped functions too .
*/
# define pci_inb(par, reg) readb(par->io_base+(reg))
# define pci_outb(par, val, reg) writeb(val, par->io_base+(reg))
static inline unsigned int iga_inb ( struct iga_par * par , unsigned int reg ,
unsigned int idx )
{
pci_outb ( par , idx , reg ) ;
return pci_inb ( par , reg + 1 ) ;
}
static inline void iga_outb ( struct iga_par * par , unsigned char val ,
unsigned int reg , unsigned int idx )
{
pci_outb ( par , idx , reg ) ;
pci_outb ( par , val , reg + 1 ) ;
}
2007-03-01 04:05:06 +03:00
# endif /* CONFIG_SPARC */
2005-04-17 02:20:36 +04:00
/*
* Very important functionality for the JavaEngine1 computer :
* make screen border black ( usign special IGA registers )
*/
static void iga_blank_border ( struct iga_par * par )
{
int i ;
#if 0
/*
* PROM does this for us , so keep this code as a reminder
* about required read from 0x3DA and writing of 0x20 in the end .
*/
( void ) pci_inb ( par , 0x3DA ) ; /* required for every access */
pci_outb ( par , IGA_IDX_VGA_OVERSCAN , IGA_ATTR_CTL ) ;
( void ) pci_inb ( par , IGA_ATTR_CTL + 1 ) ;
pci_outb ( par , 0x38 , IGA_ATTR_CTL ) ;
pci_outb ( par , 0x20 , IGA_ATTR_CTL ) ; /* re-enable visual */
# endif
/*
* This does not work as it was designed because the overscan
* color is looked up in the palette . Therefore , under X11
* overscan changes color .
*/
for ( i = 0 ; i < 3 ; i + + )
iga_outb ( par , 0 , IGA_EXT_CNTRL , IGA_IDX_OVERSCAN_COLOR + i ) ;
}
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
2006-01-15 00:21:25 +03:00
static int igafb_mmap ( struct fb_info * info ,
2005-04-17 02:20:36 +04:00
struct vm_area_struct * vma )
{
struct iga_par * par = ( struct iga_par * ) info - > par ;
unsigned int size , page , map_size = 0 ;
unsigned long map_offset = 0 ;
int i ;
if ( ! par - > mmap_map )
return - ENXIO ;
size = vma - > vm_end - vma - > vm_start ;
/* Each page, see which map applies */
for ( page = 0 ; page < size ; ) {
map_size = 0 ;
for ( i = 0 ; par - > mmap_map [ i ] . size ; i + + ) {
unsigned long start = par - > mmap_map [ i ] . voff ;
unsigned long end = start + par - > mmap_map [ i ] . size ;
unsigned long offset = ( vma - > vm_pgoff < < PAGE_SHIFT ) + page ;
if ( start > offset )
continue ;
if ( offset > = end )
continue ;
map_size = par - > mmap_map [ i ] . size - ( offset - start ) ;
map_offset = par - > mmap_map [ i ] . poff + ( offset - start ) ;
break ;
}
if ( ! map_size ) {
page + = PAGE_SIZE ;
continue ;
}
if ( page + map_size > size )
map_size = size - page ;
pgprot_val ( vma - > vm_page_prot ) & = ~ ( par - > mmap_map [ i ] . prot_mask ) ;
pgprot_val ( vma - > vm_page_prot ) | = par - > mmap_map [ i ] . prot_flag ;
if ( remap_pfn_range ( vma , vma - > vm_start + page ,
map_offset > > PAGE_SHIFT , map_size , vma - > vm_page_prot ) )
return - EAGAIN ;
page + = map_size ;
}
if ( ! map_size )
return - EINVAL ;
vma - > vm_flags | = VM_IO ;
return 0 ;
}
2007-03-01 04:05:06 +03:00
# endif /* CONFIG_SPARC */
2005-04-17 02:20:36 +04:00
static int igafb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
{
/*
* Set a single color register . The values supplied are
* already rounded down to the hardware ' s capabilities
* ( according to the entries in the ` var ' structure ) . Return
* ! = 0 for invalid regno .
*/
struct iga_par * par = ( struct iga_par * ) info - > par ;
if ( regno > = info - > cmap . len )
return 1 ;
pci_outb ( par , regno , DAC_W_INDEX ) ;
pci_outb ( par , red , DAC_DATA ) ;
pci_outb ( par , green , DAC_DATA ) ;
pci_outb ( par , blue , DAC_DATA ) ;
if ( regno < 16 ) {
switch ( info - > var . bits_per_pixel ) {
case 16 :
( ( u16 * ) ( info - > pseudo_palette ) ) [ regno ] =
( regno < < 10 ) | ( regno < < 5 ) | regno ;
break ;
case 24 :
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] =
( regno < < 16 ) | ( regno < < 8 ) | regno ;
break ;
case 32 :
{ int i ;
i = ( regno < < 8 ) | regno ;
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] = ( i < < 16 ) | i ;
}
break ;
}
}
return 0 ;
}
/*
* Framebuffer option structure
*/
static struct fb_ops igafb_ops = {
. owner = THIS_MODULE ,
. fb_setcolreg = igafb_setcolreg ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
2005-04-17 02:20:36 +04:00
. fb_mmap = igafb_mmap ,
# endif
} ;
static int __init iga_init ( struct fb_info * info , struct iga_par * par )
{
char vramsz = iga_inb ( par , IGA_EXT_CNTRL , IGA_IDX_EXT_BUS_CNTL )
& MEM_SIZE_ALIAS ;
int video_cmap_len ;
switch ( vramsz ) {
case MEM_SIZE_1M :
info - > fix . smem_len = 0x100000 ;
break ;
case MEM_SIZE_2M :
info - > fix . smem_len = 0x200000 ;
break ;
case MEM_SIZE_4M :
case MEM_SIZE_RESERVED :
info - > fix . smem_len = 0x400000 ;
break ;
}
if ( info - > var . bits_per_pixel > 8 )
video_cmap_len = 16 ;
else
video_cmap_len = 256 ;
info - > fbops = & igafb_ops ;
info - > flags = FBINFO_DEFAULT ;
fb_alloc_cmap ( & info - > cmap , video_cmap_len , 0 ) ;
if ( register_framebuffer ( info ) < 0 )
return 0 ;
2013-09-20 05:35:55 +04:00
fb_info ( info , " %s frame buffer device at 0x%08lx [%dMB VRAM] \n " ,
info - > fix . id , par - > frame_buffer_phys , info - > fix . smem_len > > 20 ) ;
2005-04-17 02:20:36 +04:00
iga_blank_border ( par ) ;
return 1 ;
}
2010-08-11 05:02:47 +04:00
static int __init igafb_init ( void )
2005-04-17 02:20:36 +04:00
{
struct fb_info * info ;
struct pci_dev * pdev ;
struct iga_par * par ;
unsigned long addr ;
int size , iga2000 = 0 ;
if ( fb_get_options ( " igafb " , NULL ) )
return - ENODEV ;
2006-12-08 13:40:18 +03:00
pdev = pci_get_device ( PCI_VENDOR_ID_INTERG ,
2005-04-17 02:20:36 +04:00
PCI_DEVICE_ID_INTERG_1682 , 0 ) ;
if ( pdev = = NULL ) {
/*
* XXX We tried to use cyber2000fb . c for IGS 2000.
* But it does not initialize the chip in JavaStation - E , alas .
*/
2006-12-08 13:40:18 +03:00
pdev = pci_get_device ( PCI_VENDOR_ID_INTERG , 0x2000 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( pdev = = NULL ) {
return - ENXIO ;
}
iga2000 = 1 ;
}
2006-12-08 13:40:18 +03:00
/* We leak a reference here but as it cannot be unloaded this is
fine . If you write unload code remember to free it in unload */
2005-04-17 02:20:36 +04:00
2009-06-17 02:34:23 +04:00
size = sizeof ( struct iga_par ) + sizeof ( u32 ) * 16 ;
2005-04-17 02:20:36 +04:00
2009-06-17 02:34:23 +04:00
info = framebuffer_alloc ( size , & pdev - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! info ) {
printk ( " igafb_init: can't alloc fb_info \n " ) ;
drivers/video: add missing pci_dev_get
pci_get_device does a pci_dev_get, so pci_dev_put needs to be called in an
error case
The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@exists@
type T1,T2;
identifier E;
statement S,S1;
expression x1,x2,x3;
expression test;
int ret != 0;
@@
struct pci_dev *E;
...
(
E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...);
if (E == NULL) S
|
if ((E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...)) == NULL) S
)
... when != pci_dev_put(...,(T1)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
(
if (E == NULL) S1
|
if (test)
+ {
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
+ }
|
if (test) {
... when != pci_dev_put(...,(T2)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
}
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:39:23 +03:00
pci_dev_put ( pdev ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
2009-06-17 02:34:23 +04:00
par = info - > par ;
2005-04-17 02:20:36 +04:00
if ( ( addr = pdev - > resource [ 0 ] . start ) = = 0 ) {
printk ( " igafb_init: no memory start \n " ) ;
kfree ( info ) ;
drivers/video: add missing pci_dev_get
pci_get_device does a pci_dev_get, so pci_dev_put needs to be called in an
error case
The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@exists@
type T1,T2;
identifier E;
statement S,S1;
expression x1,x2,x3;
expression test;
int ret != 0;
@@
struct pci_dev *E;
...
(
E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...);
if (E == NULL) S
|
if ((E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...)) == NULL) S
)
... when != pci_dev_put(...,(T1)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
(
if (E == NULL) S1
|
if (test)
+ {
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
+ }
|
if (test) {
... when != pci_dev_put(...,(T2)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
}
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:39:23 +03:00
pci_dev_put ( pdev ) ;
2005-04-17 02:20:36 +04:00
return - ENXIO ;
}
if ( ( info - > screen_base = ioremap ( addr , 1024 * 1024 * 2 ) ) = = 0 ) {
printk ( " igafb_init: can't remap %lx[2M] \n " , addr ) ;
kfree ( info ) ;
drivers/video: add missing pci_dev_get
pci_get_device does a pci_dev_get, so pci_dev_put needs to be called in an
error case
The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@exists@
type T1,T2;
identifier E;
statement S,S1;
expression x1,x2,x3;
expression test;
int ret != 0;
@@
struct pci_dev *E;
...
(
E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...);
if (E == NULL) S
|
if ((E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...)) == NULL) S
)
... when != pci_dev_put(...,(T1)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
(
if (E == NULL) S1
|
if (test)
+ {
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
+ }
|
if (test) {
... when != pci_dev_put(...,(T2)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
}
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:39:23 +03:00
pci_dev_put ( pdev ) ;
2005-04-17 02:20:36 +04:00
return - ENXIO ;
}
par - > frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK ;
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
2005-04-17 02:20:36 +04:00
/*
* The following is sparc specific and this is why :
*
* IGS2000 has its I / O memory mapped and we want
* to generate memory cycles on PCI , e . g . do ioremap ( ) ,
2011-08-15 04:02:26 +04:00
* then readb / writeb ( ) as in Documentation / io - mapping . txt .
2005-04-17 02:20:36 +04:00
*
* IGS1682 is more traditional , it responds to PCI I / O
* cycles , so we want to access it with inb ( ) / outb ( ) .
*
* On sparc , PCIC converts CPU memory access within
* phys window 0x3000 xxxx into PCI I / O cycles . Therefore
* we may use readb / writeb to access them with IGS1682 .
*
* We do not take io_base_phys from resource [ n ] . start
* on IGS1682 because that chip is BROKEN . It does not
* have a base register for I / O . We just " know " what its
* I / O addresses are .
*/
if ( iga2000 ) {
igafb_fix . mmio_start = par - > frame_buffer_phys | 0x00800000 ;
} else {
igafb_fix . mmio_start = 0x30000000 ; /* XXX */
}
if ( ( par - > io_base = ( int ) ioremap ( igafb_fix . mmio_start , igafb_fix . smem_len ) ) = = 0 ) {
printk ( " igafb_init: can't remap %lx[4K] \n " , igafb_fix . mmio_start ) ;
iounmap ( ( void * ) info - > screen_base ) ;
kfree ( info ) ;
drivers/video: add missing pci_dev_get
pci_get_device does a pci_dev_get, so pci_dev_put needs to be called in an
error case
The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@exists@
type T1,T2;
identifier E;
statement S,S1;
expression x1,x2,x3;
expression test;
int ret != 0;
@@
struct pci_dev *E;
...
(
E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...);
if (E == NULL) S
|
if ((E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...)) == NULL) S
)
... when != pci_dev_put(...,(T1)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
(
if (E == NULL) S1
|
if (test)
+ {
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
+ }
|
if (test) {
... when != pci_dev_put(...,(T2)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
}
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:39:23 +03:00
pci_dev_put ( pdev ) ;
2005-04-17 02:20:36 +04:00
return - ENXIO ;
}
/*
* Figure mmap addresses from PCI config space .
* We need two regions : for video memory and for I / O ports .
* Later one can add region for video coprocessor registers .
* However , mmap routine loops until size ! = 0 , so we put
* one additional region with size = = 0.
*/
2007-02-12 11:55:12 +03:00
par - > mmap_map = kzalloc ( 4 * sizeof ( * par - > mmap_map ) , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! par - > mmap_map ) {
printk ( " igafb_init: can't alloc mmap_map \n " ) ;
iounmap ( ( void * ) par - > io_base ) ;
iounmap ( info - > screen_base ) ;
kfree ( info ) ;
drivers/video: add missing pci_dev_get
pci_get_device does a pci_dev_get, so pci_dev_put needs to be called in an
error case
The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@exists@
type T1,T2;
identifier E;
statement S,S1;
expression x1,x2,x3;
expression test;
int ret != 0;
@@
struct pci_dev *E;
...
(
E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...);
if (E == NULL) S
|
if ((E = \(pci_get_slot\|pci_get_device\|pci_get_bus_and_slot\)(...)) == NULL) S
)
... when != pci_dev_put(...,(T1)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
(
if (E == NULL) S1
|
if (test)
+ {
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
+ }
|
if (test) {
... when != pci_dev_put(...,(T2)E,...)
when != if (E != NULL) { ... pci_dev_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
+ pci_dev_put(E);
return;
|
+ pci_dev_put(E);
return ret;
)
}
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:39:23 +03:00
pci_dev_put ( pdev ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
/*
* Set default vmode and cmode from PROM properties .
*/
{
2007-03-01 04:05:06 +03:00
struct device_node * dp = pci_device_to_OF_node ( pdev ) ;
int node = dp - > node ;
2005-04-17 02:20:36 +04:00
int width = prom_getintdefault ( node , " width " , 1024 ) ;
int height = prom_getintdefault ( node , " height " , 768 ) ;
int depth = prom_getintdefault ( node , " depth " , 8 ) ;
switch ( width ) {
case 1024 :
if ( height = = 768 )
default_var = default_var_1024x768 ;
break ;
case 1152 :
if ( height = = 900 )
default_var = default_var_1152x900 ;
break ;
case 1280 :
if ( height = = 1024 )
default_var = default_var_1280x1024 ;
break ;
default :
break ;
}
switch ( depth ) {
case 8 :
default_var . bits_per_pixel = 8 ;
break ;
case 16 :
default_var . bits_per_pixel = 16 ;
break ;
case 24 :
default_var . bits_per_pixel = 24 ;
break ;
case 32 :
default_var . bits_per_pixel = 32 ;
break ;
default :
break ;
}
}
# endif
igafb_fix . smem_start = ( unsigned long ) info - > screen_base ;
igafb_fix . line_length = default_var . xres * ( default_var . bits_per_pixel / 8 ) ;
igafb_fix . visual = default_var . bits_per_pixel < = 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR ;
info - > var = default_var ;
info - > fix = igafb_fix ;
info - > pseudo_palette = ( void * ) ( par + 1 ) ;
if ( ! iga_init ( info , par ) ) {
iounmap ( ( void * ) par - > io_base ) ;
iounmap ( info - > screen_base ) ;
kfree ( par - > mmap_map ) ;
kfree ( info ) ;
2010-08-11 05:02:47 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2007-03-01 04:05:06 +03:00
# ifdef CONFIG_SPARC
2005-04-17 02:20:36 +04:00
/*
* Add / dev / fb mmap values .
*/
/* First region is for video memory */
par - > mmap_map [ 0 ] . voff = 0x0 ;
par - > mmap_map [ 0 ] . poff = par - > frame_buffer_phys & PAGE_MASK ;
par - > mmap_map [ 0 ] . size = info - > fix . smem_len & PAGE_MASK ;
par - > mmap_map [ 0 ] . prot_mask = SRMMU_CACHE ;
par - > mmap_map [ 0 ] . prot_flag = SRMMU_WRITE ;
/* Second region is for I/O ports */
par - > mmap_map [ 1 ] . voff = par - > frame_buffer_phys & PAGE_MASK ;
par - > mmap_map [ 1 ] . poff = info - > fix . smem_start & PAGE_MASK ;
par - > mmap_map [ 1 ] . size = PAGE_SIZE * 2 ; /* X wants 2 pages */
par - > mmap_map [ 1 ] . prot_mask = SRMMU_CACHE ;
par - > mmap_map [ 1 ] . prot_flag = SRMMU_WRITE ;
2007-03-01 04:05:06 +03:00
# endif /* CONFIG_SPARC */
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-08-11 05:02:47 +04:00
static int __init igafb_setup ( char * options )
2005-04-17 02:20:36 +04:00
{
char * this_opt ;
if ( ! options | | ! * options )
return 0 ;
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
}
return 0 ;
}
module_init ( igafb_init ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-12-22 01:07:39 +04:00
static struct pci_device_id igafb_pci_tbl [ ] = {
2006-10-18 16:50:49 +04:00
{ PCI_VENDOR_ID_INTERG , PCI_DEVICE_ID_INTERG_1682 ,
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( pci , igafb_pci_tbl ) ;