⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uchelper.c

📁 Linux下比较早的基于命令行的DVD播放器
💻 C
字号:
// Copyright (c) 2004 by Istv醤 V醨adi// This file is part of dxr3Player, a DVD player written specifically // for the DXR3 (aka Hollywood+) decoder card, but now handles other// hardware as well. These files contain a (mostly) user-space driver // for the Unichrome board found on Via's EPIA motherboards.//// The information for implementing this driver has been gathered// from the following sources://// - The DirectFB Unichrome driver//   Copyright (c) 2003 Andreas Robinson, All rights reserved.//// - Andreas Robinson's MPEG-2 decoder for the Unichrome board.//   Copyright (c) 2003 Andreas Robinson, All rights reserved.//// - Via's Unichrome Framebuffer driver//   Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.//   Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.// 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 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; 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/*-----------------------------------------------------------------------------*/#include "uchelper.h"/*-----------------------------------------------------------------------------*/#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <asm/uaccess.h>/*-----------------------------------------------------------------------------*/#define MODULE_NAME "uchelper"#define MAJOR_NR 62/*-----------------------------------------------------------------------------*/#define PCI_DEVICE_ID_CLE266 0x3122#define UC_REG_IRQ         (0x200>>2)#define UC_REG_V1_STARTADDR_Y0 (0x254>>2)#define UC_REG_V_COMPOSE_MODE (0x298>>2)#define UC_V1_COMMAND_FIRE 0x80000000#define UC_IRQ_GLOBAL      0x80000000#define UC_IRQ_VBI_ENABLE  0x00080000#define UC_IRQ_VBI_PENDING 0x00000008/*-----------------------------------------------------------------------------*/static struct pci_dev* pcidev = NULL;static u32 mmio_base_physical;static u32 mmio_size;static volatile u32* mmio;DECLARE_WAIT_QUEUE_HEAD(uchelper_wait_queue);static volatile unsigned field_count = 0;static volatile unsigned flip_field = 0;static volatile unsigned flip_offset = 0;/*-----------------------------------------------------------------------------*//*-----------------------------------------------------------------------------*/static int uchelper_ctl_flip(flip_param_t* flip_param){    unsigned offset;    unsigned field;    int displayed = 0;    if (copy_from_user(&offset, &flip_param->offset, sizeof(offset)) ||        copy_from_user(&field, &flip_param->field, sizeof(field))) {        return -EFAULT;    }    if (field!=0) {        if (field<field_count) {            printk(KERN_ALERT MODULE_NAME ": Field is late, skipping (%d, %d)\n", field, field_count);            if (copy_to_user(&flip_param->displayed, &displayed, sizeof(displayed))) {                return -EFAULT;            }            return 0;        } else if (field>(field_count+100)) {            printk(KERN_ALERT MODULE_NAME ": Too long time to field (%d, %d)\n", field, field_count);            return -EINVAL;        }    }    displayed = 1;    DEFINE_WAIT(flip_wait);    int retval = 0;    flip_field = field;    flip_offset = offset;        while(flip_offset!=0 && retval==0) {        prepare_to_wait(&uchelper_wait_queue, &flip_wait, TASK_INTERRUPTIBLE);        if (flip_offset!=0) {            if (signal_pending(current)) {                flip_offset = 0;                retval = -EAGAIN;            } else {                schedule();            }        }        finish_wait(&uchelper_wait_queue, &flip_wait);    }    if (copy_to_user(&flip_param->displayed, &displayed, sizeof(displayed))) {        return -EFAULT;    }    return retval;}/*-----------------------------------------------------------------------------*/static int uchelper_ctl_get_count(unsigned* count){    unsigned c = field_count;    if (copy_to_user(count, &c, sizeof(*count))) {        return -EFAULT;    }        return 0;}/*-----------------------------------------------------------------------------*/static int uchelper_ioctl(struct inode* ino, struct file* filp,                          unsigned int cmd, unsigned long arg){    switch(cmd) {      case UCHELPER_CTL_FLIP:        return uchelper_ctl_flip((flip_param_t*)arg);      case UCHELPER_CTL_GET_COUNT:        return uchelper_ctl_get_count((unsigned*)arg);    }    return -EINVAL;}/*-----------------------------------------------------------------------------*/static irqreturn_t uchelper_irqhandler(int irq, void* dev_id, struct pt_regs* regs){    u32 status = mmio[UC_REG_IRQ];    if (status & UC_IRQ_VBI_PENDING) {        mmio[UC_REG_IRQ] = status | UC_IRQ_VBI_PENDING;        if (flip_offset!=0 && (flip_field==0 || flip_field<=field_count)) {            if (flip_field==0) {                field_count = 0;            } else if (flip_field<field_count) {                printk(KERN_ALERT MODULE_NAME ": Field is late by %u (%d<%d)\n",                       field_count-flip_field, flip_field, field_count);            }                        mmio[UC_REG_V1_STARTADDR_Y0] = flip_offset;            mmio[UC_REG_V_COMPOSE_MODE] = UC_V1_COMMAND_FIRE;                        flip_offset = 0;                        wake_up_interruptible(&uchelper_wait_queue);        }        ++field_count;    }    return IRQ_HANDLED;}/*-----------------------------------------------------------------------------*/static struct file_operations uchelper_operations = {    .owner = THIS_MODULE,    .ioctl = uchelper_ioctl};/*-----------------------------------------------------------------------------*/static int uchelper_init(void){    int retval;    u8 revision;    struct pci_dev* rev_dev;        pcidev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_CLE266, NULL);    if (pcidev==NULL) {        printk(KERN_ALERT MODULE_NAME ": No CLE266/Unichrome device is found.\n");        return -ENODEV;    }    if (pcidev->driver) {        printk(KERN_ALERT MODULE_NAME ": Another driver is aleady controlling the device.\n");        return -EBUSY;    }    mmio_base_physical = pci_resource_start(pcidev, 1);    mmio_size = pci_resource_len(pcidev, 1);    if (!request_mem_region(mmio_base_physical, mmio_size, MODULE_NAME)) {        printk(KERN_ALERT MODULE_NAME ": Cannot acquire MMIO memory region.\n");        return -EBUSY;    }    mmio = (volatile u32*)ioremap(mmio_base_physical, mmio_size);    if (mmio==NULL) {        printk(KERN_ALERT MODULE_NAME ": Cannot map MMIO memory region.\n");        release_mem_region(mmio_base_physical, mmio_size);        return -EBUSY;    }        retval = request_irq(pcidev->irq,                          uchelper_irqhandler,                         SA_SHIRQ | SA_INTERRUPT, MODULE_NAME, (void*)&mmio);    if (retval == -EINVAL) {        printk(KERN_ALERT MODULE_NAME ": No IRQ handler installed, "               "IRQ number %d is not valid.\n", pcidev->irq);    }    else if (retval == -EBUSY) {        printk(KERN_ALERT MODULE_NAME ": No IRQ handler installed, "               "IRQ %d is busy. Check BIOS.\n", pcidev->irq);    }    else if (retval < 0) {        printk(KERN_ALERT MODULE_NAME ": No IRQ handler installed. "               "Tried IRQ number %d.\n", pcidev->irq);    }    if (retval<0) {        iounmap(mmio);        release_mem_region(mmio_base_physical, mmio_size);        return -EBUSY;    }    register_chrdev(MAJOR_NR, MODULE_NAME, &uchelper_operations);    mmio[UC_REG_IRQ] |= UC_IRQ_GLOBAL | UC_IRQ_VBI_ENABLE | UC_IRQ_VBI_PENDING;    outb(0x11, 0x3d4);    outb(inb(0x3d5) | 0x30, 0x3d5);    // Enable MMIO    outb(0x10, 0x3c4);    outb(0x01, 0x3c5);    outb(0x1a, 0x3c4);        rev_dev = pci_find_slot(0, 0);    if (rev_dev!=NULL) {        pci_read_config_byte(rev_dev, 0xf6, &revision);    } else {        revision = 255;    }    printk(KERN_ALERT MODULE_NAME " installed. CLE266/Unichrome rev %u detected.\n",           (unsigned)revision);        return 0;}/*-----------------------------------------------------------------------------*/static void uchelper_exit(void){    mmio[UC_REG_IRQ] =         (mmio[UC_REG_IRQ] & ~UC_IRQ_VBI_ENABLE) | UC_IRQ_VBI_PENDING;        unregister_chrdev(MAJOR_NR, MODULE_NAME);        free_irq(pcidev->irq, (void*)&mmio);        iounmap(mmio);    release_mem_region(mmio_base_physical, mmio_size);    printk(KERN_ALERT MODULE_NAME " removed\n");}/*-----------------------------------------------------------------------------*/module_init(uchelper_init);module_exit(uchelper_exit);/*-----------------------------------------------------------------------------*/MODULE_LICENSE("GPL");/*-----------------------------------------------------------------------------*//* * Local Variables: * mode: C * c-basic-offset: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -