]> rtime.felk.cvut.cz Git - mf6xx.git/blob - src/uio/mf614/kernel/mf614.c
Correct UIO kernel module PCI table specification.
[mf6xx.git] / src / uio / mf614 / kernel / mf614.c
1 /*
2  * UIO driver fo Humusoft MF614 DAQ card.
3  * Copyright (C) 2010--2011 Rostislav Lisovy <lisovy@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/device.h>
23 #include <linux/pci.h>
24 #include <linux/slab.h>
25 #include <linux/io.h>
26 #include <linux/kernel.h>
27 #include <linux/uio_driver.h>
28
29 #define PCI_VENDOR_ID_HUMUSOFT          0x186c
30 #define PCI_DEVICE_ID_MF614             0x0614
31 #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
32 #define PCI_SUBDEVICE_DEVICE            0x0000
33
34 #define STATUS_REG                      0x10
35 #define STATUS_T5INTE                   (u32) (1 << 19)
36 #define STATUS_T5                       (u32) (1 << 3)
37 #define STATUS_CCINTE                   (u32) (1 << 18)
38 #define STATUS_CC                       (u32) (1 << 2)
39
40
41 static irqreturn_t mf614_irq_handler(int irq, struct uio_info *info)
42 {
43         void __iomem *status_reg = info->priv;
44         status_reg = (u8 *)status_reg + STATUS_REG;
45
46
47         if ((ioread32(status_reg) & STATUS_T5INTE)
48         && (ioread32(status_reg) & STATUS_T5)) {
49                 /* disable interrupt */
50                 iowrite32(ioread32(status_reg) & ~STATUS_T5INTE, status_reg);
51                 return IRQ_HANDLED;
52         }
53
54         if ((ioread32(status_reg) & STATUS_CCINTE)
55         && (ioread32(status_reg) & STATUS_CC)) {
56                 /* disable interrupt */
57                 iowrite32(ioread32(status_reg) & ~STATUS_CCINTE, status_reg);
58                 return IRQ_HANDLED;
59         }
60
61         return IRQ_NONE;
62 }
63
64 static int mf614_irqcontrol(struct uio_info *info, s32 irq_on)
65 {
66         void __iomem *status_reg = info->priv;
67         status_reg = (u8 *)status_reg + STATUS_REG;
68
69
70         if (irq_on == 0) { /* Disable interrupts */
71                 iowrite32(ioread32(status_reg) & ~STATUS_T5INTE, status_reg);
72                 iowrite32(ioread32(status_reg) & ~STATUS_CCINTE, status_reg);
73         } else if (irq_on == 1) {
74                 iowrite32(ioread32(status_reg) | STATUS_T5INTE, status_reg);
75                 iowrite32(ioread32(status_reg) | STATUS_CCINTE, status_reg);
76         }
77
78         return 0;
79 }
80
81 static int __devinit mf614_pci_probe(struct pci_dev *dev,
82                                 const struct pci_device_id *id)
83 {
84         struct uio_info *info;
85
86         info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
87         if (!info)
88                 return -ENOMEM;
89
90         if (pci_enable_device(dev))
91                 goto out_free;
92
93         if (pci_request_regions(dev, "mf614"))
94                 goto out_disable;
95
96         info->name = "MF614";
97         info->version = "0.0.1";
98
99         info->port[0].name = "Board programming registers";
100         info->port[0].porttype = UIO_PORT_X86;
101         info->port[0].start = pci_resource_start(dev, 0);
102         if (!info->port[0].start)
103                 goto out_release;
104         info->port[0].size = pci_resource_len(dev, 0);
105
106
107         info->port[1].name = "OX9162 local configuration registers";
108         info->port[1].porttype = UIO_PORT_X86;
109         info->port[1].start = pci_resource_start(dev, 2);
110         if (!info->port[1].start)
111                 goto out_release;
112         info->port[1].size = pci_resource_len(dev, 2);
113
114         info->priv = pci_iomap(dev, 2, 0);
115         if (!info->priv)
116                 goto out_release;
117
118
119         info->mem[0].name = "Board programming registers";
120         info->mem[0].addr = pci_resource_start(dev, 4);
121         if (!info->mem[0].addr)
122                 goto out_release;
123         info->mem[0].size = pci_resource_len(dev, 4);
124         info->mem[0].memtype = UIO_MEM_PHYS;
125         info->mem[0].internal_addr = pci_ioremap_bar(dev, 4);
126         if (!info->mem[0].internal_addr)
127                 goto out_release;
128
129
130         info->mem[1].name = "OX9162 local configuration registers";
131         info->mem[1].addr = pci_resource_start(dev, 3);
132         if (!info->mem[1].addr)
133                 goto out_release;
134         info->mem[1].size = pci_resource_len(dev, 3);
135         info->mem[1].memtype = UIO_MEM_PHYS;
136         info->mem[1].internal_addr = pci_ioremap_bar(dev, 3);
137         if (!info->mem[1].internal_addr)
138                 goto out_release;
139
140
141         info->irq = dev->irq;
142         info->irq_flags = IRQF_SHARED;
143         info->handler = mf614_irq_handler;
144
145         info->irqcontrol = mf614_irqcontrol;
146
147         if (uio_register_device(&dev->dev, info))
148                 goto out_unmap;
149
150         pci_set_drvdata(dev, info);
151
152         return 0;
153
154 out_unmap:
155         iounmap(info->mem[0].internal_addr);
156         iounmap(info->mem[1].internal_addr);
157         pci_iounmap(dev, info->priv);
158 out_release:
159         pci_release_regions(dev);
160 out_disable:
161         pci_disable_device(dev);
162 out_free:
163         kfree(info);
164         return -ENODEV;
165 }
166
167 static void mf614_pci_remove(struct pci_dev *dev)
168 {
169         struct uio_info *info = pci_get_drvdata(dev);
170         void __iomem *status_reg = info->priv;
171         status_reg = (u8 *)status_reg + STATUS_REG;
172
173         /* Disable interrupts */
174         iowrite32(ioread32(status_reg) & ~STATUS_T5INTE, status_reg);
175         iowrite32(ioread32(status_reg) & ~STATUS_CCINTE, status_reg);
176
177         uio_unregister_device(info);
178         pci_release_regions(dev);
179         pci_disable_device(dev);
180         pci_set_drvdata(dev, NULL);
181         pci_iounmap(dev, info->priv);
182         iounmap(info->mem[0].internal_addr);
183         iounmap(info->mem[1].internal_addr);
184
185         kfree(info);
186 }
187
188 static struct pci_device_id mf614_pci_id[] __devinitdata = {
189         {
190                 .vendor = PCI_VENDOR_ID_HUMUSOFT,
191                 .device = PCI_DEVICE_ID_MF614,
192                 .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
193                 .subdevice = PCI_SUBDEVICE_DEVICE,
194         },
195         { 0, }
196 };
197 MODULE_DEVICE_TABLE(pci, mf614_pci_id);
198
199 static struct pci_driver mf614_pci_driver = {
200         .name = "mf614",
201         .id_table = mf614_pci_id,
202         .probe = mf614_pci_probe,
203         .remove = mf614_pci_remove,
204 };
205
206 static int __init mf614_init_module(void)
207 {
208         return pci_register_driver(&mf614_pci_driver);
209 }
210
211 static void __exit mf614_exit_module(void)
212 {
213         pci_unregister_driver(&mf614_pci_driver);
214 }
215
216 module_init(mf614_init_module);
217 module_exit(mf614_exit_module);
218
219 MODULE_LICENSE("GPL v2");
220 MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");