Skip to content
Snippets Groups Projects
Commit 8a4bfc22 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra Committed by Alessandro Rubini
Browse files

pcie-wb: Add driver stub code

parent b15814a9
Branches
Tags
No related merge requests found
#export PATH=$PATH:/share/eldk/bin:/share/eldk/usr/bin
#export CROSS_COMPILE=ppc_4xxFP-
#export ARCH=powerpc
# This is useful if cross-compiling. Taken from kernel Makefile (CC changed)
#AS =$(CROSS_COMPILE)as
#LD =$(CROSS_COMPILE)ld
#CC =$(CROSS_COMPILE)gcc
#CPP =$(CC) -E
#AR =$(CROSS_COMPILE)ar
#NM =$(CROSS_COMPILE)nm
#STRIP =$(CROSS_COMPILE)strip
#OBJCOPY =$(CROSS_COMPILE)objcopy
#OBJDUMP =$(CROSS_COMPILE)objdump
KERNELDIR ?= /common/usr/embedded/kernel/scu/linux-2.6.33.6/
ifneq ($(KERNELRELEASE),)
obj-m := pci_char.o sleepy.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
/*
* syscalls.c
* Program to illustrate common system calls. Doesn't actually
* perform any useful function, but will later be expanded into
* a program which does.
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "pci_char.h"
#define FALSE 0
#define TRUE 1
#define BUFCOUNT 100
#define TICK 8 /* 8 ns */
int main()
{
int fd_irq; /* device file descriptor for blocking read */
int fd_rd; /* device file descriptor for non-blocking read */
unsigned int cnt_value_irq; /* buffer to hold data */
unsigned int cnt_value_rd; /* buffer to hold data */
unsigned int diff_buffer[BUFCOUNT];
int status; /* return status of system calls */
int i;
int arg;
/* open irq device */
status = fd_irq = open("/dev/pci_char0", O_RDWR);
if (status == -1) {
perror("error opening /dev/pci_char0");
return(1);
}
/* open rd device after irq device */
status = fd_rd = open("/dev/pci_char1", O_RDWR);
if (status == -1) {
perror("error opening /dev/pci_char1");
return(1);
}
/* one tick is 8ns, so 1250000 ticks give 10µs */
arg = 1250000; // 0.01s / 8*E-9s
//status = ioctl(fd_irq, SET_PERIOD, arg);
// if (status == -1) {
// perror("error from SET_PERIOD ioctl");
// return(1);
// }
//status = ioctl(fd_irq, GET_PERIOD, arg);
// if (status == -1) {
// perror("error from GET_PERIOD ioctl");
// return(1);
//} else
// printf("Period value is %d\n", status);
for (i = 0; i < BUFCOUNT; i++) {
// blocking read
status = read(fd_irq, &cnt_value_irq, sizeof(int));
if (status == -1) {
perror("error reading from fd_irq");
return(1);
}
// non-blocking read
status = read(fd_rd, &cnt_value_rd, sizeof(int));
if (status == -1) {
perror("error reading from fd_rd");
return(1);
}
diff_buffer[i] = abs(cnt_value_irq-cnt_value_rd);
}
for (i = 0; i < BUFCOUNT; i++) {
printf("%d\n", diff_buffer[i]);
}
close(fd_irq);
close(fd_rd);
return(0);
/* write some data */
// *buf = 1;
// while(1) {
// status = write(fd, buf, 1);
// if (status == -1) {
// perror("error writing to /dev/pci_char0");
// exit(1);
// }
//usleep(125000); /* wait for 250ms */
//}
/* close the device */
// status = close(fd_irq);
// if (status == -1) {
// perror("error closing /dev/pci_char0");
// return(1);
// }
/* and exit */
}
/*
* syscalls.c
* Program to illustrate common system calls. Doesn't actually
* perform any useful function, but will later be expanded into
* a program which does.
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define FALSE 0
#define TRUE 1
int main()
{
int fd; /* device file descriptor */
//int arg; /* argument for ioctl call */
unsigned char buf[1]; /* buffer to hold data */
int status; /* return status of system calls */
char up = TRUE;
/* open device */
status = fd = open("/dev/pci_char0", O_RDWR);
if (status == -1) {
perror("error opening /dev/pci_char0");
exit(1);
}
/* set a parameter using ioctl call */
//arg = 8000; /* sampling rate */
/*status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1) {
perror("error from SOUND_PCM_WRITE_RATE ioctl");
exit(1);
}*/
/* read some data */
//status = read(fd, buf, sizeof(buf));
//if (status == -1) {
// perror("error reading from /dev/dsp");
// exit(1);
//}
/* write some data */
*buf = 1;
while(1) {
status = write(fd, buf, 1);
if (status == -1) {
perror("error writing to /dev/pci_char0");
exit(1);
}
if (buf[0] == 0x80) /* turn if highest bit is set */
up = FALSE;
else if (buf[0] == 0x01)
up = TRUE;
if (up == TRUE)
buf[0] <<= 1;
else
buf[0] >>= 1;
usleep(125000); /* wait for 250ms */
}
/* close the device */
status = close(fd);
if (status == -1) {
perror("error closing /dev/pci_char0");
exit(1);
}
/* and exit */
return(0);
}
/*
* Accessing a PCI memory region using mmap() on /dev/mem
*
* Compile with 'gcc -Wall -O file.c -lpci -o peeker' (-O *is* mandatory)
*
* Run with './peeker x y z' arguments can be derived from 'lspci -tvv'
*
* Make sure (with lspci -vvs x:y.z) that "Region 0" is memory and that
* "Region 1" is I/O.
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pci/pci.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <string.h>
#include "pci_char.h"
#define PCI_MEM_LEN (1<<18)
#define COUNT 100000
int main( int argc, char *argv[]){
unsigned char* ptr_to_pci_mem;
unsigned int pci_mem_addr;
int buffer[COUNT];
int i;
FILE* fd;
/* Check IO permissions to be able to open /dev/mem
*/
if(iopl(3)){
printf("Cannot get I/O permissions (being root helps)\n");
return -1;
}
pci_mem_addr = 0xfeac0000;
//pci_mem_addr += SCU_MASTER;
fd = fopen ( "/dev/mem", "r+w");
/* ...and map the PCI memory area (man 2 mmap for more info)
*/
ptr_to_pci_mem = mmap( NULL,
PCI_MEM_LEN,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fileno(fd), pci_mem_addr);
/* Voila! Two bytes of PCI memory out from the board
* You can also use the memcpy() family of functions
*/
printf("Memory pointer: %p\n", ptr_to_pci_mem);
printf("PCI memory @%#x\n", pci_mem_addr);
for (i = 0; i< 30; i++) {
printf("addr %p : %#x\n",ptr_to_pci_mem + PCIE_BASE + 0x800+ i*4, *(ptr_to_pci_mem + PCIE_BASE + 0x800 + i*4) );
}
//printf("The 2nd byte on PCI memory is : %#x\n", *(ptr_to_pci_mem+2) );
//memcpy(buffer, ptr_to_pci_mem, COUNT);
//for (i=0; i < COUNT; i+=1) {
// buffer[i] = *(ptr_to_pci_mem++);
// //*(ptr_to_pci_mem+1) = i;
//}
munmap(ptr_to_pci_mem, PCI_MEM_LEN);
fclose(fd);
return 0;
}
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/aer.h>
#include <asm/io.h> /*outb iowrite8 */
#include <asm/spinlock.h>
#include "pci_char.h"
#define FALSE 0
#define TRUE 1
int use_mem = FALSE; /* mem or io port */
int use_msi = FALSE; /* Message Signaled Interrupts enabled */
static int major_num = 0; /* major number for char device */
static int minor_num = 0; /* minor number for char device */
static struct cdev *cdev_irq;
static struct cdev *cdev_rd;
struct pci_resource *pci_res0 = NULL; /* ptrs to resource objects */
struct pci_resource *pci_res1 = NULL;
char name_str[] = "pci_char";
char myirq = -1; /* IRQ from PCI config reg */
int instance_count = 0; /* counting connected processes for housekeeping */
static DECLARE_WAIT_QUEUE_HEAD(event_wq);
static DEFINE_SPINLOCK(snapshot_lock);
static DEFINE_SPINLOCK(period_lock);
unsigned long short_buffer = 0;
unsigned long volatile short_head;
volatile unsigned long short_tail;
static inline void short_incr_bp(volatile unsigned long *index, int delta)
{
unsigned long new = *index + delta;
barrier(); /* Don't optimize these two together */
*index = (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new;
}
struct pci_resource {
int bar; /* BAR number from 0 to 5 */
unsigned long start; /* start addr of BAR */
unsigned long end; /* end addr of BAR */
unsigned int size;
void *m_addr; /* remapped addr */
int is_mem;
};
irq_handler_t my_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int ret;
int snapl_value;
int snaph_value;
int snap_value;
unsigned char *bptr = pci_res0->m_addr;
//int written;
mb();
/* check if our device has triggered */
ret = ioread32(bptr + TMR_0_BASE);mb();
if (!(ret & 0x1))
return IRQ_NONE;
/* copy snapshot value from timer */
/* should be atomic */
spin_lock(&snapshot_lock);
/* trigger the latch of the counter value */
iowrite16(0x0, bptr + TMR_0_SNAPL);
rmb(); // has to be executed before reading
snapl_value = ioread16(bptr + TMR_0_SNAPL);rmb();
snaph_value = ioread16(bptr + TMR_0_SNAPH);rmb();
spin_unlock(&snapshot_lock);
snap_value = (int)(snaph_value << 16) | snapl_value;
//printk(KERN_ALERT "%s: snap_value = 0x%x\n", name_str, snap_value);
//snap_value = snap_value | (snaph_value << 32);
//written = sprintf((char *)short_head,"%08x\n", snap_value);
*(u32 *)short_head = snap_value;
short_incr_bp(&short_head, sizeof(u32));
/* wake up the reading process */
wake_up_interruptible(&event_wq);
/* clear the interrupting bit in the pio */
//iowrite32(0x0, bptr + PIO_BASE + EDGE_CAPTURE);
/* clear pending bit in edge capture register */
mb();
//iowrite32(0x0, bptr + TMR_EDGE_CAPTURE);
iowrite16(0x0, bptr + TMR_0_BASE);mb();
//printk(KERN_ALERT "%s: irq handler called\n", name_str);
return (irq_handler_t)IRQ_HANDLED;
}
int pci_skel_open (struct inode *inode, struct file *filp)
{
int result;
unsigned char *bptr = pci_res0->m_addr;
int arg = IRQ_RATE;
instance_count++;
iowrite16(arg, bptr + TMR_0_PERIODL);
wmb();
iowrite16(arg >> 16, bptr + TMR_0_PERIODH);
/* we have a irq number and the first process is connecting */
if (myirq >= 0 && instance_count == 1) {
result = request_irq( myirq,
(irq_handler_t)my_irq_handler,
IRQF_SHARED,
name_str,
pci_res0 /* used as dev_id */
);
if (result) {
printk(KERN_ALERT "%s: can't get IRQ %d\n", name_str, myirq);
myirq = -1;
} else {
/* enable irq */
/* enable MSI in MSI Control Register of PCI Endpoint */
result = ioread32(bptr + PCIE_BASE + MSI);
iowrite32(result |= (1UL << 16), bptr + PCIE_BASE + MSI);
/* enable AVL_IRQ in MSI Control Register of PCI Endpoint */
result = ioread32(bptr + PCIE_BASE + MSI);
iowrite32(result |= (1UL << 7), bptr + PCIE_BASE + MSI);
mb();
iowrite16(0x7, bptr + TMR_0_CTRL);
ioread32(bptr + PCIE_BASE); /* dummy read */
mb();
}
}
return 0;
}
int pci_rd_open (struct inode *inode, struct file *filp)
{
return 0;
}
int pci_irq_release (struct inode *inode, struct file *filp)
{
unsigned char *bptr = pci_res0->m_addr;
int result;
instance_count--;
/* we have a irq number and the last connected process is to be released*/
if (myirq && instance_count == 0)
{
free_irq(myirq, pci_res0 /* dev_id */);
mb();
/* disable timer irq */
iowrite16(0x0, bptr + TMR_0_CTRL);
mb();
/* disable AVL_IRQ in MSI Control Register of PCI Endpoint */
result = ioread32(bptr + PCIE_BASE + MSI);
iowrite32(result |= (0UL << 7), bptr + PCIE_BASE + MSI);
/* disable MSI in MSI Control Register of PCI Endpoint */
result = ioread32(bptr + PCIE_BASE + MSI);
iowrite32(result |= (0UL << 16), bptr + PCIE_BASE + MSI);
ioread32(bptr + PCIE_BASE); /* dummy read */
mb();
}
return 0;
}
int pci_rd_release (struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t pci_blocking_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int count0;
/* there is no data so we are going to wait. */
/* but only if there is no wakeup call pending */
wait_event_interruptible(event_wq, short_head != short_tail);
/* now we should have at least one event in the buffer */
/* count0 is the number of readable data bytes */
count0 = short_head - short_tail;
if (count0 < 0) /* wrapped */
count0 = short_buffer + PAGE_SIZE - short_tail;
//printk(KERN_ALERT "%s: read count0 = %d\n", name_str, count0);
if (count0 < count) count = count0;
if (copy_to_user(buf, (char *)short_tail, count))
return -EFAULT;
short_incr_bp (&short_tail, count);
return count;
}
ssize_t pci_nonblocking_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int snapl_value;
int snaph_value;
int snap_value;
unsigned char *bptr = pci_res0->m_addr;
/* copy snapshot value from timer */
/* should be atomic */
spin_lock(&snapshot_lock);
/* trigger the latch of the counter value */
iowrite16(0x0, bptr + TMR_0_SNAPL);
rmb(); // has to be executed before reading
snapl_value = ioread16(bptr + TMR_0_SNAPL);rmb();
snaph_value = ioread16(bptr + TMR_0_SNAPH);rmb();
spin_unlock(&snapshot_lock);
snap_value = (int)(snaph_value << 16) | snapl_value;
if (copy_to_user(buf, &snap_value, 4))
return -EFAULT;
return 4;
}
ssize_t pci_skel_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
return 0;
}
int pci_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) {
int retval = 0;
unsigned char *bptr = pci_res0->m_addr;
if(_IOC_TYPE(cmd) != PCI_CHAR_MAGIC) return -ENOTTY;
if(_IOC_NR(cmd) > PCI_CHAR_MAXNR) return -ENOTTY;
switch(cmd) {
/*case SET_PERIOD:
//printk(KERN_ALERT "%s: periodl 0x%x\n", name_str, arg);
should be atomic
spin_lock(&period_lock);
iowrite16(arg, bptr + TMR_0_PERIODL);
wmb();
iowrite16(arg >> 16, bptr + TMR_0_PERIODH);
spin_unlock(&period_lock);
break;
case GET_PERIOD:
spin_lock(&period_lock);
retval = ioread16(bptr + TMR_0_PERIODL);
rmb();
retval = ioread16(bptr + TMR_0_PERIODH) << 16 | retval;
spin_unlock(&period_lock);
printk(KERN_ALERT "%s: period value is 0x%x\n", name_str, retval);
return retval;
break;*/
default:
return -ENOTTY;
}
return retval;
}
unsigned int pci_skel_poll(struct file *filp, poll_table *wait)
{
return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
}
struct file_operations pci_irq_fops = {
.owner = THIS_MODULE,
.read = pci_blocking_read,
.write = pci_skel_write,
.ioctl = pci_ioctl,
.poll = pci_skel_poll,
.open = pci_skel_open,
.release = pci_irq_release,
};
struct file_operations pci_rd_fops = {
.owner = THIS_MODULE,
.read = pci_nonblocking_read,
.poll = pci_skel_poll,
.open = pci_rd_open,
.release = pci_rd_release,
};
static struct pci_device_id ids[] = {
{ PCI_DEVICE(ALTERA_ID, DEVICE_ID), },
{ PCI_DEVICE(0x1002, 0x4750), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ids);
static unsigned char skel_get_revision(struct pci_dev *dev)
{
u8 revision;
pci_read_config_byte(dev, PCI_REVISION_ID, &revision);
return revision;
}
static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
/* Do probing type stuff here.
* Like calling request_region();
* reading BARs
* reading IRQ
* register char dev
*/
int result;
int is_mem;
dev_t dev_irq = MKDEV(major_num, minor_num);
dev_t dev_rd = MKDEV(major_num, minor_num);
if (skel_get_revision(pdev) != 0x01) {
printk(KERN_ALERT "%s: revision ID wrong!\n", name_str);
return -ENODEV;
}
/* enable pcie error reporting */
result = pci_enable_pcie_error_reporting(pdev);
if (result) {
printk(KERN_ALERT "Could not enable pcie error reporting.\n");
}
/* enable message signaled interrupts */
result = pci_enable_msi(pdev);
/* could not use MSI? */
if (result) {
/* resort to legacy interrupts */
printk(KERN_ALERT "Could not enable MSI interrupting, staying with legacy.\n");
/* MSI enabled, remember for cleanup */
} else {
use_msi = TRUE;
printk(KERN_ALERT "Enabled MSI interrupting.\n");
}
pci_res0 = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); /* mem for object */
if (!pci_res0) {
printk(KERN_ALERT "%s: could not alloc mem for pci_res0!\n", name_str);
goto err_pci_res0;
}
/*init of pci_res0 */
pci_res0->bar = 0;
pci_res0->start = pci_resource_start(pdev, 0);
pci_res0->end = pci_resource_end(pdev, 0);
pci_res0->size = pci_res0->end - pci_res0->start + 1;
is_mem = pci_resource_flags(pdev, 0);
is_mem = is_mem & IORESOURCE_MEM;
pci_res0->is_mem = is_mem;
printk(KERN_ALERT "%s: BAR0 0x%lx - 0x%lx\n", name_str, pci_res0->start, pci_res0->end);
if (!request_mem_region(pci_res0->start, pci_res0->size, name_str)) {
printk(KERN_ALERT "%s: request_mem_region failed\n", name_str);
goto err_mem_region;
}
pci_res0->m_addr = ioremap_nocache(pci_res0->start, pci_res0->size);
printk(KERN_ALERT "%s: ioremap to %lx\n", name_str, (unsigned long)pci_res0->m_addr);
/* get irq number from pci */
myirq = pdev->irq;
printk(KERN_ALERT "%s: using IRQ number %d\n", name_str, myirq);
/* alloc DEV_COUNT device number */
result = alloc_chrdev_region (&dev_irq, FIRSTMINOR, DEV_COUNT, name_str);
if(result < 0) {
printk(KERN_ALERT "%s: ERROR unable to get major number\n", name_str);
goto err_alloc_chrdev;
} else {
major_num = MAJOR(dev_irq);
printk(KERN_ALERT "%s: My major nummber is: %d\n", name_str, major_num);
};
// assign dev_rd the next minor number
dev_rd = MKDEV(major_num, MINOR(dev_irq) + 1);
// allocate cdev structures
cdev_irq = cdev_alloc();
cdev_rd = cdev_alloc();
if((cdev_irq == NULL) || (cdev_rd == NULL)){
printk("%s: ERROR allocate cdev structur failure\n", name_str);
goto err_cdev_alloc;
}
cdev_irq->owner = THIS_MODULE;
cdev_irq->ops = &pci_irq_fops;
cdev_rd->owner = THIS_MODULE;
cdev_rd->ops = &pci_rd_fops;
result = cdev_add(cdev_irq, dev_irq, 1);
if(result < 0){
printk("%s: cdev_add dev_irq failed\n", name_str);
goto err_alloc_chrdev;
} else
printk("%s: added cdev_irq\n", name_str);
result = cdev_add(cdev_rd, dev_rd, 1);
if(result < 0){
printk("%s: cdev_add dev_rd failed\\n", name_str);
goto err_cdev_add;
} else
printk("%s: added cdev_rd\n", name_str);
short_buffer = __get_free_pages(GFP_KERNEL,0); //never fails
short_head = short_tail = short_buffer;
return pci_enable_device(pdev);
/* cleaning up */
err_cdev_add:
cdev_del(cdev_irq);
err_cdev_alloc:
unregister_chrdev_region (MKDEV(major_num, minor_num), DEV_COUNT);
err_alloc_chrdev:
iounmap(pci_res0->m_addr);
release_mem_region(pci_res0->start, pci_res0->size);
err_mem_region:
kfree(pci_res0);
err_pci_res0:
return -EIO;
}
static void remove(struct pci_dev *pdev)
{
/* clean up any allocated resources and stuff here.
* like call release_mem_region();
*/
printk(KERN_ALERT "%s: releasing resources\n", name_str);
if (cdev_rd)
cdev_del(cdev_rd);
if (cdev_irq)
cdev_del(cdev_irq);
if (major_num) {
unregister_chrdev_region (MKDEV(major_num, minor_num), DEV_COUNT);
printk(KERN_ALERT "%s: released major number %i\n", name_str, major_num);
}
if (use_msi)
pci_disable_msi(pdev);
iounmap(pci_res0->m_addr);
release_mem_region(pci_res0->start, pci_res0->size);
printk(KERN_ALERT "%s: released io 0x%lx\n", name_str, pci_res0->start);
if (pci_res0 != NULL)
kfree(pci_res0);
}
static int err_handler(struct pci_dev *pdev) {
printk(KERN_ALERT "%s: err handler called!\n", name_str);
return 0;
}
static struct pci_driver pci_driver = {
.name = name_str,
.id_table = ids,
.probe = probe,
.remove = remove,
.err_handler = err_handler,
};
static int __init pci_skel_init(void)
{
return pci_register_driver(&pci_driver);
}
static void __exit pci_skel_exit(void)
{
pci_unregister_driver(&pci_driver);
}
MODULE_LICENSE("GPL");
module_init(pci_skel_init);
module_exit(pci_skel_exit);
#ifndef PCI_CHAR_DRIVER_H_
#define PCI_CHAR_DRIVER_H_
#endif /*PCI_CHAR_DRIVER_H_*/
#include <linux/ioctl.h>
#define PCI_CHAR_MAGIC 'S'
#define SET_PERIOD _IO(PCI_CHAR_MAGIC, 0)
#define GET_PERIOD _IO(PCI_CHAR_MAGIC, 1)
#define PCI_CHAR_MAXNR 3
#define ALTERA_ID 0x1172
#define DEVICE_ID 0x0004
#define FIRSTMINOR 0
#define DEV_COUNT 2
#define ONCHIP_RAM_OFFSET 0x4000
#define SCU_ADDR 0x4030
#define SCU_TIMING 0x4040
#define SCU_WR_DATA 0x4020
#define SCU_CTRL 0x4050
#define SCU_RD_DATA 0x4060
#define SCU_STATUS 0x4070
#define SCU_MASTER 0x1000000
#define SCU_RD 'R'
#define SCU_WR 'W'
#define SCU_TM 'T'
#define PCIE_BASE 0x20000
#define MSI 0x050
#define TMR_BASE 0x24000
#define TMR_DIR (TMR_BASE + 0x8)
#define TMR_EDGE_CAPTURE (TMR_BASE + 0x18)
#define TMR_IRQ_MASK (TMR_BASE + 0x10)
#define TMR_SNAP 0x24020
#define TMR_0_BASE 0x24080
#define TMR_0_CTRL (TMR_0_BASE + 0x8)
#define TMR_0_PERIODL (TMR_0_BASE + 0x10)
#define TMR_0_PERIODH (TMR_0_BASE + 0x18)
#define TMR_0_SNAPL (TMR_0_BASE + 0x20)
#define TMR_0_SNAPH (TMR_0_BASE + 0x28)
#define EVENT_BUFFER_SIZE 100
#define IRQ_RATE 1250000
struct scu_cycle_data {
unsigned int data; /* 16 bit data */
unsigned int addr; /* 20 bit addr */
char type; /* SCU_RD, SCU_WR, SCU_TM */
};
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>
MODULE_INFO(vermagic, VERMAGIC_STRING);
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};
static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";
MODULE_ALIAS("pci:v00001172d00000004sv*sd*bc*sc*i*");
#!/bin/sh
module="pci_char"
device="pci_char"
mode="664"
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.ko $* || exit 1
#remove stale nodes
rm -f /dev/${device}[0-3]
major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
/*
* syscalls.c
* Program to illustrate common system calls. Doesn't actually
* perform any useful function, but will later be expanded into
* a program which does.
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include "pci_char_driver.h"
#define FALSE 0
#define TRUE 1
#define BUFSIZE 1
int main()
{
int fd; /* device file descriptor */
int i = 0, j = 0;
unsigned int wbuf[BUFSIZE]; /* buffer to hold data */
unsigned int rbuf[BUFSIZE];
int status; /* return status of system calls */
char up = TRUE;
struct scu_cycle_data *scu_buf = malloc(sizeof(struct scu_cycle_data));
/* open device */
status = fd = open("/dev/pci", O_RDWR);
if (status == -1) {
perror("error opening /dev/pci");
exit(1);
}
/* reset of the SCU Macro */
status = ioctl(fd, PCI_CHAR_RESET);
if (status == -1) {
perror("error from PCI_CHAR_RESET");
exit(1);
}
scu_buf->addr = 0x00002;
scu_buf->addr <<= 2;
scu_buf->data = 0xAFFE;
scu_buf->type = SCU_WR;
status = write(fd, scu_buf, sizeof(struct scu_cycle_data));
if (status == -1) {
perror("error writing to SCU bus!");
exit(1);
}
//for (j=0; j<1000; j++) {
status = read(fd, scu_buf, sizeof(struct scu_cycle_data));
if (status == -1) {
perror("error reading from SCU bus!");
exit(1);
}
//}
/* close the device */
status = close(fd);
if (status == -1) {
perror("error closing /dev/pci");
exit(1);
}
/* and exit */
return(0);
}
/*
* sleepy.c -- the writers awake the readers
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
* $Id: sleepy.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h> /* current and everything */
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/types.h> /* size_t */
#include <linux/wait.h>
MODULE_LICENSE("GPL");
static int sleepy_major = 0;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag = 0;
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_ALERT "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
printk(KERN_ALERT "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
struct file_operations sleepy_fops = {
.owner = THIS_MODULE,
.read = sleepy_read,
.write = sleepy_write,
};
int sleepy_init(void)
{
int result;
/*
* Register your major, and accept a dynamic number
*/
result = register_chrdev(sleepy_major, "sleepy", &sleepy_fops);
if (result < 0)
return result;
if (sleepy_major == 0)
sleepy_major = result; /* dynamic */
return 0;
}
void sleepy_cleanup(void)
{
unregister_chrdev(sleepy_major, "sleepy");
}
module_init(sleepy_init);
module_exit(sleepy_cleanup);
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>
MODULE_INFO(vermagic, VERMAGIC_STRING);
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};
static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment