Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
2
simulators/bochs/host/linux/pcidev/Make.kbuild
Normal file
2
simulators/bochs/host/linux/pcidev/Make.kbuild
Normal file
@ -0,0 +1,2 @@
|
||||
obj-m += pcidev.o
|
||||
|
||||
75
simulators/bochs/host/linux/pcidev/Makefile.in
Normal file
75
simulators/bochs/host/linux/pcidev/Makefile.in
Normal file
@ -0,0 +1,75 @@
|
||||
ifneq ($(KERNELRELEASE), )
|
||||
# linux kernel 2.6 kbuild invocation
|
||||
include $(src)/Make.kbuild
|
||||
else
|
||||
# command prompt invocation or linux kernel 2.4 build
|
||||
|
||||
KERNELDIR = @KERNELDIR@
|
||||
CC = @CC@
|
||||
LSMOD = @LSMOD@
|
||||
INSMOD = @INSMOD@
|
||||
RMMOD = @RMMOD@
|
||||
DEPMOD = @DEPMOD@
|
||||
KERNEL_MODULE_SUFFIX = @KERNEL_MODULE_SUFFIX@
|
||||
|
||||
MODULE_NAME = pcidev
|
||||
MODULE_FILE = $(MODULE_NAME).$(KERNEL_MODULE_SUFFIX)
|
||||
|
||||
PCIDEV_MODULE_MAKE_ALL = @PCIDEV_MODULE_MAKE_ALL@
|
||||
|
||||
CFLAGS = -Wstrict-prototypes -Wno-trigraphs -g -fno-strict-aliasing -fno-common -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wall
|
||||
|
||||
|
||||
.PHONY : all
|
||||
all : $(PCIDEV_MODULE_MAKE_ALL)
|
||||
|
||||
|
||||
.PHONY : all-kernel24
|
||||
all-kernel24 : $(MODULE_FILE)
|
||||
|
||||
$(MODULE_FILE) : pcidev.c kernel_pcidev.h
|
||||
|
||||
|
||||
.PHONY : all-kernel26
|
||||
all-kernel26 :
|
||||
$(MAKE) -C $(KERNELDIR) SUBDIRS=$(shell pwd) modules
|
||||
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
@RMCOMMAND@ *.o *~ core *.mod.* .*.cmd *.ko
|
||||
|
||||
.PHONY : dist-clean
|
||||
dist-clean: clean
|
||||
@RMCOMMAND@ Makefile
|
||||
|
||||
|
||||
.PHONY : devices
|
||||
devices:
|
||||
@DEVICE="/dev/pcidev" ; \
|
||||
if test \! -c $$DEVICE ; then \
|
||||
echo "Adding $$DEVICE ..." ; \
|
||||
mknod $$DEVICE c 240 0 ; \
|
||||
chmod a+wr $$DEVICE ; \
|
||||
ls -l $$DEVICE ; \
|
||||
else \
|
||||
echo "Device $$DEVICE already exists." ; \
|
||||
fi
|
||||
|
||||
|
||||
# works only under linux of course
|
||||
.PHONY : install
|
||||
install:
|
||||
@if test $$USER != "root" ; then \
|
||||
echo "Only root can install." ; \
|
||||
exit 1 ; \
|
||||
fi ; \
|
||||
if $(LSMOD) | grep -q $(MODULE_NAME) ; then \
|
||||
echo "Unloading $(MODULE_NAME) ..." ; \
|
||||
$(RMMOD) $(MODULE_NAME) ; \
|
||||
fi ; \
|
||||
echo "Loading $(MODULE_NAME) ..." ; \
|
||||
$(INSMOD) $(MODULE_FILE) ; \
|
||||
echo "Done."
|
||||
|
||||
endif
|
||||
93
simulators/bochs/host/linux/pcidev/kernel_pcidev.h
Normal file
93
simulators/bochs/host/linux/pcidev/kernel_pcidev.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* PCIDEV: PCI host device mapping
|
||||
* Copyright (C) 2003 Frank Cornelis <fcorneli@pandora.be>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef _KERNEL_PCIDEV_H
|
||||
#define _KERNEL_PCIDEV_H
|
||||
|
||||
#define PCIDEV_MAJOR 240
|
||||
#define PCIDEV_NAME "pcidev"
|
||||
|
||||
#define PCIDEV_COUNT_RESOURCES 6
|
||||
|
||||
struct pcidev_find_struct {
|
||||
unsigned long vendorID;
|
||||
unsigned long deviceID;
|
||||
unsigned long bus;
|
||||
unsigned long device;
|
||||
unsigned long func;
|
||||
struct {
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
unsigned long flags; // see linux/ioport.h
|
||||
} resources [PCIDEV_COUNT_RESOURCES];
|
||||
};
|
||||
|
||||
// we copied these values from linux/ioport.h since these
|
||||
// are not accessible from within user space code
|
||||
#define PCIDEV_RESOURCE_IO 0x100
|
||||
#define PCIDEV_RESOURCE_MEM 0x200
|
||||
|
||||
struct pcidev_io_struct {
|
||||
unsigned long address;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
#define PCIDEV_IOCTL_MAGIC 'p'
|
||||
#define PCIDEV_IOCTL_FIND _IOWR(PCIDEV_IOCTL_MAGIC, 0, struct pcidev_find_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_READ_CONFIG_BYTE _IOWR(PCIDEV_IOCTL_MAGIC, 1, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_CONFIG_WORD _IOWR(PCIDEV_IOCTL_MAGIC, 2, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_CONFIG_DWORD _IOWR(PCIDEV_IOCTL_MAGIC, 3, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_WRITE_CONFIG_BYTE _IOR(PCIDEV_IOCTL_MAGIC, 4, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_CONFIG_WORD _IOR(PCIDEV_IOCTL_MAGIC, 5, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_CONFIG_DWORD _IOR(PCIDEV_IOCTL_MAGIC, 6, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_INTERRUPT _IO(PCIDEV_IOCTL_MAGIC, 7)
|
||||
#define PCIDEV_IOCTL_INTERRUPT_TEST _IO(PCIDEV_IOCTL_MAGIC, 8)
|
||||
|
||||
#define PCIDEV_IOCTL_READ_IO_BYTE _IOWR(PCIDEV_IOCTL_MAGIC, 9, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_IO_WORD _IOWR(PCIDEV_IOCTL_MAGIC, 10, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_IO_DWORD _IOWR(PCIDEV_IOCTL_MAGIC, 11, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_WRITE_IO_BYTE _IOR(PCIDEV_IOCTL_MAGIC, 12, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_IO_WORD _IOR(PCIDEV_IOCTL_MAGIC, 13, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_IO_DWORD _IOR(PCIDEV_IOCTL_MAGIC, 14, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_READ_MEM_BYTE _IOWR(PCIDEV_IOCTL_MAGIC, 15, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_MEM_WORD _IOWR(PCIDEV_IOCTL_MAGIC, 16, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_READ_MEM_DWORD _IOWR(PCIDEV_IOCTL_MAGIC, 17, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_WRITE_MEM_BYTE _IOR(PCIDEV_IOCTL_MAGIC, 18, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_MEM_WORD _IOR(PCIDEV_IOCTL_MAGIC, 19, struct pcidev_io_struct)
|
||||
#define PCIDEV_IOCTL_WRITE_MEM_DWORD _IOR(PCIDEV_IOCTL_MAGIC, 20, struct pcidev_io_struct)
|
||||
|
||||
#define PCIDEV_IOCTL_PROBE_CONFIG_DWORD _IOWR(PCIDEV_IOCTL_MAGIC, 21, struct pcidev_io_struct)
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct pcidev_struct {
|
||||
struct pci_dev *dev;
|
||||
int pid; // send irq signals to this task
|
||||
struct timer_list irq_timer; // for testing the irq signals
|
||||
void *mapped_mem [PCIDEV_COUNT_RESOURCES];
|
||||
};
|
||||
|
||||
#endif // __KERNEL__
|
||||
|
||||
#endif // _KERNEL_PCIDEV_H
|
||||
481
simulators/bochs/host/linux/pcidev/pcidev.c
Normal file
481
simulators/bochs/host/linux/pcidev/pcidev.c
Normal file
@ -0,0 +1,481 @@
|
||||
/*
|
||||
* PCIDEV: PCI host device mapping
|
||||
* Copyright (C) 2003, 2004 Frank Cornelis <fcorneli@pandora.be>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
* Create the PCIDEV using:
|
||||
* mknod /dev/pcidev c 240 0
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "kernel_pcidev.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Frank Cornelis <fcorneli@pandora.be>");
|
||||
MODULE_DESCRIPTION("PCI Host Device Mapper Driver");
|
||||
MODULE_SUPPORTED_DEVICE("pcidev");
|
||||
|
||||
//EXPORT_NO_SYMBOLS;
|
||||
|
||||
|
||||
static char *pcidev_name = PCIDEV_NAME;
|
||||
|
||||
static int pcidev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pcidev_struct *pcidev = kmalloc(sizeof(struct pcidev_struct), GFP_KERNEL);
|
||||
int idx;
|
||||
if (!pcidev)
|
||||
goto out;
|
||||
pcidev->dev = NULL;
|
||||
pcidev->pid = 0;
|
||||
for (idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++)
|
||||
pcidev->mapped_mem[idx] = NULL;
|
||||
init_timer(&pcidev->irq_timer);
|
||||
pcidev->irq_timer.function = NULL; // no test irq signaling
|
||||
out:
|
||||
file->private_data = pcidev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pcidev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pcidev_struct *pcidev = (struct pcidev_struct *)file->private_data;
|
||||
int idx;
|
||||
if (!pcidev)
|
||||
return 0;
|
||||
if (!pcidev->dev)
|
||||
goto out;
|
||||
if (pcidev->irq_timer.function)
|
||||
del_timer_sync(&pcidev->irq_timer);
|
||||
if (pcidev->pid) {
|
||||
u8 irq;
|
||||
pci_read_config_byte(pcidev->dev, PCI_INTERRUPT_PIN, &irq);
|
||||
pci_read_config_byte(pcidev->dev, PCI_INTERRUPT_LINE, &irq);
|
||||
free_irq(irq, (void *)pcidev->pid);
|
||||
}
|
||||
for (idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++)
|
||||
if (pcidev->mapped_mem[idx])
|
||||
iounmap(pcidev->mapped_mem[idx]);
|
||||
pci_release_regions(pcidev->dev);
|
||||
out:
|
||||
kfree(file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
|
||||
// linux kernel 2.4
|
||||
typedef void irqreturn_t;
|
||||
#define IRQ_NONE
|
||||
#endif
|
||||
|
||||
|
||||
static irqreturn_t pcidev_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int pid = (int)dev_id;
|
||||
struct task_struct *task;
|
||||
read_lock(&tasklist_lock);
|
||||
task = find_task_by_pid(pid);
|
||||
if (task)
|
||||
send_sig_info(SIGUSR1, (struct siginfo *)1, task); // XXX: should be converted to real-time signals
|
||||
read_unlock(&tasklist_lock);
|
||||
return IRQ_NONE;
|
||||
/*
|
||||
* we cannot possible say IRQ_HANDLED because we simply
|
||||
* don't know yet... only bochs could tell
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static void irq_test_timer(unsigned long data)
|
||||
{
|
||||
struct task_struct *task;
|
||||
struct pcidev_struct *pcidev = (struct pcidev_struct *)data;
|
||||
read_lock(&tasklist_lock);
|
||||
task = find_task_by_pid(pcidev->pid);
|
||||
if (task)
|
||||
send_sig_info(SIGUSR1, (struct siginfo *)1, task);
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
//printk(KERN_INFO "irq_test_timer\n");
|
||||
init_timer(&pcidev->irq_timer);
|
||||
pcidev->irq_timer.data = data;
|
||||
pcidev->irq_timer.function = irq_test_timer;
|
||||
pcidev->irq_timer.expires = jiffies + HZ;
|
||||
add_timer(&pcidev->irq_timer);
|
||||
}
|
||||
|
||||
|
||||
static int pcidev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pcidev_struct *pcidev = (struct pcidev_struct *)file->private_data;
|
||||
if (!pcidev)
|
||||
return -EIO;
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_FIND: {
|
||||
struct pcidev_find_struct *find;
|
||||
struct pci_dev *dev;
|
||||
unsigned long vendorID, deviceID;
|
||||
int idx;
|
||||
if (pcidev->dev)
|
||||
return -EIO; // only alloc once for now
|
||||
if (!access_ok(VERIFY_WRITE, (void *)arg, sizeof(struct pcidev_find_struct)))
|
||||
return -EFAULT;
|
||||
find = (struct pcidev_find_struct *)arg;
|
||||
__get_user(vendorID, &find->vendorID);
|
||||
__get_user(deviceID, &find->deviceID);
|
||||
__put_user(-1, &find->bus);
|
||||
__put_user(-1, &find->device);
|
||||
__put_user(-1, &find->func);
|
||||
dev = pci_find_device(vendorID, deviceID, NULL);
|
||||
if (!dev)
|
||||
return -ENOENT;
|
||||
if (pci_enable_device(dev)) {
|
||||
printk(KERN_WARNING "pcidev: Could not enable the PCI device.\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (pci_set_dma_mask(dev, 0xffffffff))
|
||||
printk(KERN_WARNING "pcidev: only limited PCI busmaster DMA support.\n");
|
||||
pci_set_master(dev);
|
||||
printk(KERN_INFO "pcidev: device found at %x:%x.%d\n",
|
||||
dev->bus->number, PCI_SLOT(dev->devfn),
|
||||
PCI_FUNC(dev->devfn));
|
||||
ret = pci_request_regions(dev, pcidev_name);
|
||||
if (ret < 0)
|
||||
break;
|
||||
for (idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++) {
|
||||
if (pci_resource_flags(dev, idx) & IORESOURCE_MEM) {
|
||||
long len = pci_resource_len(dev, idx);
|
||||
unsigned long mapped_start = (unsigned long)ioremap(pci_resource_start(dev, idx), len);
|
||||
__put_user(mapped_start, &find->resources[idx].start);
|
||||
__put_user(mapped_start + len - 1, &find->resources[idx].end);
|
||||
pcidev->mapped_mem[idx] = (void *)mapped_start;
|
||||
}
|
||||
else {
|
||||
pcidev->mapped_mem[idx] = NULL;
|
||||
__put_user(pci_resource_start(dev, idx), &find->resources[idx].start);
|
||||
__put_user(pci_resource_end(dev, idx), &find->resources[idx].end);
|
||||
}
|
||||
__put_user(pci_resource_flags(dev, idx), &find->resources[idx].flags);
|
||||
}
|
||||
pcidev->dev = dev;
|
||||
__put_user(dev->bus->number, &find->bus);
|
||||
__put_user(PCI_SLOT(dev->devfn), &find->device);
|
||||
__put_user(PCI_FUNC(dev->devfn), &find->func);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_READ_CONFIG_BYTE:
|
||||
case PCIDEV_IOCTL_READ_CONFIG_WORD:
|
||||
case PCIDEV_IOCTL_READ_CONFIG_DWORD: {
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value;
|
||||
if (!pcidev->dev)
|
||||
return -EIO;
|
||||
if (!access_ok(VERIFY_WRITE, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
__put_user(-1, &io->value);
|
||||
printk(KERN_DEBUG "pcidev: reading config address %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_READ_CONFIG_BYTE:
|
||||
ret = pci_read_config_byte(pcidev->dev, address, (u8 *)&value);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_CONFIG_WORD:
|
||||
ret = pci_read_config_word(pcidev->dev, address, (u16 *)&value);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_CONFIG_DWORD:
|
||||
ret = pci_read_config_dword(pcidev->dev, address, (u32 *)&value);
|
||||
break;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
__put_user(value, &io->value);
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_BYTE:
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_WORD:
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_DWORD: {
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value;
|
||||
if (!pcidev->dev)
|
||||
return -EIO;
|
||||
if (!access_ok(VERIFY_READ, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
__get_user(value, &io->value);
|
||||
/*
|
||||
* Next tests prevent the pcidev user from remapping
|
||||
* the PCI host device since this could cause great
|
||||
* trouble because we don't own those I/O resources.
|
||||
* If the pcidev wants to remap a device he needs to
|
||||
* emulate the mapping himself and not bother the host
|
||||
* kernel about it.
|
||||
*/
|
||||
if (address == PCI_INTERRUPT_PIN) {
|
||||
printk(KERN_WARNING "pcidev: not allowed to set irq pin!\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (address == PCI_INTERRUPT_LINE) {
|
||||
printk(KERN_WARNING "pcidev: not allowed to set irq line!\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (PCI_BASE_ADDRESS_0 <= address && (address & ~3UL) <= PCI_BASE_ADDRESS_5) {
|
||||
printk(KERN_WARNING "pcidev: now allowed to change base address %d\n",
|
||||
(int)((address & ~3UL) - PCI_BASE_ADDRESS_0) / 4);
|
||||
return -EIO;
|
||||
}
|
||||
printk(KERN_DEBUG "pcidev: writing config address %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_BYTE:
|
||||
ret = pci_write_config_byte(pcidev->dev, address, (u8)value);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_WORD:
|
||||
ret = pci_write_config_word(pcidev->dev, address, (u16)value);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_CONFIG_DWORD:
|
||||
ret = pci_write_config_dword(pcidev->dev, address, (u32)value);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_INTERRUPT: {
|
||||
u8 irq;
|
||||
if (!pcidev->dev)
|
||||
return -EIO;
|
||||
ret = pci_read_config_byte(pcidev->dev, PCI_INTERRUPT_PIN, &irq);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (!irq)
|
||||
return -EIO;
|
||||
ret = pci_read_config_byte(pcidev->dev, PCI_INTERRUPT_LINE, &irq);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (arg & 1) {
|
||||
pcidev->pid = current->pid; // our dev_id
|
||||
printk(KERN_INFO "pcidev: enabling IRQ %d\n", irq);
|
||||
ret = request_irq(irq, pcidev_irqhandler, SA_SHIRQ,
|
||||
pcidev_name, (void *)current->pid);
|
||||
}
|
||||
else {
|
||||
if (!pcidev->pid)
|
||||
return -EIO;
|
||||
printk(KERN_INFO "pcidev: disabling IRQ %d\n", irq);
|
||||
free_irq(irq, (void *)pcidev->pid);
|
||||
pcidev->pid = 0;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Next ioctl is only for testing purposes.
|
||||
*/
|
||||
case PCIDEV_IOCTL_INTERRUPT_TEST: {
|
||||
ret = -EIO;
|
||||
if (!pcidev->dev)
|
||||
break;
|
||||
if (!pcidev->pid)
|
||||
break;
|
||||
if (pcidev->irq_timer.function)
|
||||
del_timer_sync(&pcidev->irq_timer);
|
||||
pcidev->irq_timer.function = NULL;
|
||||
if (arg & 1) {
|
||||
init_timer(&pcidev->irq_timer);
|
||||
pcidev->irq_timer.function = irq_test_timer;
|
||||
pcidev->irq_timer.data = (unsigned long)pcidev;
|
||||
pcidev->irq_timer.expires = jiffies + HZ;
|
||||
add_timer(&pcidev->irq_timer);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_READ_IO_BYTE:
|
||||
case PCIDEV_IOCTL_READ_IO_WORD:
|
||||
case PCIDEV_IOCTL_READ_IO_DWORD: {
|
||||
/*
|
||||
* We should probably check access rights against
|
||||
* the PCI resource list... but who cares for a
|
||||
* security hole more or less :)
|
||||
*/
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value = -1;
|
||||
if (!access_ok(VERIFY_WRITE, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
printk(KERN_DEBUG "pcidev: reading I/O port %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_READ_IO_BYTE:
|
||||
value = inb(address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_IO_WORD:
|
||||
value = inw(address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_IO_DWORD:
|
||||
value = inl(address);
|
||||
break;
|
||||
}
|
||||
__put_user(value, &io->value);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_WRITE_IO_BYTE:
|
||||
case PCIDEV_IOCTL_WRITE_IO_WORD:
|
||||
case PCIDEV_IOCTL_WRITE_IO_DWORD: {
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value;
|
||||
if (!access_ok(VERIFY_READ, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
__get_user(value, &io->value);
|
||||
printk(KERN_DEBUG "pcidev: writing I/O port %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_WRITE_IO_BYTE:
|
||||
outb(value, address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_IO_WORD:
|
||||
outw(value, address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_IO_DWORD:
|
||||
outl(value, address);
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_READ_MEM_BYTE:
|
||||
case PCIDEV_IOCTL_READ_MEM_WORD:
|
||||
case PCIDEV_IOCTL_READ_MEM_DWORD: {
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value = -1;
|
||||
if (!access_ok(VERIFY_WRITE, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
printk(KERN_DEBUG "pcidev: reading memory %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_READ_MEM_BYTE:
|
||||
value = readb((unsigned char *)address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_MEM_WORD:
|
||||
value = readw((unsigned short *)address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_READ_MEM_DWORD:
|
||||
value = readl((unsigned int *)address);
|
||||
break;
|
||||
}
|
||||
__put_user(value, &io->value);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_WRITE_MEM_BYTE:
|
||||
case PCIDEV_IOCTL_WRITE_MEM_WORD:
|
||||
case PCIDEV_IOCTL_WRITE_MEM_DWORD: {
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value;
|
||||
if (!access_ok(VERIFY_READ, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
__get_user(value, &io->value);
|
||||
printk(KERN_DEBUG "pcidev: writing memory %#x\n", (int)address);
|
||||
switch(cmd) {
|
||||
case PCIDEV_IOCTL_WRITE_MEM_BYTE:
|
||||
writeb(value, (unsigned char *)address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_MEM_WORD:
|
||||
writew(value, (unsigned short *)address);
|
||||
break;
|
||||
case PCIDEV_IOCTL_WRITE_MEM_DWORD:
|
||||
writel(value, (unsigned int *)address);
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PCIDEV_IOCTL_PROBE_CONFIG_DWORD: {
|
||||
/*
|
||||
* This ioctl allows for probing a config space value.
|
||||
* This can be used for base address size probing
|
||||
*/
|
||||
struct pcidev_io_struct *io;
|
||||
unsigned long address, value, orig_value;
|
||||
if (!pcidev->dev)
|
||||
return -EIO;
|
||||
if (!access_ok(VERIFY_WRITE, (void *)arg, sizeof(struct pcidev_io_struct)))
|
||||
return -EFAULT;
|
||||
io = (struct pcidev_io_struct *)arg;
|
||||
__get_user(address, &io->address);
|
||||
__get_user(value, &io->value);
|
||||
__put_user(-1, &io->value);
|
||||
printk(KERN_INFO "pcidev: probing config space address: %#x\n", (int)address);
|
||||
ret = pci_read_config_dword(pcidev->dev, address, (u32 *)&orig_value);
|
||||
if (ret < 0)
|
||||
break;
|
||||
pci_write_config_dword(pcidev->dev, address, (u32)value);
|
||||
pci_read_config_dword(pcidev->dev, address, (u32 *)&value);
|
||||
ret = pci_write_config_dword(pcidev->dev, address, (u32)orig_value);
|
||||
if (ret < 0)
|
||||
break;
|
||||
__put_user(value, &io->value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct file_operations pcidev_fops = {
|
||||
open: pcidev_open,
|
||||
release: pcidev_release,
|
||||
ioctl: pcidev_ioctl,
|
||||
owner: THIS_MODULE
|
||||
};
|
||||
|
||||
|
||||
|
||||
int __init init_module(void)
|
||||
{
|
||||
int result;
|
||||
printk(KERN_INFO "pcidev init\n");
|
||||
if ((result = register_chrdev(PCIDEV_MAJOR, pcidev_name, &pcidev_fops)) < 0)
|
||||
printk(KERN_WARNING "Could not register pcidev.\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void __exit cleanup_module(void)
|
||||
{
|
||||
if (unregister_chrdev(PCIDEV_MAJOR, pcidev_name) < 0)
|
||||
printk(KERN_WARNING "Could not unregister pcidev.\n");
|
||||
printk(KERN_INFO "pcidev cleanup\n");
|
||||
}
|
||||
Reference in New Issue
Block a user