#include <linux/module.h> #include <linux/version.h> #include <linux/pci.h> #include <asm/uaccess.h> #include "cc.h" struct cc_device { char *io_base; char *mem_base; unsigned int irq; char *name; wait_queue_head_t waitq; struct camac camac; int status; int crate; }; static struct cc_device ccdev;CAMAC関連のインクルードファイルはcc.hで下記のように 定義されます。
cc.h: #define PCI_VENDOR_ID_CC77 1 #define PCI_DEVICE_ID_CC77 0xcc77 #define CC7X00_MAJOR 36 #define CARD_NAME "cc" #define CC_CRATE_NO 1 #define CC_TIMEOUT 500 #define CCIOC_RESET _IO('ps', 1) #define CCIOC_CAMAC _IOWR('ps', 2, 8) #define CCIOC_WAIT_LAM _IO('cc', 3) struct camac { int csr; /* Control/Status Register */ int cnafr; /* Crate address and NAF Register */ int datar; /* Data Register */ int exer; /* EXEcute Register */ }; /* NAF code generation */ #define NAFGEN(n,a,f) ((((n<<4) + a) << 5) + f) #define CC_ADDR 0x310 /* Base Address of PCI/CC-7700 */ #define CC_SIZE 0x10 /* Size of the registers */ #define CC_IRQ 0x9 /* IRQ of PCI/CC-7700 */ #define CSR 0 /* Control/Status Register */ #define CCR 4 /* Crate address & CAMAC Command Registers */ #define LAMR 4 /* LAM Register */ #define DATR 8 /* Data Low Register */ #define EXER 12 /* EXEcute Register */ /* CSR field */ #define CC_CSRM_NOQ 1 /* NO Q */ #define CC_CSRM_NOX 2 /* NO X */ #define CC_CSRM_NOQX 0XFFFC /* NO Q and X */ #define CC_CSRM_CLEAR 1 /* CAMAC Clear */ #define CC_CSRM_INIT 2 /* CAMAC Initialize */ #define CC_CSRM_INHBIT 4 /* CAMAC Inhibit */ #define CC_CSRM_EN 8 /* Enable Interrupt */ #define CC_CSRM_DONE 0X10 /* Completion Status */ #define CC_CSRM_ONLINE 0X20 /* Data Ready */ #define CC_CSRM_LAM 0X40 /* LAM is present. */ #define CC_CSRM_RST 0X40 /* Reset the controller */ #define CC_CSRM_LAMI 0X80 /* LAM internal */ /* CAMAC Command field */ #define CC_NAFRM_F 0 /* Functioin */ #define CC_NAFRK_F8 8 /* F = 8 */ #define CC_NAFRK_F16 0x10 /* F = 16 */ #define CC_NAFRK_F24 0x18 /* F = 24 */ #define CC_NAFRM_A 0x20 /* Subaddress */ #define CC_NAFRM_N 0X200 /* Station number */ /* EXE field */ #define CC_EXERM_GO 1 /* Go CAMAC Cycle */
void CAMAC(int naf, int *data, int *qx) { int status; if( CC_NAFRK_F16 & naf ) { if( CC_NAFRK_F8 & naf ) { outl( naf, ccdev.camac.cnafr ); outl( CC_EXERM_GO, ccdev.camac.exer); while(!(( *qx = inl(ccdev.camac.csr)) & CC_CSRM_DONE )); } else { outl(naf,ccdev.camac.cnafr); outl(*data, ccdev.camac.datar); outl(CC_EXERM_GO, ccdev.camac.exer); while(!(( *qx = inl(ccdev.camac.csr)) & CC_CSRM_DONE )); } } else { if( CC_NAFRK_F8 & naf ) { outl(naf, ccdev.camac.cnafr); outl(CC_EXERM_GO,ccdev.camac.exer); while(!(( *qx = inl(ccdev.camac.csr)) & CC_CSRM_DONE )); } else { outl(naf, ccdev.camac.cnafr); outl(CC_EXERM_GO, ccdev.camac.exer); while(!(( *qx = inl(ccdev.camac.csr)) & CC_CSRM_DONE )); *data = inl(ccdev.camac.datar); } } status = ~status; *qx = status & (CC_CSRM_NOQ| CC_CSRM_NOX); } void dump_reg() { printk("CSR = %x\n", inl(ccdev.camac.csr)); printk("LAMR = %x\n", inl(ccdev.camac.cnafr)); printk("DATAR = %x\n", inl(ccdev.camac.datar)); } void ccreset(){ outl( CC_CSRM_RST, ccdev.camac.csr); outl( CC_CSRM_CLEAR, ccdev.camac.csr); }
static int cc_open(struct inode *inode, struct file * file) { MOD_INC_USE_COUNT; return 0; } static void cc_release(struct inode * inode, struct file * file) { MOD_DEC_USE_COUNT; }
static int cc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int retval = 0; int cnaf, data, qx; int cmddata[3]; switch ( cmd ) { case CCIOC_RESET : ccreset(); dump_reg(); break; case CCIOC_CAMAC: if (copy_from_user(cmddata, (int *)arg, sizeof(int)*2)) return -EFAULT; cnaf = cmddata[0]; data = cmddata[1]; CAMAC(cnaf, &data, &qx ); cmddata[1] = data; cmddata[2] = qx; if (copy_to_user((int *)arg, cmddata, sizeof(int)*3)) return -EFAULT; break; case CCIOC_WAIT_LAM : data = inl(ccdev.camac.csr); data |= CC_CSRM_EN; cli(); outl( data, ccdev.camac.csr ); // Enable Interrupt of CC7700 interruptible_sleep_on_timeout(&ccdev.waitq, CC_TIMEOUT); outl( 0, ccdev.camac.csr ); // Disable Interrupt of CC7700 data = inl(ccdev.camac.cnafr); if (copy_to_user((int *)arg, &data, sizeof(int))) return -EFAULT; break; default: retval = -EINVAL; }; return 0; }
static void cc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { outl( 0, ccdev.camac.csr ); // Disable Interrupt of CC7700 while (irq != ccdev.irq) { printk("unexpected interrupt...\n"); return; } wake_up_interruptible(&ccdev.waitq); }
static struct file_operations cc_fops = { ioctl: cc_ioctl, open: cc_open, release: cc_release, };
int init_module(void) { struct pci_dev *pcidev=NULL; int retval; if(!pci_present()) return -ENODEV; pcidev = pci_find_device(PCI_VENDOR_ID_CC77, PCI_DEVICE_ID_CC77, pcidev); if (pcidev == NULL) { return -ENODEV; } ccdev.irq = 9; pcidev->irq = ccdev.irq; pci_write_config_byte(pcidev, PCI_INTERRUPT_LINE, ccdev.irq); retval = pci_enable_device(pcidev); if(retval) return retval; ccdev.io_base = (char *)pci_resource_start(pcidev, 0); printk("CC7x00:IO_BASE = %x\n", ccdev.io_base); ccdev.camac.csr = ccdev.io_base + CSR; ccdev.camac.cnafr = ccdev.io_base + CCR; ccdev.camac.datar = ccdev.io_base + DATR; ccdev.camac.exer = ccdev.io_base + EXER; printk("irq number of CC = %x\n", ccdev.irq); retval = register_chrdev(CC7X00_MAJOR,CARD_NAME,&cc_fops); if (retval) { printk("unable to get major %d for CAMAC\n", CC7X00_MAJOR); return retval; } retval = request_irq(ccdev.irq, cc_interrupt, SA_INTERRUPT, CARD_NAME, &ccdev. irq); if (retval){ printk("pci_cc77: interrupt registration fault on level %d\n", ccdev.irq); return retval; } init_waitqueue_head(&ccdev.waitq); printk("CAMAC(CC7X00) has been installed.\n"); return 0; }
void cleanup_module(void) { free_irq(ccdev.irq, &ccdev.irq); unregister_chrdev(CC7X00_MAJOR,CARD_NAME); printk("CAMAC(CC7X00) has been removed.\n"); }
INCDIR = -I/usr/src/linux/include VERSIONINC = -include /usr/src/linux/include/linux/modversions.h CFLAGS = -O2 -Wall -c -D__KERNEL__ -DMODULE -Wall $(INCDIR) $(VERSIONINC) DRIVER = cc TEST = test_cc all: $(DRIVER).o $(TEST) $(TEST)_int $(DRIVER).o: $(DRIVER).c $(DRIVER).h gcc $(CFLAGS) $(DRIVER).c device: mknod -m 666 /dev/$(DRIVER) c 36 0 $(TEST): $(TEST).c $(DRIVER).h gcc -o $(TEST) $(TEST).c $(TEST)_int: $(TEST)_int.c $(DRIVER).h gcc -o $(TEST)_int $(TEST)_int.c clean: rm -f *.o *~ core $(TEST) $(TEST)_int
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include <stdio.h> #include <linux/wait.h> #include "cc.h" #define MEM 3-1 main() { int fd; int cmddata[3]; int crate = 0; unsigned int i = 0; int ccwrite, ccread, ccclear; fd = open("/dev/cc", O_RDWR); if( fd == -1) { printf("open error...\n"); exit(0); } ioctl(fd, CCIOC_RESET); ccclear = NAFGEN(MEM, 0, 9); ccwrite = NAFGEN(MEM, 0, 16); ccread = NAFGEN(MEM, 0, 0 ); cmddata[0] = ccclear + crate; ioctl(fd, CCIOC_CAMAC, cmddata); while(1) { cmddata[0] = ccclear + crate; ioctl(fd, CCIOC_CAMAC, cmddata); cmddata[0] = ccwrite + crate; cmddata[1] = i; ioctl(fd, CCIOC_CAMAC, cmddata); cmddata[0] = ccclear + crate; ioctl(fd, CCIOC_CAMAC, cmddata); cmddata[0] = ccread + crate; ioctl(fd, CCIOC_CAMAC, cmddata); //printf("MEM : read data = %x qx = %x\n", cmddata[1], cmddata[2]); i++; } close(fd); }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include <stdio.h> #include <linux/wait.h> #include "cc.h" #define INT 5-1 main() { int fd; int cmddata[3]; int crate = 0; unsigned int i = 0; int ccreadclear, ccenable, ccclear; int lam = 0; fd = open("/dev/cc", O_RDWR); if( fd == -1) { printf("open error...\n"); exit(0); } ioctl(fd, CCIOC_RESET); ccclear = NAFGEN(INT, 0, 9); cmddata[0] = ccclear + crate; ioctl(fd, CCIOC_CAMAC, cmddata); ccenable = NAFGEN(INT, 0, 26); ccreadclear = NAFGEN(INT, 0, 2 ); while(1) { cmddata[0] = ccenable + crate; ioctl(fd, CCIOC_CAMAC, cmddata); ioctl(fd, CCIOC_WAIT_LAM, &lam); i++; printf("Read LAM : %x, total interrupt counter = %d\n", lam, i); cmddata[0] = ccreadclear + crate; ioctl(fd, CCIOC_CAMAC, cmddata); } close(fd); }