]> rtime.felk.cvut.cz Git - mf6xx.git/blob - src/comedi/mf614_simple_driver/kernel/mf614.c
Fixed all errors. Tested. Works. DIN + DOUT only.
[mf6xx.git] / src / comedi / mf614_simple_driver / kernel / mf614.c
1 #include "../comedidev.h"
2 #include <linux/pci.h>
3
4 #define PCI_VENDOR_ID_MF614 0x186c
5 #define PCI_DEVICE_ID_MF614 0x0614
6
7 #define DIN_reg         0x6
8 #define DOUT_reg        0x6
9
10
11 static struct pci_device_id mf614_pci_table[] __devinitdata = {
12         { PCI_VENDOR_ID_MF614, PCI_DEVICE_ID_MF614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
13         { 0 }
14 };
15 MODULE_DEVICE_TABLE(pci, mf614_pci_table);
16
17
18 typedef struct mf614_board_struct {
19         char *name;
20         unsigned short device_id;
21         unsigned int ai_chans;
22         unsigned int ai_bits;
23         unsigned int ao_chans;
24         unsigned int ao_bits;
25         unsigned int di_chans;
26         unsigned int do_chans;
27 } mf614_board;
28
29 static const mf614_board mf614_boards[] = {
30         {
31                 name:           "mf614",        /* device name          */
32                 device_id:      PCI_DEVICE_ID_MF614,    /* PCI dev ID   */
33                 ai_chans:       8,              /* Num of ADC channels  */
34                 ai_bits:        14,             /* Num of ADC bits      */
35                 ao_chans:       8,              /* Num of DAC channels  */
36                 ao_bits:        14,             /* Num of DAC bits      */
37                 di_chans:       8,              /* Num of digital in    */
38                 do_chans:       8,              /* Num of digital out   */
39         }
40 };
41
42 static int mf614_attach(struct comedi_device *dev, struct comedi_devconfig *it);
43 static int mf614_detach(struct comedi_device *dev);
44 static struct comedi_driver driver_mf614 = {
45         driver_name:    "mf614",
46         module:         THIS_MODULE,
47         attach:         mf614_attach,
48         detach:         mf614_detach,
49 };
50
51 /* Private data structure */
52 typedef struct {
53         struct pci_dev *pci_dev;
54
55         void __iomem *BAR0_io;
56         void __iomem *BAR2_io;
57
58         u8 in_use;
59         /* Used for AO readback */
60         //lsampl_t ao_readback[8];
61 } mf614_private;
62
63
64 /*
65 ==============================================================================
66 */
67
68
69 static int mf614_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 
70                               struct comedi_insn *insn, unsigned int *data);
71 static int mf614_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 
72                               struct comedi_insn *insn, unsigned int *data);
73
74 #define devpriv                 ((mf614_private *) dev->private)
75 #define thisboard               ((mf614_board *) dev->board_ptr)
76 static int mf614_attach(struct comedi_device *dev, struct comedi_devconfig *it)
77 {
78         struct comedi_subdevice *s;
79         struct pci_dev* pcidev;
80         //unsigned int channel; 
81         //unsigned int status;
82
83         printk("comedi%d: mf614: ", dev->minor);
84
85         if(alloc_private(dev, sizeof(mf614_private)) < 0) { // No need to free() later
86                 return -ENOMEM;
87         }
88         
89         devpriv->in_use = -1;
90
91         /* Probe the device to determine what device in the series it is */
92         for(pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 
93                 pcidev != NULL; 
94                 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))
95                 {
96
97                 if(pcidev->vendor != PCI_VENDOR_ID_MF614) {
98                         continue;
99                 }
100
101                 if(mf614_boards[0].device_id != pcidev->device) {
102                         continue;
103                 }
104
105                 /* was a particular bus/slot requested ? */
106                 if(it->options[0] || it->options[1])
107                 {
108                         /* are we on the wrong bus/slot ? */
109                         if(pcidev->bus->number != it->options[0] ||
110                            PCI_SLOT(pcidev->devfn) != it->options[1]) {
111                                 continue;
112                         }
113                 }
114
115                 devpriv->pci_dev = pcidev;
116                 dev->board_ptr = mf614_boards + 0; // Zero offset; Only One card is supported
117                 goto found;     
118         }
119
120         comedi_error(dev, "Can't find MF614 card on requested position\n");
121         return -EIO;
122
123 found:
124         printk("Found %s on bus %i, slot %i\n",  
125                 mf614_boards[0].name, pcidev->bus->number, PCI_SLOT(pcidev->devfn));
126
127         /* comedi_pci_enable(struct pci_dev *pdev, const char *res_name) */
128         if(pci_enable_device(devpriv->pci_dev)) {
129                 comedi_error(dev, "Failed to enable PCI device\n");
130                 goto out_exit;
131         }
132         if(pci_request_regions(devpriv->pci_dev, "mf614")) {
133                 comedi_error(dev, "Card's IO ports allready in use\n");
134                 goto out_disable;
135         }
136
137         /* pci_ioremap_bar(devpriv->pci_dev, 0) is for memory regions; This are IO ports */
138         devpriv->BAR0_io = pci_iomap(devpriv->pci_dev, 0, 0);
139         if (!devpriv->BAR0_io) {
140                 goto out_release;
141         }       
142         devpriv->BAR2_io = pci_iomap(devpriv->pci_dev, 2, 0);
143         if (!devpriv->BAR2_io) {
144                 goto out_unmap;
145         }
146         
147         devpriv->in_use = 1;
148         dev->board_name = thisboard->name;
149         
150         /* Allocate subdevices */
151         if(alloc_subdevices(dev, 2) < 0) {
152                 return -ENOMEM;
153         }
154         
155         /* DIN */       
156         s = dev->subdevices + 0;
157         s->type = COMEDI_SUBD_DI;
158         s->subdev_flags = SDF_READABLE;
159         s->n_chan = thisboard->di_chans;
160         s->maxdata = 1;
161         s->range_table = &range_digital;
162         s->insn_bits = mf614_di_insn_bits;
163
164         /* DOUT */      
165         s = dev->subdevices + 1;
166         s->type = COMEDI_SUBD_DO;
167         s->subdev_flags = SDF_WRITABLE;
168         s->n_chan = thisboard->do_chans;
169         s->maxdata = 1;
170         s->range_table = &range_digital;
171         s->insn_bits  = mf614_do_insn_bits;
172
173         printk("comedi%d: mf614: Driver attached\n", dev->minor);
174         
175         return 0;
176
177 out_unmap:
178         pci_iounmap(devpriv->pci_dev, devpriv->BAR0_io);
179 out_release:
180         pci_release_regions(devpriv->pci_dev);
181 out_disable:
182         pci_disable_device(devpriv->pci_dev);
183 out_exit:
184         return -ENODEV;
185 }
186
187 static int mf614_detach(struct comedi_device *dev)
188 {
189         if(devpriv && devpriv->pci_dev)
190         {
191                 if(devpriv->in_use == 1)
192                 {
193                         pci_release_regions(devpriv->pci_dev);
194                         pci_disable_device(devpriv->pci_dev);
195                         pci_iounmap(devpriv->pci_dev, devpriv->BAR0_io);
196                         pci_iounmap(devpriv->pci_dev, devpriv->BAR2_io);
197                 }
198                 
199                 pci_dev_put(devpriv->pci_dev);
200         }
201
202         return 0;
203 }
204
205 /* Write digital data */
206 static int mf614_do_insn_bits(struct comedi_device *dev, 
207                               struct comedi_subdevice *s, 
208                               struct comedi_insn *insn, unsigned int *data)
209 {
210         if(insn->n != 2) {
211                 return -EINVAL;
212         }
213
214         if(data[0]) {
215                 s->state &= ~data[0];
216                 s->state |= data[0] & data[1];
217
218                 iowrite8(s->state, devpriv->BAR0_io + DOUT_reg);
219         }
220         return 2;
221 }
222
223 /* Read digital data */
224 static int mf614_di_insn_bits(struct comedi_device *dev, 
225                               struct comedi_subdevice *s, 
226                               struct comedi_insn *insn, unsigned int *data)
227 {
228         if(insn->n != 2) {
229                 return -EINVAL;
230         }
231
232         data[1] = ioread8(devpriv->BAR0_io + DIN_reg);
233
234         return 2;
235 }
236
237 /*
238 ==============================================================================
239 */
240 static int __devinit mf614_probe(struct pci_dev *dev, const struct pci_device_id *ent)
241 {
242         return comedi_pci_auto_config(dev, driver_mf614.driver_name);
243 }
244
245 static void __devexit mf614_remove(struct pci_dev *dev)
246 {
247         comedi_pci_auto_unconfig(dev);
248 }
249
250 static struct pci_driver driver_mf614_pci = {
251         .id_table = mf614_pci_table,
252         .probe = &mf614_probe,
253         .remove = __devexit_p(&mf614_remove)
254 };
255
256 static int __init mf614_init_module(void)
257 {
258         int retval;
259
260         retval = comedi_driver_register(&driver_mf614);
261         if (retval < 0)
262                 return retval;
263
264         /* Copy "name" from Comedi driver struct into pci_driver_struct*/
265         driver_mf614_pci.name = (char *)driver_mf614.driver_name; 
266         return pci_register_driver(&driver_mf614_pci);
267 }
268
269 static void __exit mf614_cleanup_module(void)
270 {
271         pci_unregister_driver(&driver_mf614_pci);
272         comedi_driver_unregister(&driver_mf614);
273 }
274
275 module_init(mf614_init_module);
276 module_exit(mf614_cleanup_module);
277
278 MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
279 MODULE_DESCRIPTION("Humusoft MF614 DAQ Card");
280 MODULE_LICENSE("GPL v2");