]> rtime.felk.cvut.cz Git - mf6xx.git/commitdiff
MF624 UIO driver (krnel part only). Compilable version. Not tested.
authorRostislav Lisovy <lisovy@gmail.com>
Sun, 20 Mar 2011 13:50:07 +0000 (14:50 +0100)
committerRostislav Lisovy <lisovy@gmail.com>
Sun, 20 Mar 2011 13:50:07 +0000 (14:50 +0100)
src/uio/mf614/kernel/Makefile [moved from src/uio/kernel/Makefile with 100% similarity]
src/uio/mf614/kernel/README [moved from src/uio/kernel/README with 100% similarity]
src/uio/mf614/kernel/mf614.c [moved from src/uio/kernel/mf614.c with 100% similarity]
src/uio/mf614/userspace/test_application/Makefile [moved from src/uio/userspace/test_application/Makefile with 100% similarity]
src/uio/mf614/userspace/test_application/main.c [moved from src/uio/userspace/test_application/main.c with 100% similarity]
src/uio/mf624/kernel/Makefile [new file with mode: 0644]
src/uio/mf624/kernel/mf624.c [new file with mode: 0755]

diff --git a/src/uio/mf624/kernel/Makefile b/src/uio/mf624/kernel/Makefile
new file mode 100644 (file)
index 0000000..b9620eb
--- /dev/null
@@ -0,0 +1,17 @@
+MY_KERNEL_VERSION=$(shell uname -r)
+MY_KERNEL_BUILD=/lib/modules/$(MY_KERNEL_VERSION)/build
+
+my_all:
+       make -C $(MY_KERNEL_BUILD) M=`pwd` modules
+
+obj-m := mf624.o
+
+clean:
+       rm *.ko *.o
+
+load:
+       sync
+       rmmod mf624
+       sync
+       insmod ./mf624.ko
+
diff --git a/src/uio/mf624/kernel/mf624.c b/src/uio/mf624/kernel/mf624.c
new file mode 100755 (executable)
index 0000000..a275db5
--- /dev/null
@@ -0,0 +1,217 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HUMUSOFT         0x186c
+#define PCI_DEVICE_ID_MF624            0x0624
+#define PCI_SUBVENDOR_ID_HUMUSOFT      0x186c
+#define PCI_SUBDEVICE_DEVICE           0x0000
+
+#define INTCSR                         0x4C
+#define INTCSR_ADINT_ENABLE            (1 << 0)
+#define INTCSR_CTR4INT_ENABLE          (1 << 3)
+#define INTCSR_PCIINT_ENABLE           (1 << 6)
+#define INTCSR_ADINT_STATUS            (1 << 2)
+#define INTCSR_CTR4INT_STATUS          (1 << 5)
+
+
+typedef enum {ADC, CTR4, ALL} mf624_interrupt_source_t;
+
+void mf624_disable_interrupt(mf624_interrupt_source_t source, struct uio_info *info)
+{
+       u32 *INTCSR_reg = ((u32*) info->mem[0].internal_addr) + INTCSR;
+
+       switch (source) {
+               case ADC:
+                       *INTCSR_reg &= ~(INTCSR_ADINT_ENABLE);
+                       break;
+               case CTR4:
+                       *INTCSR_reg &= ~(INTCSR_CTR4INT_ENABLE);
+                       break;
+               case ALL:
+                       *INTCSR_reg &= ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE);
+                       break;
+               default:
+                       *INTCSR_reg &= ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE);
+                       break;
+       }
+}
+
+void mf624_enable_interrupt(mf624_interrupt_source_t source, struct uio_info *info)
+{
+       u32 *INTCSR_reg = ((u32*) info->mem[0].internal_addr) + INTCSR;
+
+       switch (source) {
+               case ADC:
+                       *INTCSR_reg |= (INTCSR_ADINT_ENABLE);
+                       break;
+               case CTR4:
+                       *INTCSR_reg |= (INTCSR_CTR4INT_ENABLE);
+                       break;
+               case ALL:
+                       *INTCSR_reg |= (INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE);
+                       break;
+               default:
+                       *INTCSR_reg |= (INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE);
+                       break;
+       }
+}
+
+static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
+{
+       u32 *INTCSR_reg = ((u32*) info->mem[0].internal_addr) + INTCSR;
+
+       if ((*INTCSR_reg & INTCSR_ADINT_ENABLE) && (*INTCSR_reg & INTCSR_ADINT_STATUS))
+       {
+               //disable interrupt
+               mf624_disable_interrupt(ADC, info);
+               return IRQ_HANDLED;
+       }
+
+       if ((*INTCSR_reg & INTCSR_CTR4INT_ENABLE) && (*INTCSR_reg & INTCSR_CTR4INT_STATUS))
+       {
+               //disable interrupt
+               mf624_disable_interrupt(CTR4, info);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
+{
+       if (irq_on == 0) { /* Disable interrupts */
+               mf624_disable_interrupt(ALL, info);
+       } 
+       else if (irq_on == 1) {
+               mf624_enable_interrupt(ALL, info);
+       }
+
+       return 0;
+}
+
+static int __devinit mf624_pci_probe(struct pci_dev *dev,
+                                     const struct pci_device_id *id)
+{
+       struct uio_info *info;
+
+       info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       
+       if (pci_enable_device(dev))
+               goto out_free;
+
+       if (pci_request_regions(dev, "mf624"))
+               goto out_disable;
+       
+       info->name = "MF624";
+       info->version = "0.0.1";
+
+
+       info->mem[0].name = "PCI chipset, interrupts, status bits, special functions";
+       info->mem[0].addr = pci_resource_start(dev, 0);
+       if (!info->mem[0].addr)
+               goto out_release;
+       info->mem[0].size = pci_resource_len(dev, 0);
+       info->mem[0].memtype = UIO_MEM_PHYS;
+       info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
+       if (!info->mem[0].internal_addr)
+               goto out_release;
+
+       
+       info->mem[1].name = "ADC, DAC, DIO";
+       info->mem[1].addr = pci_resource_start(dev, 1);
+       if (!info->mem[1].addr)
+               goto out_release;
+       info->mem[1].size = pci_resource_len(dev, 1);
+       info->mem[1].memtype = UIO_MEM_PHYS;
+       info->mem[1].internal_addr = pci_ioremap_bar(dev, 1);
+       if (!info->mem[1].internal_addr)
+               goto out_release;
+
+
+       info->mem[2].name = "Counter/timer chip";
+       info->mem[2].addr = pci_resource_start(dev, 2);
+       if (!info->mem[2].addr)
+               goto out_release;
+       info->mem[2].size = pci_resource_len(dev, 2);
+       info->mem[2].memtype = UIO_MEM_PHYS;
+       info->mem[2].internal_addr = pci_ioremap_bar(dev, 2);
+       if (!info->mem[2].internal_addr)
+               goto out_release;
+
+       
+       info->irq = dev->irq;
+       info->irq_flags = IRQF_SHARED;
+       info->handler = mf624_irq_handler;
+
+       info->irqcontrol = mf624_irqcontrol;
+
+       if(uio_register_device(&dev->dev, info))
+               goto out_release;
+
+       pci_set_drvdata(dev, info);
+
+       return 0;
+
+out_release:
+       pci_release_regions(dev);
+out_disable:
+       pci_disable_device(dev);
+out_free:
+       kfree(info);
+       return -ENODEV;
+}
+
+static void mf624_pci_remove(struct pci_dev *dev)
+{
+       struct uio_info *info = pci_get_drvdata(dev);
+       
+       mf624_disable_interrupt(ALL, info);
+       
+       uio_unregister_device(info);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       
+       kfree(info);
+}
+
+static struct pci_device_id mf624_pci_id[] __devinitdata = {
+       {
+               .vendor = PCI_VENDOR_ID_HUMUSOFT,
+               .device = PCI_DEVICE_ID_MF624,
+               .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
+               .subdevice = PCI_SUBDEVICE_DEVICE,
+       },
+       { 0, }
+};
+
+static struct pci_driver mf624_pci_driver = {
+       .name = "mf624",
+       .id_table = mf624_pci_id,
+       .probe = mf624_pci_probe, 
+       .remove = mf624_pci_remove,
+};
+
+static int __init mf624_init_module(void)
+{
+       return pci_register_driver(&mf624_pci_driver);
+}
+
+static void __exit mf624_exit_module(void)
+{
+       pci_unregister_driver(&mf624_pci_driver);
+}
+
+module_init(mf624_init_module);
+module_exit(mf624_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");