📄 i810tv.c
字号:
/* Hardware driver for Intel i810 LCD/TV Copyright 2002 Lars Gustavsson <lars@textalk.se> ---------------------------------------------------------- This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/random.h>#include <linux/miscdevice.h>#include <linux/smp_lock.h>#include <linux/mm.h>#include <asm/io.h>#include <asm/uaccess.h>#include "i810tv.h"/* * core module and version information */#define TV_VERSION "0.1.0"#define TV_MODULE_NAME "i810_tv"#define TV_DRIVER_NAME TV_MODULE_NAME " hardware driver " TV_VERSION#define IO_CTRL 0x5000#define IO_CTRL_LEN 0x1000#define CLKPWR_CTRL 0x6000#define CLKPWR_LEN 0x1000#define TV_ADDR 0x60000#define TV_LEN 0x1000#define TV_MINOR 42static __u8 *tv_mem, *io_mem, *clk_mem;static struct semaphore tv_open_sem;static char * print_bin( int b ) { static char bin[33]; int i; for (i=0;i<32;i++) { bin[i] = b&0x80000000?'1':'0'; b <<= 1; } bin[32]='\0'; return bin;} static inline void outlong( __u8 *base, int adr, unsigned int val ) { *((unsigned int *) ( base + adr )) = val;// writel(tv_mem+adr,val); printk("i810 set 0x%08x=%s\n", adr, print_bin(val) );}static inline unsigned int readlong( __u8 *base, int adr ) { return *((unsigned int *)(base+adr));// return readl(tv_mem+adr);}static int tv_dev_open (struct inode *inode, struct file *filp){ return 0;}static int tv_dev_release (struct inode *inode, struct file *filp){ return 0;}static int tv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static struct file_operations tv_chrdev_ops = { owner: THIS_MODULE, open: tv_dev_open, release: tv_dev_release, ioctl: tv_ioctl,};static struct miscdevice tv_miscdev = { TV_MINOR, TV_MODULE_NAME, &tv_chrdev_ops,};static int __init tv_init_one (struct pci_dev *dev){ unsigned long cadr; int rc, i; u8 hw_status; rc = misc_register (&tv_miscdev); if (rc) { printk ("cannot register misc device\n"); goto err_out; } cadr = dev->resource[1].start; printk("0x%08x\n", cadr ); tv_mem = ioremap (cadr + TV_ADDR, TV_LEN); if (tv_mem == NULL) { printk ("cannot ioremap TV Memory\n"); rc = -EBUSY; goto err_out_free_miscdev; } io_mem = ioremap_nocache(cadr + IO_CTRL, IO_CTRL_LEN ); if (io_mem == NULL) { iounmap(tv_mem); printk ("cannot ioremap io ctrl memory\n"); rc = -EBUSY; goto err_out_free_miscdev; } clk_mem = ioremap_nocache(cadr + CLKPWR_CTRL, CLKPWR_LEN ); if (clk_mem == NULL) { iounmap(tv_mem); iounmap(io_mem); printk ("cannot ioremap io ctrl memory\n"); rc = -EBUSY; goto err_out_free_miscdev; } for(i=0;i<0x20;i+=4) printk("0x600%02x: 0x%08x\n", i, readlong(tv_mem,i)); printk("---- clock ----\n"); for(i=0;i<=0x14;i+=4) printk("0x60%02x: 0x%08x\n", i, readlong(clk_mem,i)); printk("0x%08x\n", readlong(clk_mem,0x14)); return 0;err_out_free_map: iounmap (tv_mem);err_out_free_miscdev: misc_deregister (&tv_miscdev);err_out: return rc;}/* * Data for PCI driver interface * * This data only exists for exporting the supported * PCI ids via MODULE_DEVICE_TABLE. We do not actually * register a pci_driver, because someone else might one day * want to register another driver on the same PCI id. */static struct pci_device_id tv_pci_tbl[] __initdata = { { 0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x7125, PCI_ANY_ID, PCI_ANY_ID, }, { 0, },};MODULE_DEVICE_TABLE (pci, tv_pci_tbl);MODULE_AUTHOR("Lars Gustavsson");MODULE_DESCRIPTION("Intel i810 LCD/TV driver");MODULE_LICENSE("GPL");static int __init tv_init (void){ int rc; struct pci_dev *pdev; init_MUTEX (&tv_open_sem); pci_for_each_dev(pdev) { if (pci_match_device (tv_pci_tbl, pdev) != NULL) goto match; } return -ENODEV;match: rc = tv_init_one (pdev); if (rc) return rc; printk ("i810 LCD/TV driver loaded\n"); return 0;}static void __exit tv_cleanup (void){ misc_deregister (&tv_miscdev); iounmap (tv_mem);}static int tv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned int minor = MINOR(inode->i_rdev); int retval = 0; unsigned int memdata, tmpval; switch ( cmd ) { case TV_SET_BORDER: memdata=readlong(tv_mem,0x18); if (arg) memdata |= 0x80; else memdata &= 0xffffff7f; outlong(tv_mem,0x18,memdata); break; case TV_GET_BORDER: memdata=readlong(tv_mem,0x18) & 0x80; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_CENTER: memdata=readlong(tv_mem,0x18); if (arg) memdata |= 0x20000000; else memdata &= 0xdfffffff; outlong(tv_mem,0x18,memdata); break; case TV_GET_CENTER: memdata=readlong(tv_mem,0x18) & 0x20000000; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_VGAOUT: if (arg) { // Turn vga output on outlong(io_mem,0,0); outlong(clk_mem,0x14,3); } else { // Turn off VGA output outlong(io_mem,0,0); outlong(clk_mem,0x14,2); } break; case TV_SET_HOR_TOT: if (!arg) return -EFAULT; memdata = ((arg & 0xfff) - 1) << 16; tmpval = readlong(tv_mem,0x00) & 0xf000ffff; outlong( tv_mem, 0x00, memdata|tmpval ); tmpval = readlong(tv_mem,0x04) & 0xf000ffff; outlong( tv_mem, 0x04, memdata|tmpval ); printk("horz: 0x%08x\n",memdata|tmpval); break; case TV_SET_VER_TOT: if (!arg) return -EFAULT; memdata = ((arg & 0xfff) - 1) << 16; tmpval = readlong(tv_mem,0x0c) & 0xf000ffff; outlong( tv_mem, 0x0c, memdata|tmpval ); tmpval = readlong(tv_mem,0x10) & 0xf000ffff; outlong( tv_mem, 0x10, memdata|tmpval ); printk("vert: 0x%08x\n",memdata|tmpval); break; case TV_GET_VGAOUT: memdata=readlong(clk_mem,0x14)&1; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_TVOUT: if (arg) { // LCD/TV on outlong(tv_mem,0x00,0x03a7031f); outlong(tv_mem,0x04,0x03a7031f); outlong(tv_mem,0x08,0x04a30363); outlong(tv_mem,0x0c,0x03430257); outlong(tv_mem,0x10,0x03430257); outlong(tv_mem,0x14,0x0290028d); outlong(tv_mem,0x18,0xa0000007); outlong(clk_mem,0x00,0x00030013); outlong(clk_mem,0x04,0x00100053); outlong(clk_mem,0x08,0x0011007b); outlong(clk_mem,0x0c,0x0001000a); outlong(clk_mem,0x10,0x30404040); } else { outlong(tv_mem,0x18,0x00000000); outlong(clk_mem,0x00,0x00030013); outlong(clk_mem,0x04,0x00100053); outlong(clk_mem,0x08,0x0011007b); outlong(clk_mem,0x0c,0x00030013); outlong(clk_mem,0x10,0x40404040); } break; case TV_GET_VSYNC_START: memdata=readlong(tv_mem,0x14)&0x00000fff; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_VSYNC_START: memdata=readlong(tv_mem,0x14)&0xfffff000; memdata |= (arg & 0xfff); outlong(tv_mem,0x14,memdata); break; case TV_GET_VSYNC_END: memdata=(readlong(tv_mem,0x14)>>16)&0x00000fff; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_VSYNC_END: memdata=readlong(tv_mem,0x14)&0xf000ffff; memdata |= ((arg&0xfff)<<16); outlong(tv_mem,0x14,memdata); break; case TV_GET_HSYNC_START: memdata=readlong(tv_mem,0x08)&0x00000fff; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_HSYNC_START: memdata=readlong(tv_mem,0x08)&0xfffff000; memdata |= (arg & 0xfff); outlong(tv_mem,0x08,memdata); break; case TV_GET_HSYNC_END: memdata=(readlong(tv_mem,0x08)>>16)&0x00000fff; if (copy_to_user((int *) arg, &memdata, sizeof(int))) return -EFAULT; break; case TV_SET_HSYNC_END: memdata=readlong(tv_mem,0x08)&0xf000ffff; memdata |= ((arg&0xfff)<<16); outlong(tv_mem,0x08,memdata); break; default: retval = -EINVAL; } return retval;}module_init (tv_init);module_exit (tv_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -