Skip to content
Snippets Groups Projects
Commit 3e3feba1 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra
Browse files

Rewrote driver!

parent 937b2a9c
No related merge requests found
......@@ -18,7 +18,7 @@
KERNELDIR ?= /usr/src/linux-3.2.14 #/common/usr/embedded/kernel/scu/linux-2.6.33.6/
ifneq ($(KERNELRELEASE),)
CFLAGS_pcie_wb.o = -msse2
obj-m := pcie_wb.o
obj-m := pcie_wb.o wishbone.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
......
/*
* 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/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*");
MODULE_ALIAS("pci:v00001002d00004750sv*sd*bc*sc*i*");
#!/bin/sh
module="pcie_wb"
device="pcie_wb"
mode="664"
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
rmmod $module
/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} c $major 0
......@@ -10,138 +10,115 @@
#include <linux/cdev.h>
#include <linux/aer.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <asm/io.h> /*outb iowrite8 */
#include <asm/io.h>
#include <asm/spinlock.h>
#include "pcie_wb.h"
#include "wishbone.h"
#define FALSE 0
#define TRUE 1
static unsigned int debug = 0;
typedef float __m128 __attribute__ ((__vector_size__ (16)));
static int major_num = 0; /* major number for char device */
static int minor_num = 0; /* minor number for char device */
static struct cdev *cdev_char;
struct pci_resource *pci_res0 = NULL; /* ptrs to resource objects */
struct pci_resource *pci_res1 = NULL;
char name_str[] = "pcie_wb";
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)
void wb_cycle(struct wishbone* wb, int on)
{
return (irq_handler_t)IRQ_HANDLED;
}
int char_open (struct inode *inode, struct file *filp)
{
//iowrite16(arg >> 16, bptr + TMR_0_PERIODH);
//wmb();
return 0;
struct pcie_wb_dev* dev;
unsigned char* control;
dev = container_of(wb, struct pcie_wb_dev, wb);
control = dev->pci_res[0].addr;
iowrite32(on?0x80000000UL:0, control + CONTROL_REGISTER_HIGH);
}
int char_release (struct inode *inode, struct file *filp)
void wb_write(struct wishbone* wb, wb_addr_t addr, wb_data_t data)
{
return 0;
struct pcie_wb_dev* dev;
unsigned char* control;
unsigned char* window;
wb_addr_t window_offset;
dev = container_of(wb, struct pcie_wb_dev, wb);
control = dev->pci_res[0].addr;
window = dev->pci_res[1].addr;
window_offset = addr & WINDOW_HIGH;
if (window_offset != dev->window_offset) {
iowrite32(window_offset, control + WINDOW_OFFSET_LOW);
dev->window_offset = window_offset;
}
iowrite32(data, window + (addr & WINDOW_LOW));
}
ssize_t char_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
wb_data_t wb_read(struct wishbone* wb, wb_addr_t addr)
{
unsigned char *bptr = pci_res0->m_addr;
int value = 0x41424344;
/* copy snapshot value from timer */
/* should be atomic */
spin_lock(&snapshot_lock);
struct pcie_wb_dev* dev;
unsigned char* control;
unsigned char* window;
wb_addr_t window_offset;
dev = container_of(wb, struct pcie_wb_dev, wb);
control = dev->pci_res[0].addr;
window = dev->pci_res[1].addr;
window_offset = addr & WINDOW_HIGH;
if (window_offset != dev->window_offset) {
iowrite32(window_offset, control + WINDOW_OFFSET_LOW);
dev->window_offset = window_offset;
}
rmb(); // has to be executed before reading
spin_unlock(&snapshot_lock);
return ioread32(window + (addr & WINDOW_LOW));
}
if (copy_to_user(buf, &value, 4))
return -EFAULT;
static const struct wishbone_operations wb_ops = {
.cycle = wb_cycle,
.write = wb_write,
.read = wb_read,
};
return 4;
#if 0
static irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
return (irq_handler_t)IRQ_HANDLED;
}
#endif
ssize_t char_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
static int setup_bar(struct pci_dev* pdev, struct pcie_wb_resource* res, int bar)
{
unsigned char *bptr = pci_res0->m_addr;
uint32_t value;
__m128 x;
if (copy_from_user(&value, buf, 4))
return -EFAULT;
/*init of pci_res0 */
res->start = pci_resource_start(pdev, bar);
res->end = pci_resource_end(pdev, bar);
res->size = res->end - res->start + 1;
/* copy snapshot value from timer */
/* should be atomic */
spin_lock(&snapshot_lock);
iowrite32(value, bptr + 8);
iowrite32(value, bptr + 12);
iowrite16(value, bptr + 18);
iowrite8(value, bptr + 17);
ioread16(bptr + 16);
// iowrite32(value, bptr + 12);
// iowrite32(value, bptr + 16);
// iowrite16(value, bptr + 18);
// iowrite8(value, bptr + 25);
rmb(); // has to be executed before reading
spin_unlock(&snapshot_lock);
if (debug)
printk(KERN_ALERT PCIE_WB "/BAR%d 0x%lx - 0x%lx\n", bar, res->start, res->end);
return 1;
// is_mem = pci_resource_flags(pdev, 0);
// is_mem = is_mem & IORESOURCE_MEM;
if (!request_mem_region(res->start, res->size, PCIE_WB)) {
printk(KERN_ALERT PCIE_WB "/BAR%d: request_mem_region failed\n", bar);
return -ENOMEM;
}
res->addr = ioremap_nocache(res->start, res->size);
if (debug)
printk(KERN_ALERT PCIE_WB "/BAR%d: ioremap to %lx\n", bar, (unsigned long)res->addr);
return 0;
}
unsigned int char_poll(struct file *filp, poll_table *wait)
static void destroy_bar(struct pcie_wb_resource* res)
{
return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
if (debug)
printk(KERN_ALERT "released io 0x%lx\n", res->start);
iounmap(res->addr);
release_mem_region(res->start, res->size);
}
struct file_operations char_fops = {
.owner = THIS_MODULE,
.read = char_read,
.write = char_write,
.poll = char_poll,
.open = char_open,
.release = char_release,
};
static struct pci_device_id ids[] = {
{ PCI_DEVICE(ALTERA_ID, DEVICE_ID), },
{ PCI_DEVICE(0x1002, 0x4750), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ids);
static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
/* Do probing type stuff here.
......@@ -150,134 +127,82 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
* reading IRQ
* register char dev
*/
dev_t dev_char;
int result;
int is_mem;
u8 revision;
dev_char = MKDEV(major_num, minor_num);
struct pcie_wb_dev *dev;
pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
if (revision != 0x01) {
printk(KERN_ALERT "%s: revision ID wrong!\n", name_str);
return -ENODEV;
printk(KERN_ALERT PCIE_WB ": revision ID wrong!\n");
goto fail_out;
}
/* enable pcie error reporting */
/*
result = pci_enable_pcie_error_reporting(pdev);
if (result) {
printk(KERN_ALERT "Could not enable pcie error reporting.\n");
return -ENODEV;
dev = kmalloc(sizeof(struct pcie_wb_dev), GFP_KERNEL);
if (!dev) {
printk(KERN_ALERT PCIE_WB ": could not allocate memory for pcie_wb_dev structure!\n");
goto fail_out;
}
*/
pci_set_drvdata(pdev, dev);
/* enable message signaled interrupts */
if (pci_enable_msi(pdev) != 0) {
/* resort to legacy interrupts */
printk(KERN_ALERT "Could not enable MSI interrupting, staying with legacy.\n");
return -ENODEV;
}
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;
printk(KERN_ALERT PCIE_WB ": could not enable MSI interrupting\n");
goto fail_free;
}
/*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;
}
if (setup_bar(pdev, &dev->pci_res[0], 0) < 0) goto fail_msi;
if (setup_bar(pdev, &dev->pci_res[1], 1) < 0) goto fail_bar0;
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_char, 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_char);
printk(KERN_ALERT "%s: My major nummber is: %d\n", name_str, major_num);
};
// allocate cdev structures
cdev_char = cdev_alloc();
if(cdev_char == NULL) {
printk("%s: ERROR allocate cdev structur failure\n", name_str);
goto err_cdev_alloc;
dev->wb.wops = &wb_ops;
strcpy(dev->wb.name, PCIE_WB "%d");
dev->wb.parent = &pdev->dev;
if (wishbone_register(&dev->wb) < 0) {
printk(KERN_ALERT PCIE_WB ": could not register wishbone bus\n");
goto fail_bar1;
}
cdev_char->owner = THIS_MODULE;
cdev_char->ops = &char_fops;
result = cdev_add(cdev_char, dev_char, 1);
if(result < 0){
printk("%s: cdev_add dev_char failed\n", name_str);
goto err_alloc_chrdev;
} else
printk("%s: added cdev_irq\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_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;
fail_bar1:
destroy_bar(&dev->pci_res[1]);
fail_bar0:
destroy_bar(&dev->pci_res[0]);
fail_msi:
pci_disable_msi(pdev);
fail_free:
kfree(dev);
fail_out:
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_char)
cdev_del(cdev_char);
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);
}
struct pcie_wb_dev *dev;
dev = pci_get_drvdata(pdev);
wishbone_unregister(&dev->wb);
destroy_bar(&dev->pci_res[1]);
destroy_bar(&dev->pci_res[0]);
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);
kfree(dev);
}
static struct pci_driver pci_driver = {
.name = name_str,
static struct pci_device_id ids[] = {
{ PCI_DEVICE(PCIE_WB_VENDOR_ID, PCIE_WB_DEVICE_ID), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ids);
static struct pci_driver pcie_wb_driver = {
.name = PCIE_WB,
.id_table = ids,
.probe = probe,
.remove = remove,
......@@ -285,15 +210,20 @@ static struct pci_driver pci_driver = {
static int __init pcie_wb_init(void)
{
return pci_register_driver(&pci_driver);
return pci_register_driver(&pcie_wb_driver);
}
static void __exit pcie_wb_exit(void)
{
pci_unregister_driver(&pci_driver);
pci_unregister_driver(&pcie_wb_driver);
}
MODULE_AUTHOR("Stefan Rauch <s.rauch@gsi.de>");
MODULE_DESCRIPTION("GSI Etherbone to Wishbone bridge driver");
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable debugging information");
MODULE_LICENSE("GPL");
MODULE_VERSION(PCIE_WB_VERSION);
module_init(pcie_wb_init);
module_exit(pcie_wb_exit);
#ifndef PCI_CHAR_DRIVER_H_
#define PCI_CHAR_DRIVER_H_
#ifndef PCIE_WB_DRIVER_H
#define PCIE_WB_DRIVER_H
#endif /*PCI_CHAR_DRIVER_H_*/
#include "wishbone.h"
#include <linux/ioctl.h>
#define PCIE_WB "pcie_wb"
#define PCIE_WB_VERSION "0.1"
#define PCI_CHAR_MAGIC 'S'
#define PCIE_WB_VENDOR_ID 0x1172
#define PCIE_WB_DEVICE_ID 0x0004
#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
#define CONTROL_REGISTER_HIGH 0
#define CONTROL_REGISTER_LOW 4
#define ERROR_FLAG_HIGH 8
#define ERROR_FLAG_LOW 12
#define WINDOW_OFFSET_HIGH 16
#define WINDOW_OFFSET_LOW 20
#define WINDOW_HIGH 0xFFFF0000UL
#define WINDOW_LOW 0x0000FFFFUL
/* One per BAR */
struct pcie_wb_resource {
unsigned long start; /* start addr of BAR */
unsigned long end; /* end addr of BAR */
unsigned long size; /* size of BAR */
void *addr; /* remapped addr */
};
struct scu_cycle_data {
unsigned int data; /* 16 bit data */
unsigned int addr; /* 20 bit addr */
char type; /* SCU_RD, SCU_WR, SCU_TM */
/* One per physical card */
struct pcie_wb_dev {
struct pci_dev* pci_dev;
struct pcie_wb_resource pci_res[2];
struct wishbone wb;
int pci_irq[4]; /* IRQ from PCI config reg */
unsigned int window_offset;
};
#endif
/*
* 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=";
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/device.h>
#include "wishbone.h"
/* Module parameters */
static unsigned int max_devices = WISHONE_MAX_DEVICES;
/* Module globals */
static LIST_HEAD(wishbone_list); /* Sorted by ascending minor number */
static DEFINE_MUTEX(wishbone_mutex);
static struct class *wishbone_class;
static dev_t wishbone_dev_first;
static int char_open(struct inode *inode, struct file *filep)
{
struct etherbone_context* context;
context = kzalloc(sizeof(struct etherbone_context), GFP_KERNEL);
if (!context) return -ENOMEM;
context->wishbone = container_of(inode->i_cdev, struct wishbone, cdev);
filep->private_data = context;
return 0;
}
static int char_release(struct inode *inode, struct file *filep)
{
kfree(filep->private_data);
return 0;
}
static ssize_t char_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
{
return 0;
}
static ssize_t char_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
{
return 0;
}
static unsigned int char_poll(struct file *filp, poll_table *wait)
{
return 0;
}
static int char_fasync(int fd, struct file *file, int on)
{
struct etherbone_context* context;
context = file->private_data;
/* No locking - fasync_helper does its own locking */
return fasync_helper(fd, file, on, &context->fasync);
}
static const struct file_operations etherbone_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = char_aio_read,
.write = do_sync_write,
.aio_write = char_aio_write,
.open = char_open,
.poll = char_poll,
.release = char_release,
.fasync = char_fasync,
};
int wishbone_register(struct wishbone* wb)
{
struct list_head *list_pos;
struct device *device;
dev_t dev;
INIT_LIST_HEAD(&wb->list);
mutex_lock(&wishbone_mutex);
/* Search the list for gaps, stopping past the gap.
* If we overflow the list (ie: not gaps), minor already points past end.
*/
dev = wishbone_dev_first;
list_for_each(list_pos, &wishbone_list) {
struct wishbone *entry =
container_of(list_pos, struct wishbone, list);
if (entry->dev != dev) {
/* We found a gap! */
break;
} else {
/* Run out of minors? */
if (MINOR(dev) == max_devices) goto fail_out;
/* Try the next minor */
dev = MKDEV(MAJOR(dev), MINOR(dev) + 1);
}
}
/* Connect the file operations with the cdev */
cdev_init(&wb->cdev, &etherbone_fops);
wb->cdev.owner = THIS_MODULE;
/* Connect the major/minor number to the cdev */
if (cdev_add(&wb->cdev, dev, 1)) goto fail_out;
/* Create the sysfs entry */
device = device_create(wishbone_class, wb->parent, dev, NULL, wb->name, MINOR(dev));
if (IS_ERR(device)) goto fail_del;
/* Insert the device into the gap */
wb->dev = dev;
wb->device = device;
list_add_tail(&wb->list, list_pos);
mutex_unlock(&wishbone_mutex);
return 0;
fail_del:
cdev_del(&wb->cdev);
fail_out:
mutex_unlock(&wishbone_mutex);
return -ENOMEM;
}
int wishbone_unregister(struct wishbone* wb)
{
if (WARN_ON(list_empty(&wb->list)))
return -EINVAL;
mutex_lock(&wishbone_mutex);
list_del(&wb->list);
device_destroy(wishbone_class, wb->dev);
cdev_del(&wb->cdev);
mutex_unlock(&wishbone_mutex);
return 0;
}
static int __init wishbone_init(void)
{
int err;
dev_t overflow;
overflow = MKDEV(0, max_devices-1);
if (MINOR(overflow) != max_devices-1) {
err = -ENOMEM;
goto fail_last;
}
wishbone_class = class_create(THIS_MODULE, "wb");
if (IS_ERR(wishbone_class)) {
err = PTR_ERR(wishbone_class);
goto fail_last;
}
if (alloc_chrdev_region(&wishbone_dev_first, 0, max_devices, "wb") < 0) {
err = -EIO;
goto fail_class;
}
fail_class:
class_destroy(wishbone_class);
fail_last:
return err;
}
static void __exit wishbone_exit(void)
{
unregister_chrdev_region(wishbone_dev_first, max_devices);
class_destroy(wishbone_class);
}
MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>");
MODULE_DESCRIPTION("Wishbone character device class");
module_param(max_devices, int, 0644);
MODULE_PARM_DESC(max_devices, "Maximum number of attached wishbone devices");
MODULE_LICENSE("GPL");
MODULE_VERSION(WISHBONE_VERSION);
EXPORT_SYMBOL(wishbone_register);
EXPORT_SYMBOL(wishbone_unregister);
module_init(wishbone_init);
module_exit(wishbone_exit);
#ifndef WISHBONE_H
#define WISHBONE_H
#include <linux/types.h>
#include <linux/list.h>
#include <linux/cdev.h>
#define WISHBONE_VERSION "0.1"
#define WISHONE_MAX_DEVICES 32 /* default only */
typedef unsigned int wb_addr_t;
typedef unsigned int wb_data_t;
struct wishbone;
struct wishbone_operations
{
void (*cycle)(struct wishbone* wb, int on);
void (*write)(struct wishbone* wb, wb_addr_t addr, wb_data_t);
wb_data_t (*read)(struct wishbone* wb, wb_addr_t addr);
};
/* One per wishbone backend hardware */
struct wishbone
{
char name[32];
const struct wishbone_operations* wops;
struct device *parent;
/* internal: */
dev_t dev;
struct cdev cdev;
struct list_head list;
struct device *device;
};
/* One per open of character device */
struct etherbone_context
{
struct wishbone* wishbone;
struct fasync_struct *fasync;
char buf[1024];
};
int wishbone_register(struct wishbone* wb);
int wishbone_unregister(struct wishbone* wb);
#endif
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