#undef DEBUG
#include <linux/aperture.h>
#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/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#ifdef CONFIG_SH_DREAMCAST
#include <asm/machvec.h>
#include <mach-dreamcast/mach/sysasic.h>
#endif
#ifdef CONFIG_PVR2_DMA
#include <linux/pagemap.h>
#include <mach/dma.h>
#include <asm/dma.h>
#endif
#ifdef CONFIG_SH_STORE_QUEUES
#include <linux/uaccess.h>
#include <cpu/sq.h>
#endif
#ifndef PCI_DEVICE_ID_NEC_NEON250
#define PCI_DEVICE_ID_NEC_NEON250 …
#endif
#define DISP_BASE …
#define DISP_BRDRCOLR …
#define DISP_DIWMODE …
#define DISP_DIWADDRL …
#define DISP_DIWADDRS …
#define DISP_DIWSIZE …
#define DISP_SYNCCONF …
#define DISP_BRDRHORZ …
#define DISP_SYNCSIZE …
#define DISP_BRDRVERT …
#define DISP_DIWCONF …
#define DISP_DIWHSTRT …
#define DISP_DIWVSTRT …
#define DISP_PIXDEPTH …
#define TV_CLK …
#define VGA_CLK …
#define PAL_HTOTAL …
#define PAL_VTOTAL …
#define NTSC_HTOTAL …
#define NTSC_VTOTAL …
enum { … };
enum { … };
enum { … };
struct pvr2_params { … };
static struct pvr2_params cables[] = …;
static struct pvr2_params outputs[] = …;
static struct pvr2fb_par { … } *currentpar;
static struct fb_info *fb_info;
static struct fb_fix_screeninfo pvr2_fix = …;
static const struct fb_var_screeninfo pvr2_var = …;
static int cable_type = …;
static int video_output = …;
static int nopan = …;
static int nowrap = …;
static unsigned int do_vmode_full = …;
static unsigned int do_vmode_pan = …;
static short do_blank = …;
static unsigned int is_blanked = …;
#ifdef CONFIG_SH_STORE_QUEUES
static unsigned long pvr2fb_map;
#endif
#ifdef CONFIG_PVR2_DMA
static unsigned int shdma = PVR2_CASCADE_CHAN;
static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
#endif
static struct fb_videomode pvr2_modedb[] = …;
#define NUM_TOTAL_MODES …
#define DEFMODE_NTSC …
#define DEFMODE_PAL …
#define DEFMODE_VGA …
static int defmode = …;
static char *mode_option = …;
static inline void pvr2fb_set_pal_type(unsigned int type)
{ … }
static inline void pvr2fb_set_pal_entry(struct pvr2fb_par *par,
unsigned int regno,
unsigned int val)
{ … }
static int pvr2fb_blank(int blank, struct fb_info *info)
{ … }
static inline unsigned long get_line_length(int xres_virtual, int bpp)
{ … }
static void set_color_bitfields(struct fb_var_screeninfo *var)
{ … }
static int pvr2fb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info)
{ … }
#define PCTRA …
#define PDTRA …
#define VOUTC …
static int pvr2_init_cable(void)
{ … }
static int pvr2fb_set_par(struct fb_info *info)
{ … }
static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ … }
static void pvr2_update_display(struct fb_info *info)
{ … }
static void pvr2_init_display(struct fb_info *info)
{ … }
#define BLANK_BIT …
static void pvr2_do_blank(void)
{ … }
static irqreturn_t __maybe_unused pvr2fb_interrupt(int irq, void *dev_id)
{ … }
#ifdef CONFIG_PVR2_DMA
static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
size_t count, loff_t *ppos)
{
unsigned long dst, start, end, len;
unsigned int nr_pages;
struct page **pages;
int ret, i;
if (!info->screen_base)
return -ENODEV;
nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT;
pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
ret = pin_user_pages_fast((unsigned long)buf, nr_pages, FOLL_WRITE, pages);
if (ret < nr_pages) {
if (ret < 0) {
nr_pages = 0;
} else {
nr_pages = ret;
ret = -EINVAL;
}
goto out_unmap;
}
dma_configure_channel(shdma, 0x12c1);
dst = (unsigned long)fb_info->screen_base + *ppos;
start = (unsigned long)page_address(pages[0]);
end = (unsigned long)page_address(pages[nr_pages]);
len = nr_pages << PAGE_SHIFT;
if (start + len == end) {
if ((*ppos + len) > fb_info->fix.smem_len) {
ret = -ENOSPC;
goto out_unmap;
}
dma_write(shdma, start, 0, len);
dma_write(pvr2dma, 0, dst, len);
dma_wait_for_completion(pvr2dma);
goto out;
}
for (i = 0; i < nr_pages; i++, dst += PAGE_SIZE) {
if ((*ppos + (i << PAGE_SHIFT)) > fb_info->fix.smem_len) {
ret = -ENOSPC;
goto out_unmap;
}
dma_write_page(shdma, (unsigned long)page_address(pages[i]), 0);
dma_write_page(pvr2dma, 0, dst);
dma_wait_for_completion(pvr2dma);
}
out:
*ppos += count;
ret = count;
out_unmap:
unpin_user_pages(pages, nr_pages);
kfree(pages);
return ret;
}
#endif
static const struct fb_ops pvr2fb_ops = …;
#ifndef MODULE
static int pvr2_get_param_val(const struct pvr2_params *p, const char *s,
int size)
{ … }
#endif
static char *pvr2_get_param_name(const struct pvr2_params *p, int val,
int size)
{ … }
static int __maybe_unused pvr2fb_common_init(void)
{ … }
#ifdef CONFIG_SH_DREAMCAST
static int __init pvr2fb_dc_init(void)
{
if (!mach_is_dreamcast())
return -ENXIO;
if (pvr2_init_cable() == CT_VGA) {
fb_info->monspecs.hfmin = 30000;
fb_info->monspecs.hfmax = 70000;
fb_info->monspecs.vfmin = 60;
fb_info->monspecs.vfmax = 60;
} else {
fb_info->monspecs.hfmin = 15469;
fb_info->monspecs.hfmax = 15781;
fb_info->monspecs.vfmin = 49;
fb_info->monspecs.vfmax = 51;
}
if (video_output < 0) {
if (cable_type == CT_VGA) {
video_output = VO_VGA;
} else {
video_output = VO_NTSC;
}
}
pvr2_fix.smem_start = 0xa5000000;
pvr2_fix.smem_len = 8 << 20;
pvr2_fix.mmio_start = 0xa05f8000;
pvr2_fix.mmio_len = 0x2000;
if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED,
"pvr2 VBL handler", fb_info)) {
return -EBUSY;
}
#ifdef CONFIG_PVR2_DMA
if (request_dma(pvr2dma, "pvr2") != 0) {
free_irq(HW_EVENT_VSYNC, fb_info);
return -EBUSY;
}
#endif
return pvr2fb_common_init();
}
static void pvr2fb_dc_exit(void)
{
if (fb_info->screen_base) {
iounmap(fb_info->screen_base);
fb_info->screen_base = NULL;
}
if (currentpar->mmio_base) {
iounmap(currentpar->mmio_base);
currentpar->mmio_base = NULL;
}
free_irq(HW_EVENT_VSYNC, fb_info);
#ifdef CONFIG_PVR2_DMA
free_dma(pvr2dma);
#endif
}
#endif
#ifdef CONFIG_PCI
static int pvr2fb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{ … }
static void pvr2fb_pci_remove(struct pci_dev *pdev)
{ … }
static const struct pci_device_id pvr2fb_pci_tbl[] = …;
MODULE_DEVICE_TABLE(pci, pvr2fb_pci_tbl);
static struct pci_driver pvr2fb_pci_driver = …;
static int __init pvr2fb_pci_init(void)
{ … }
static void pvr2fb_pci_exit(void)
{ … }
#endif
#ifndef MODULE
static int __init pvr2fb_setup(char *options)
{ … }
#endif
static struct pvr2_board { … } board_driver[] __refdata = …;
static int __init pvr2fb_init(void)
{ … }
static void __exit pvr2fb_exit(void)
{ … }
module_init(…) …;
module_exit(pvr2fb_exit);
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;