Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
adl_pci8164.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/adl_pci8164.c
3 
4  Hardware comedi driver fot PCI-8164 Adlink card
5  Copyright (C) 2004 Michel Lachine <[email protected]>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 /*
23 Driver: adl_pci8164
24 Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
25 Devices: [ADLink] PCI-8164 (adl_pci8164)
26 Author: Michel Lachaine <[email protected]>
27 Status: experimental
28 Updated: Mon, 14 Apr 2008 15:10:32 +0100
29 
30 Configuration Options: not applicable, uses PCI auto config
31 */
32 
33 #include "../comedidev.h"
34 #include <linux/kernel.h>
35 #include <linux/delay.h>
36 #include "comedi_fc.h"
37 #include "8253.h"
38 
39 #define PCI8164_AXIS_X 0x00
40 #define PCI8164_AXIS_Y 0x08
41 #define PCI8164_AXIS_Z 0x10
42 #define PCI8164_AXIS_U 0x18
43 
44 #define PCI8164_MSTS 0x00
45 #define PCI8164_SSTS 0x02
46 #define PCI8164_BUF0 0x04
47 #define PCI8164_BUF1 0x06
48 
49 #define PCI8164_CMD 0x00
50 #define PCI8164_OTP 0x02
51 
52 #define PCI_DEVICE_ID_PCI8164 0x8164
53 
54 /*
55  all the read commands are the same except for the addition a constant
56  * const to the data for inw()
57  */
58 static void adl_pci8164_insn_read(struct comedi_device *dev,
59  struct comedi_subdevice *s,
60  struct comedi_insn *insn,
61  unsigned int *data,
62  char *action, unsigned short offset)
63 {
64  int axis, axis_reg;
65  char *axisname;
66 
67  axis = CR_CHAN(insn->chanspec);
68 
69  switch (axis) {
70  case 0:
71  axis_reg = PCI8164_AXIS_X;
72  axisname = "X";
73  break;
74  case 1:
75  axis_reg = PCI8164_AXIS_Y;
76  axisname = "Y";
77  break;
78  case 2:
79  axis_reg = PCI8164_AXIS_Z;
80  axisname = "Z";
81  break;
82  case 3:
83  axis_reg = PCI8164_AXIS_U;
84  axisname = "U";
85  break;
86  default:
87  axis_reg = PCI8164_AXIS_X;
88  axisname = "X";
89  }
90 
91  data[0] = inw(dev->iobase + axis_reg + offset);
92  printk(KERN_DEBUG "comedi: pci8164 %s read -> "
93  "%04X:%04X on axis %s\n",
94  action, data[0], data[1], axisname);
95 }
96 
97 static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
98  struct comedi_subdevice *s,
99  struct comedi_insn *insn,
100  unsigned int *data)
101 {
102  adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
103  return 2;
104 }
105 
106 static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
107  struct comedi_subdevice *s,
108  struct comedi_insn *insn,
109  unsigned int *data)
110 {
111  adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
112  return 2;
113 }
114 
115 static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
116  struct comedi_subdevice *s,
117  struct comedi_insn *insn,
118  unsigned int *data)
119 {
120  adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
121  return 2;
122 }
123 
124 static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
125  struct comedi_subdevice *s,
126  struct comedi_insn *insn,
127  unsigned int *data)
128 {
129  adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
130  return 2;
131 }
132 
133 /*
134  all the write commands are the same except for the addition a constant
135  * const to the data for outw()
136  */
137 static void adl_pci8164_insn_out(struct comedi_device *dev,
138  struct comedi_subdevice *s,
139  struct comedi_insn *insn,
140  unsigned int *data,
141  char *action, unsigned short offset)
142 {
143  unsigned int axis, axis_reg;
144 
145  char *axisname;
146 
147  axis = CR_CHAN(insn->chanspec);
148 
149  switch (axis) {
150  case 0:
151  axis_reg = PCI8164_AXIS_X;
152  axisname = "X";
153  break;
154  case 1:
155  axis_reg = PCI8164_AXIS_Y;
156  axisname = "Y";
157  break;
158  case 2:
159  axis_reg = PCI8164_AXIS_Z;
160  axisname = "Z";
161  break;
162  case 3:
163  axis_reg = PCI8164_AXIS_U;
164  axisname = "U";
165  break;
166  default:
167  axis_reg = PCI8164_AXIS_X;
168  axisname = "X";
169  }
170 
171  outw(data[0], dev->iobase + axis_reg + offset);
172 
173  printk(KERN_DEBUG "comedi: pci8164 %s write -> "
174  "%04X:%04X on axis %s\n",
175  action, data[0], data[1], axisname);
176 
177 }
178 
179 static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
180  struct comedi_subdevice *s,
181  struct comedi_insn *insn,
182  unsigned int *data)
183 {
184  adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
185  return 2;
186 }
187 
188 static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
189  struct comedi_subdevice *s,
190  struct comedi_insn *insn,
191  unsigned int *data)
192 {
193  adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
194  return 2;
195 }
196 
197 static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
198  struct comedi_subdevice *s,
199  struct comedi_insn *insn,
200  unsigned int *data)
201 {
202  adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
203  return 2;
204 }
205 
206 static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
207  struct comedi_subdevice *s,
208  struct comedi_insn *insn,
209  unsigned int *data)
210 {
211  adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
212  return 2;
213 }
214 
215 static int adl_pci8164_attach_pci(struct comedi_device *dev,
216  struct pci_dev *pcidev)
217 {
218  struct comedi_subdevice *s;
219  int ret;
220 
221  comedi_set_hw_dev(dev, &pcidev->dev);
222 
223  dev->board_name = dev->driver->driver_name;
224 
225  ret = comedi_pci_enable(pcidev, dev->board_name);
226  if (ret)
227  return ret;
228  dev->iobase = pci_resource_start(pcidev, 2);
229 
230  ret = comedi_alloc_subdevices(dev, 4);
231  if (ret)
232  return ret;
233 
234  s = &dev->subdevices[0];
235  s->type = COMEDI_SUBD_PROC;
237  s->n_chan = 4;
238  s->maxdata = 0xffff;
239  s->len_chanlist = 4;
240  /* s->range_table = &range_axis; */
241  s->insn_read = adl_pci8164_insn_read_msts;
242  s->insn_write = adl_pci8164_insn_write_cmd;
243 
244  s = &dev->subdevices[1];
245  s->type = COMEDI_SUBD_PROC;
247  s->n_chan = 4;
248  s->maxdata = 0xffff;
249  s->len_chanlist = 4;
250  /* s->range_table = &range_axis; */
251  s->insn_read = adl_pci8164_insn_read_ssts;
252  s->insn_write = adl_pci8164_insn_write_otp;
253 
254  s = &dev->subdevices[2];
255  s->type = COMEDI_SUBD_PROC;
257  s->n_chan = 4;
258  s->maxdata = 0xffff;
259  s->len_chanlist = 4;
260  /* s->range_table = &range_axis; */
261  s->insn_read = adl_pci8164_insn_read_buf0;
262  s->insn_write = adl_pci8164_insn_write_buf0;
263 
264  s = &dev->subdevices[3];
265  s->type = COMEDI_SUBD_PROC;
267  s->n_chan = 4;
268  s->maxdata = 0xffff;
269  s->len_chanlist = 4;
270  /* s->range_table = &range_axis; */
271  s->insn_read = adl_pci8164_insn_read_buf1;
272  s->insn_write = adl_pci8164_insn_write_buf1;
273 
274  dev_info(dev->class_dev, "%s attached\n", dev->board_name);
275 
276  return 0;
277 }
278 
279 static void adl_pci8164_detach(struct comedi_device *dev)
280 {
281  struct pci_dev *pcidev = comedi_to_pci_dev(dev);
282 
283  if (pcidev) {
284  if (dev->iobase)
285  comedi_pci_disable(pcidev);
286  }
287 }
288 
289 static struct comedi_driver adl_pci8164_driver = {
290  .driver_name = "adl_pci8164",
291  .module = THIS_MODULE,
292  .attach_pci = adl_pci8164_attach_pci,
293  .detach = adl_pci8164_detach,
294 };
295 
296 static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev,
297  const struct pci_device_id *ent)
298 {
299  return comedi_pci_auto_config(dev, &adl_pci8164_driver);
300 }
301 
302 static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev)
303 {
305 }
306 
307 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
309  {0}
310 };
311 MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
312 
313 static struct pci_driver adl_pci8164_pci_driver = {
314  .name = "adl_pci8164",
315  .id_table = adl_pci8164_pci_table,
316  .probe = adl_pci8164_pci_probe,
317  .remove = __devexit_p(adl_pci8164_pci_remove),
318 };
319 module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
320 
321 MODULE_AUTHOR("Comedi http://www.comedi.org");
322 MODULE_DESCRIPTION("Comedi low-level driver");
323 MODULE_LICENSE("GPL");