Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * UIO Hilscher CIF card driver
  3  *
  4  * (C) 2007 Hans J. Koch <hjk@linutronix.de>
  5  * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
  6  *
  7  * Licensed under GPL version 2 only.
  8  *
  9  */
 10 
 11 #include <linux/device.h>
 12 #include <linux/module.h>
 13 #include <linux/pci.h>
 14 #include <linux/uio_driver.h>
 15 
 16 #include <asm/io.h>
 17 
 18 #define PLX9030_INTCSR          0x4C
 19 #define INTSCR_INT1_ENABLE      0x01
 20 #define INTSCR_INT1_STATUS      0x04
 21 #define INT1_ENABLED_AND_ACTIVE (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
 22 
 23 #define PCI_SUBVENDOR_ID_PEP    0x1518
 24 #define CIF_SUBDEVICE_PROFIBUS  0x430
 25 #define CIF_SUBDEVICE_DEVICENET 0x432
 26 
 27 
 28 static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
 29 {
 30         void __iomem *plx_intscr = dev_info->mem[0].internal_addr
 31                                         + PLX9030_INTCSR;
 32 
 33         if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
 34             != INT1_ENABLED_AND_ACTIVE)
 35                 return IRQ_NONE;
 36 
 37         /* Disable interrupt */
 38         iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
 39         return IRQ_HANDLED;
 40 }
 41 
 42 static int __devinit hilscher_pci_probe(struct pci_dev *dev,
 43                                         const struct pci_device_id *id)
 44 {
 45         struct uio_info *info;
 46 
 47         info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
 48         if (!info)
 49                 return -ENOMEM;
 50 
 51         if (pci_enable_device(dev))
 52                 goto out_free;
 53 
 54         if (pci_request_regions(dev, "hilscher"))
 55                 goto out_disable;
 56 
 57         info->mem[0].addr = pci_resource_start(dev, 0);
 58         if (!info->mem[0].addr)
 59                 goto out_release;
 60         info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
 61         if (!info->mem[0].internal_addr)
 62                 goto out_release;
 63 
 64         info->mem[0].size = pci_resource_len(dev, 0);
 65         info->mem[0].memtype = UIO_MEM_PHYS;
 66         info->mem[1].addr = pci_resource_start(dev, 2);
 67         info->mem[1].size = pci_resource_len(dev, 2);
 68         info->mem[1].memtype = UIO_MEM_PHYS;
 69         switch (id->subdevice) {
 70                 case CIF_SUBDEVICE_PROFIBUS:
 71                         info->name = "CIF_Profibus";
 72                         break;
 73                 case CIF_SUBDEVICE_DEVICENET:
 74                         info->name = "CIF_Devicenet";
 75                         break;
 76                 default:
 77                         info->name = "CIF_???";
 78         }
 79         info->version = "0.0.1";
 80         info->irq = dev->irq;
 81         info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
 82         info->handler = hilscher_handler;
 83 
 84         if (uio_register_device(&dev->dev, info))
 85                 goto out_unmap;
 86 
 87         pci_set_drvdata(dev, info);
 88 
 89         return 0;
 90 out_unmap:
 91         iounmap(info->mem[0].internal_addr);
 92 out_release:
 93         pci_release_regions(dev);
 94 out_disable:
 95         pci_disable_device(dev);
 96 out_free:
 97         kfree (info);
 98         return -ENODEV;
 99 }
100 
101 static void hilscher_pci_remove(struct pci_dev *dev)
102 {
103         struct uio_info *info = pci_get_drvdata(dev);
104 
105         uio_unregister_device(info);
106         pci_release_regions(dev);
107         pci_disable_device(dev);
108         pci_set_drvdata(dev, NULL);
109         iounmap(info->mem[0].internal_addr);
110 
111         kfree (info);
112 }
113 
114 static struct pci_device_id hilscher_pci_ids[] __devinitdata = {
115         {
116                 .vendor =       PCI_VENDOR_ID_PLX,
117                 .device =       PCI_DEVICE_ID_PLX_9030,
118                 .subvendor =    PCI_SUBVENDOR_ID_PEP,
119                 .subdevice =    CIF_SUBDEVICE_PROFIBUS,
120         },
121         {
122                 .vendor =       PCI_VENDOR_ID_PLX,
123                 .device =       PCI_DEVICE_ID_PLX_9030,
124                 .subvendor =    PCI_SUBVENDOR_ID_PEP,
125                 .subdevice =    CIF_SUBDEVICE_DEVICENET,
126         },
127         { 0, }
128 };
129 
130 static struct pci_driver hilscher_pci_driver = {
131         .name = "hilscher",
132         .id_table = hilscher_pci_ids,
133         .probe = hilscher_pci_probe,
134         .remove = hilscher_pci_remove,
135 };
136 
137 static int __init hilscher_init_module(void)
138 {
139         return pci_register_driver(&hilscher_pci_driver);
140 }
141 
142 static void __exit hilscher_exit_module(void)
143 {
144         pci_unregister_driver(&hilscher_pci_driver);
145 }
146 
147 module_init(hilscher_init_module);
148 module_exit(hilscher_exit_module);
149 
150 MODULE_DEVICE_TABLE(pci, hilscher_pci_ids);
151 MODULE_LICENSE("GPL v2");
152 MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
153 
  This page was automatically generated by the LXR engine.