Merge tag 'iommu-updates-v3.17' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / staging / comedi / drivers / pcl724.c
1 /*
2  * pcl724.c
3  * Comedi driver for 8255 based ISA and PC/104 DIO boards
4  *
5  * Michal Dobes <dobes@tesnet.cz>
6  */
7
8 /*
9  * Driver: pcl724
10  * Description: Comedi driver for 8255 based ISA DIO boards
11  * Devices: (Advantech) PCL-724 [pcl724]
12  *          (Advantech) PCL-722 [pcl722]
13  *          (Advantech) PCL-731 [pcl731]
14  *          (ADLink) ACL-7122 [acl7122]
15  *          (ADLink) ACL-7124 [acl7124]
16  *          (ADLink) PET-48DIO [pet48dio]
17  *          (WinSystems) PCM-IO48 [pcmio48]
18  *          (Diamond Systems) ONYX-MM-DIO [onyx-mm-dio]
19  * Author: Michal Dobes <dobes@tesnet.cz>
20  * Status: untested
21  *
22  * Configuration options:
23  *   [0] - IO Base
24  *   [1] - IRQ (not supported)
25  *   [2] - number of DIO (pcl722 and acl7122 boards)
26  *         0, 144: 144 DIO configuration
27  *         1,  96:  96 DIO configuration
28  */
29
30 #include <linux/module.h>
31 #include "../comedidev.h"
32
33 #include "8255.h"
34
35 #define SIZE_8255       4
36
37 struct pcl724_board {
38         const char *name;
39         unsigned int io_range;
40         unsigned int can_have96:1;
41         unsigned int is_pet48:1;
42         int numofports;
43 };
44
45 static const struct pcl724_board boardtypes[] = {
46         {
47                 .name           = "pcl724",
48                 .io_range       = 0x04,
49                 .numofports     = 1,    /* 24 DIO channels */
50         }, {
51                 .name           = "pcl722",
52                 .io_range       = 0x20,
53                 .can_have96     = 1,
54                 .numofports     = 6,    /* 144 (or 96) DIO channels */
55         }, {
56                 .name           = "pcl731",
57                 .io_range       = 0x08,
58                 .numofports     = 2,    /* 48 DIO channels */
59         }, {
60                 .name           = "acl7122",
61                 .io_range       = 0x20,
62                 .can_have96     = 1,
63                 .numofports     = 6,    /* 144 (or 96) DIO channels */
64         }, {
65                 .name           = "acl7124",
66                 .io_range       = 0x04,
67                 .numofports     = 1,    /* 24 DIO channels */
68         }, {
69                 .name           = "pet48dio",
70                 .io_range       = 0x02,
71                 .is_pet48       = 1,
72                 .numofports     = 2,    /* 48 DIO channels */
73         }, {
74                 .name           = "pcmio48",
75                 .io_range       = 0x08,
76                 .numofports     = 2,    /* 48 DIO channels */
77         }, {
78                 .name           = "onyx-mm-dio",
79                 .io_range       = 0x10,
80                 .numofports     = 2,    /* 48 DIO channels */
81         },
82 };
83
84 static int pcl724_8255mapped_io(int dir, int port, int data,
85                                 unsigned long iobase)
86 {
87         int movport = SIZE_8255 * (iobase >> 12);
88
89         iobase &= 0x0fff;
90
91         outb(port + movport, iobase);
92         if (dir) {
93                 outb(data, iobase + 1);
94                 return 0;
95         }
96         return inb(iobase + 1);
97 }
98
99 static int pcl724_attach(struct comedi_device *dev,
100                          struct comedi_devconfig *it)
101 {
102         const struct pcl724_board *board = comedi_board(dev);
103         struct comedi_subdevice *s;
104         unsigned long iobase;
105         unsigned int iorange;
106         int n_subdevices;
107         int ret;
108         int i;
109
110         iorange = board->io_range;
111         n_subdevices = board->numofports;
112
113         /* Handle PCL-724 in 96 DIO configuration */
114         if (board->can_have96 &&
115             (it->options[2] == 1 || it->options[2] == 96)) {
116                 iorange = 0x10;
117                 n_subdevices = 4;
118         }
119
120         ret = comedi_request_region(dev, it->options[0], iorange);
121         if (ret)
122                 return ret;
123
124         ret = comedi_alloc_subdevices(dev, n_subdevices);
125         if (ret)
126                 return ret;
127
128         for (i = 0; i < dev->n_subdevices; i++) {
129                 s = &dev->subdevices[i];
130                 if (board->is_pet48) {
131                         iobase = dev->iobase + (i * 0x1000);
132                         ret = subdev_8255_init(dev, s, pcl724_8255mapped_io,
133                                                iobase);
134                 } else {
135                         iobase = dev->iobase + (i * SIZE_8255);
136                         ret = subdev_8255_init(dev, s, NULL, iobase);
137                 }
138                 if (ret)
139                         return ret;
140         }
141
142         return 0;
143 }
144
145 static struct comedi_driver pcl724_driver = {
146         .driver_name    = "pcl724",
147         .module         = THIS_MODULE,
148         .attach         = pcl724_attach,
149         .detach         = comedi_legacy_detach,
150         .board_name     = &boardtypes[0].name,
151         .num_names      = ARRAY_SIZE(boardtypes),
152         .offset         = sizeof(struct pcl724_board),
153 };
154 module_comedi_driver(pcl724_driver);
155
156 MODULE_AUTHOR("Comedi http://www.comedi.org");
157 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
158 MODULE_LICENSE("GPL");