]>
Commit | Line | Data |
---|---|---|
07b509e6 | 1 | /* |
fb999e7f RKM |
2 | * comedi/drivers/jr3_pci.c |
3 | * hardware driver for JR3/PCI force sensor board | |
4 | * | |
5 | * COMEDI - Linux Control and Measurement Device Interface | |
6 | * Copyright (C) 2007 Anders Blomdell <anders.blomdell@control.lth.se> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | */ | |
07b509e6 | 18 | /* |
10ba619d IA |
19 | * Driver: jr3_pci |
20 | * Description: JR3/PCI force sensor board | |
21 | * Author: Anders Blomdell <anders.blomdell@control.lth.se> | |
22 | * Updated: Thu, 01 Nov 2012 17:34:55 +0000 | |
23 | * Status: works | |
24 | * Devices: [JR3] PCI force sensor board (jr3_pci) | |
25 | * | |
26 | * Configuration options: | |
27 | * None | |
28 | * | |
29 | * Manual configuration of comedi devices is not supported by this | |
30 | * driver; supported PCI devices are configured as comedi devices | |
31 | * automatically. | |
32 | * | |
33 | * The DSP on the board requires initialization code, which can be | |
34 | * loaded by placing it in /lib/firmware/comedi. The initialization | |
35 | * code should be somewhere on the media you got with your card. One | |
36 | * version is available from http://www.comedi.org in the | |
37 | * comedi_nonfree_firmware tarball. The file is called "jr3pci.idm". | |
38 | */ | |
07b509e6 | 39 | |
33782dd5 | 40 | #include <linux/kernel.h> |
ce157f80 | 41 | #include <linux/module.h> |
07b509e6 AB |
42 | #include <linux/delay.h> |
43 | #include <linux/ctype.h> | |
9b5de0a0 | 44 | #include <linux/jiffies.h> |
5a0e3ad6 | 45 | #include <linux/slab.h> |
9b5de0a0 | 46 | #include <linux/timer.h> |
33782dd5 | 47 | |
e4c296dc | 48 | #include "../comedi_pci.h" |
33782dd5 | 49 | |
07b509e6 AB |
50 | #include "jr3_pci.h" |
51 | ||
07b509e6 | 52 | #define PCI_VENDOR_ID_JR3 0x1762 |
7211806a HS |
53 | |
54 | enum jr3_pci_boardid { | |
55 | BOARD_JR3_1, | |
56 | BOARD_JR3_2, | |
57 | BOARD_JR3_3, | |
58 | BOARD_JR3_4, | |
59 | }; | |
60 | ||
61 | struct jr3_pci_board { | |
62 | const char *name; | |
63 | int n_subdevs; | |
64 | }; | |
65 | ||
66 | static const struct jr3_pci_board jr3_pci_boards[] = { | |
67 | [BOARD_JR3_1] = { | |
68 | .name = "jr3_pci_1", | |
69 | .n_subdevs = 1, | |
70 | }, | |
71 | [BOARD_JR3_2] = { | |
72 | .name = "jr3_pci_2", | |
73 | .n_subdevs = 2, | |
74 | }, | |
75 | [BOARD_JR3_3] = { | |
76 | .name = "jr3_pci_3", | |
77 | .n_subdevs = 3, | |
78 | }, | |
79 | [BOARD_JR3_4] = { | |
80 | .name = "jr3_pci_4", | |
81 | .n_subdevs = 4, | |
82 | }, | |
83 | }; | |
07b509e6 | 84 | |
0a44493f HS |
85 | struct jr3_pci_transform { |
86 | struct { | |
87 | u16 link_type; | |
88 | s16 link_amount; | |
89 | } link[8]; | |
90 | }; | |
91 | ||
da1331a5 HS |
92 | struct jr3_pci_poll_delay { |
93 | int min; | |
94 | int max; | |
95 | }; | |
96 | ||
217fbbbc | 97 | struct jr3_pci_dev_private { |
95b24682 | 98 | struct jr3_t __iomem *iobase; |
07b509e6 | 99 | struct timer_list timer; |
217fbbbc BP |
100 | }; |
101 | ||
4af8c819 IA |
102 | union jr3_pci_single_range { |
103 | struct comedi_lrange l; | |
104 | char _reserved[offsetof(struct comedi_lrange, range[1])]; | |
105 | }; | |
106 | ||
de98befe IA |
107 | enum jr3_pci_poll_state { |
108 | state_jr3_poll, | |
109 | state_jr3_init_wait_for_offset, | |
110 | state_jr3_init_transform_complete, | |
111 | state_jr3_init_set_full_scale_complete, | |
112 | state_jr3_init_use_offset_complete, | |
113 | state_jr3_done | |
114 | }; | |
115 | ||
c6a3b7b6 | 116 | struct jr3_pci_subdev_private { |
95b24682 | 117 | struct jr3_channel __iomem *channel; |
07b509e6 | 118 | unsigned long next_time_min; |
de98befe | 119 | enum jr3_pci_poll_state state; |
07b509e6 AB |
120 | int serial_no; |
121 | int model_no; | |
4af8c819 | 122 | union jr3_pci_single_range range[9]; |
9ced1de6 | 123 | const struct comedi_lrange *range_table_list[8 * 7 + 2]; |
790c5541 | 124 | unsigned int maxdata_list[8 * 7 + 2]; |
07b509e6 AB |
125 | u16 errors; |
126 | int retries; | |
c6a3b7b6 | 127 | }; |
07b509e6 | 128 | |
da1331a5 | 129 | static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) |
07b509e6 | 130 | { |
da1331a5 | 131 | struct jr3_pci_poll_delay result; |
07b509e6 AB |
132 | |
133 | result.min = min; | |
134 | result.max = max; | |
135 | return result; | |
136 | } | |
137 | ||
95b24682 | 138 | static int is_complete(struct jr3_channel __iomem *channel) |
07b509e6 AB |
139 | { |
140 | return get_s16(&channel->command_word0) == 0; | |
141 | } | |
142 | ||
95b24682 | 143 | static void set_transforms(struct jr3_channel __iomem *channel, |
8c8022fc | 144 | const struct jr3_pci_transform *transf, short num) |
07b509e6 AB |
145 | { |
146 | int i; | |
147 | ||
d5e59c96 | 148 | num &= 0x000f; /* Make sure that 0 <= num <= 15 */ |
07b509e6 | 149 | for (i = 0; i < 8; i++) { |
07b509e6 | 150 | set_u16(&channel->transforms[num].link[i].link_type, |
8c8022fc | 151 | transf->link[i].link_type); |
5f74ea14 | 152 | udelay(1); |
07b509e6 | 153 | set_s16(&channel->transforms[num].link[i].link_amount, |
8c8022fc | 154 | transf->link[i].link_amount); |
5f74ea14 | 155 | udelay(1); |
8c8022fc | 156 | if (transf->link[i].link_type == end_x_form) |
07b509e6 | 157 | break; |
07b509e6 AB |
158 | } |
159 | } | |
160 | ||
95b24682 | 161 | static void use_transform(struct jr3_channel __iomem *channel, |
0a85b6f0 | 162 | short transf_num) |
07b509e6 AB |
163 | { |
164 | set_s16(&channel->command_word0, 0x0500 + (transf_num & 0x000f)); | |
165 | } | |
166 | ||
95b24682 | 167 | static void use_offset(struct jr3_channel __iomem *channel, short offset_num) |
07b509e6 AB |
168 | { |
169 | set_s16(&channel->command_word0, 0x0600 + (offset_num & 0x000f)); | |
170 | } | |
171 | ||
95b24682 | 172 | static void set_offset(struct jr3_channel __iomem *channel) |
07b509e6 AB |
173 | { |
174 | set_s16(&channel->command_word0, 0x0700); | |
175 | } | |
176 | ||
050509fa | 177 | struct six_axis_t { |
07b509e6 AB |
178 | s16 fx; |
179 | s16 fy; | |
180 | s16 fz; | |
181 | s16 mx; | |
182 | s16 my; | |
183 | s16 mz; | |
050509fa | 184 | }; |
07b509e6 | 185 | |
95b24682 | 186 | static void set_full_scales(struct jr3_channel __iomem *channel, |
0a85b6f0 | 187 | struct six_axis_t full_scale) |
07b509e6 | 188 | { |
07b509e6 AB |
189 | set_s16(&channel->full_scale.fx, full_scale.fx); |
190 | set_s16(&channel->full_scale.fy, full_scale.fy); | |
191 | set_s16(&channel->full_scale.fz, full_scale.fz); | |
192 | set_s16(&channel->full_scale.mx, full_scale.mx); | |
193 | set_s16(&channel->full_scale.my, full_scale.my); | |
194 | set_s16(&channel->full_scale.mz, full_scale.mz); | |
195 | set_s16(&channel->command_word0, 0x0a00); | |
196 | } | |
197 | ||
95b24682 | 198 | static struct six_axis_t get_min_full_scales(struct jr3_channel __iomem |
0a85b6f0 | 199 | *channel) |
07b509e6 | 200 | { |
050509fa | 201 | struct six_axis_t result; |
cd9da617 | 202 | |
07b509e6 AB |
203 | result.fx = get_s16(&channel->min_full_scale.fx); |
204 | result.fy = get_s16(&channel->min_full_scale.fy); | |
205 | result.fz = get_s16(&channel->min_full_scale.fz); | |
206 | result.mx = get_s16(&channel->min_full_scale.mx); | |
207 | result.my = get_s16(&channel->min_full_scale.my); | |
208 | result.mz = get_s16(&channel->min_full_scale.mz); | |
209 | return result; | |
210 | } | |
211 | ||
95b24682 | 212 | static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem |
0a85b6f0 | 213 | *channel) |
07b509e6 | 214 | { |
050509fa | 215 | struct six_axis_t result; |
cd9da617 | 216 | |
07b509e6 AB |
217 | result.fx = get_s16(&channel->max_full_scale.fx); |
218 | result.fy = get_s16(&channel->max_full_scale.fy); | |
219 | result.fz = get_s16(&channel->max_full_scale.fz); | |
220 | result.mx = get_s16(&channel->max_full_scale.mx); | |
221 | result.my = get_s16(&channel->max_full_scale.my); | |
222 | result.mz = get_s16(&channel->max_full_scale.mz); | |
223 | return result; | |
224 | } | |
225 | ||
16a86abe HS |
226 | static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, |
227 | struct comedi_subdevice *s, | |
228 | unsigned int chan) | |
229 | { | |
230 | struct jr3_pci_subdev_private *spriv = s->private; | |
231 | unsigned int val = 0; | |
232 | ||
233 | if (spriv->state != state_jr3_done) | |
234 | return 0; | |
235 | ||
236 | if (chan < 56) { | |
237 | unsigned int axis = chan % 8; | |
5efe1159 | 238 | unsigned int filter = chan / 8; |
16a86abe HS |
239 | |
240 | switch (axis) { | |
241 | case 0: | |
242 | val = get_s16(&spriv->channel->filter[filter].fx); | |
243 | break; | |
244 | case 1: | |
245 | val = get_s16(&spriv->channel->filter[filter].fy); | |
246 | break; | |
247 | case 2: | |
248 | val = get_s16(&spriv->channel->filter[filter].fz); | |
249 | break; | |
250 | case 3: | |
251 | val = get_s16(&spriv->channel->filter[filter].mx); | |
252 | break; | |
253 | case 4: | |
254 | val = get_s16(&spriv->channel->filter[filter].my); | |
255 | break; | |
256 | case 5: | |
257 | val = get_s16(&spriv->channel->filter[filter].mz); | |
258 | break; | |
259 | case 6: | |
260 | val = get_s16(&spriv->channel->filter[filter].v1); | |
261 | break; | |
262 | case 7: | |
263 | val = get_s16(&spriv->channel->filter[filter].v2); | |
264 | break; | |
265 | } | |
266 | val += 0x4000; | |
267 | } else if (chan == 56) { | |
268 | val = get_u16(&spriv->channel->model_no); | |
269 | } else if (chan == 57) { | |
270 | val = get_u16(&spriv->channel->serial_no); | |
271 | } | |
272 | ||
273 | return val; | |
274 | } | |
275 | ||
0a85b6f0 MT |
276 | static int jr3_pci_ai_insn_read(struct comedi_device *dev, |
277 | struct comedi_subdevice *s, | |
16a86abe HS |
278 | struct comedi_insn *insn, |
279 | unsigned int *data) | |
07b509e6 | 280 | { |
16a86abe HS |
281 | struct jr3_pci_subdev_private *spriv = s->private; |
282 | unsigned int chan = CR_CHAN(insn->chanspec); | |
283 | u16 errors; | |
284 | int i; | |
285 | ||
16a86abe HS |
286 | errors = get_u16(&spriv->channel->errors); |
287 | if (spriv->state != state_jr3_done || | |
288 | (errors & (watch_dog | watch_dog2 | sensor_change))) { | |
289 | /* No sensor or sensor changed */ | |
290 | if (spriv->state == state_jr3_done) { | |
291 | /* Restart polling */ | |
292 | spriv->state = state_jr3_poll; | |
07b509e6 | 293 | } |
16a86abe | 294 | return -EAGAIN; |
07b509e6 | 295 | } |
16a86abe HS |
296 | |
297 | for (i = 0; i < insn->n; i++) | |
298 | data[i] = jr3_pci_ai_read_chan(dev, s, chan); | |
299 | ||
300 | return insn->n; | |
07b509e6 AB |
301 | } |
302 | ||
3c17ba07 | 303 | static int jr3_pci_open(struct comedi_device *dev) |
07b509e6 | 304 | { |
617cd653 HS |
305 | struct jr3_pci_subdev_private *spriv; |
306 | struct comedi_subdevice *s; | |
307 | int i; | |
07b509e6 | 308 | |
f41ad667 | 309 | dev_dbg(dev->class_dev, "jr3_pci_open\n"); |
ed8cd560 | 310 | for (i = 0; i < dev->n_subdevices; i++) { |
617cd653 HS |
311 | s = &dev->subdevices[i]; |
312 | spriv = s->private; | |
67aa069d IA |
313 | dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", |
314 | spriv, spriv->serial_no, s->index); | |
07b509e6 | 315 | } |
3c17ba07 | 316 | return 0; |
07b509e6 AB |
317 | } |
318 | ||
2ca9bc2e HS |
319 | static int read_idm_word(const u8 *data, size_t size, int *pos, |
320 | unsigned int *val) | |
07b509e6 AB |
321 | { |
322 | int result = 0; | |
cd9da617 HS |
323 | int value; |
324 | ||
57991b6b | 325 | if (pos && val) { |
d5e59c96 | 326 | /* Skip over non hex */ |
abcdc99f IA |
327 | for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) |
328 | ; | |
d5e59c96 | 329 | /* Collect value */ |
07b509e6 | 330 | *val = 0; |
3ff16c25 | 331 | for (; *pos < size; (*pos)++) { |
3ff16c25 AS |
332 | value = hex_to_bin(data[*pos]); |
333 | if (value >= 0) { | |
334 | result = 1; | |
335 | *val = (*val << 4) + value; | |
abcdc99f | 336 | } else { |
3ff16c25 | 337 | break; |
abcdc99f | 338 | } |
07b509e6 AB |
339 | } |
340 | } | |
341 | return result; | |
342 | } | |
343 | ||
127301cb HS |
344 | static int jr3_check_firmware(struct comedi_device *dev, |
345 | const u8 *data, size_t size) | |
07b509e6 | 346 | { |
127301cb HS |
347 | int more = 1; |
348 | int pos = 0; | |
349 | ||
07b509e6 AB |
350 | /* |
351 | * IDM file format is: | |
352 | * { count, address, data <count> } * | |
353 | * ffff | |
354 | */ | |
07b509e6 | 355 | while (more) { |
127301cb HS |
356 | unsigned int count = 0; |
357 | unsigned int addr = 0; | |
07b509e6 AB |
358 | |
359 | more = more && read_idm_word(data, size, &pos, &count); | |
127301cb HS |
360 | if (more && count == 0xffff) |
361 | return 0; | |
362 | ||
07b509e6 AB |
363 | more = more && read_idm_word(data, size, &pos, &addr); |
364 | while (more && count > 0) { | |
127301cb HS |
365 | unsigned int dummy = 0; |
366 | ||
07b509e6 AB |
367 | more = more && read_idm_word(data, size, &pos, &dummy); |
368 | count--; | |
369 | } | |
370 | } | |
371 | ||
127301cb HS |
372 | return -ENODATA; |
373 | } | |
374 | ||
375 | static void jr3_write_firmware(struct comedi_device *dev, | |
376 | int subdev, const u8 *data, size_t size) | |
377 | { | |
378 | struct jr3_pci_dev_private *devpriv = dev->private; | |
379 | struct jr3_t __iomem *iobase = devpriv->iobase; | |
380 | u32 __iomem *lo; | |
381 | u32 __iomem *hi; | |
382 | int more = 1; | |
383 | int pos = 0; | |
384 | ||
385 | while (more) { | |
386 | unsigned int count = 0; | |
387 | unsigned int addr = 0; | |
388 | ||
389 | more = more && read_idm_word(data, size, &pos, &count); | |
390 | if (more && count == 0xffff) | |
391 | return; | |
392 | ||
393 | more = more && read_idm_word(data, size, &pos, &addr); | |
394 | ||
395 | dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", | |
396 | subdev, count, addr); | |
397 | ||
398 | while (more && count > 0) { | |
399 | if (addr & 0x4000) { | |
400 | /* 16 bit data, never seen in real life!! */ | |
401 | unsigned int data1 = 0; | |
402 | ||
403 | more = more && | |
404 | read_idm_word(data, size, &pos, &data1); | |
405 | count--; | |
406 | /* jr3[addr + 0x20000 * pnum] = data1; */ | |
407 | } else { | |
408 | /* Download 24 bit program */ | |
409 | unsigned int data1 = 0; | |
410 | unsigned int data2 = 0; | |
07b509e6 | 411 | |
127301cb HS |
412 | lo = &iobase->channel[subdev].program_lo[addr]; |
413 | hi = &iobase->channel[subdev].program_hi[addr]; | |
07b509e6 | 414 | |
abcdc99f | 415 | more = more && |
127301cb | 416 | read_idm_word(data, size, &pos, &data1); |
abcdc99f | 417 | more = more && |
127301cb HS |
418 | read_idm_word(data, size, &pos, &data2); |
419 | count -= 2; | |
420 | if (more) { | |
421 | set_u16(lo, data1); | |
422 | udelay(1); | |
423 | set_u16(hi, data2); | |
424 | udelay(1); | |
07b509e6 AB |
425 | } |
426 | } | |
127301cb | 427 | addr++; |
07b509e6 AB |
428 | } |
429 | } | |
127301cb HS |
430 | } |
431 | ||
432 | static int jr3_download_firmware(struct comedi_device *dev, | |
433 | const u8 *data, size_t size, | |
434 | unsigned long context) | |
435 | { | |
127301cb HS |
436 | int subdev; |
437 | int ret; | |
438 | ||
439 | /* verify IDM file format */ | |
440 | ret = jr3_check_firmware(dev, data, size); | |
441 | if (ret) | |
442 | return ret; | |
443 | ||
444 | /* write firmware to each subdevice */ | |
ed8cd560 | 445 | for (subdev = 0; subdev < dev->n_subdevices; subdev++) |
127301cb HS |
446 | jr3_write_firmware(dev, subdev, data, size); |
447 | ||
448 | return 0; | |
07b509e6 AB |
449 | } |
450 | ||
d5e59c96 AJ |
451 | static struct jr3_pci_poll_delay |
452 | jr3_pci_poll_subdevice(struct comedi_subdevice *s) | |
07b509e6 | 453 | { |
01fca473 | 454 | struct jr3_pci_subdev_private *spriv = s->private; |
da1331a5 | 455 | struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); |
01fca473 HS |
456 | struct jr3_channel __iomem *channel; |
457 | u16 model_no; | |
458 | u16 serial_no; | |
459 | int errors; | |
b1f68dc1 | 460 | int i; |
07b509e6 | 461 | |
01fca473 HS |
462 | channel = spriv->channel; |
463 | errors = get_u16(&channel->errors); | |
464 | ||
465 | if (errors != spriv->errors) | |
466 | spriv->errors = errors; | |
467 | ||
468 | /* Sensor communication lost? force poll mode */ | |
469 | if (errors & (watch_dog | watch_dog2 | sensor_change)) | |
470 | spriv->state = state_jr3_poll; | |
471 | ||
472 | switch (spriv->state) { | |
473 | case state_jr3_poll: | |
474 | model_no = get_u16(&channel->model_no); | |
475 | serial_no = get_u16(&channel->serial_no); | |
476 | ||
477 | if ((errors & (watch_dog | watch_dog2)) || | |
478 | model_no == 0 || serial_no == 0) { | |
479 | /* | |
480 | * Still no sensor, keep on polling. | |
481 | * Since it takes up to 10 seconds for offsets to | |
482 | * stabilize, polling each second should suffice. | |
483 | */ | |
484 | } else { | |
485 | spriv->retries = 0; | |
486 | spriv->state = state_jr3_init_wait_for_offset; | |
487 | } | |
488 | break; | |
489 | case state_jr3_init_wait_for_offset: | |
490 | spriv->retries++; | |
491 | if (spriv->retries < 10) { | |
492 | /* | |
493 | * Wait for offeset to stabilize | |
494 | * (< 10 s according to manual) | |
495 | */ | |
496 | } else { | |
0a44493f | 497 | struct jr3_pci_transform transf; |
01fca473 HS |
498 | |
499 | spriv->model_no = get_u16(&channel->model_no); | |
500 | spriv->serial_no = get_u16(&channel->serial_no); | |
501 | ||
502 | /* Transformation all zeros */ | |
503 | for (i = 0; i < ARRAY_SIZE(transf.link); i++) { | |
504 | transf.link[i].link_type = (enum link_types)0; | |
505 | transf.link[i].link_amount = 0; | |
07b509e6 | 506 | } |
abcdc99f | 507 | |
8c8022fc | 508 | set_transforms(channel, &transf, 0); |
01fca473 HS |
509 | use_transform(channel, 0); |
510 | spriv->state = state_jr3_init_transform_complete; | |
511 | /* Allow 20 ms for completion */ | |
512 | result = poll_delay_min_max(20, 100); | |
513 | } | |
514 | break; | |
515 | case state_jr3_init_transform_complete: | |
516 | if (!is_complete(channel)) { | |
517 | result = poll_delay_min_max(20, 100); | |
518 | } else { | |
519 | /* Set full scale */ | |
520 | struct six_axis_t min_full_scale; | |
521 | struct six_axis_t max_full_scale; | |
522 | ||
523 | min_full_scale = get_min_full_scales(channel); | |
524 | max_full_scale = get_max_full_scales(channel); | |
525 | set_full_scales(channel, max_full_scale); | |
526 | ||
527 | spriv->state = state_jr3_init_set_full_scale_complete; | |
528 | /* Allow 20 ms for completion */ | |
529 | result = poll_delay_min_max(20, 100); | |
07b509e6 | 530 | } |
01fca473 HS |
531 | break; |
532 | case state_jr3_init_set_full_scale_complete: | |
533 | if (!is_complete(channel)) { | |
534 | result = poll_delay_min_max(20, 100); | |
535 | } else { | |
536 | struct force_array __iomem *fs = &channel->full_scale; | |
4af8c819 | 537 | union jr3_pci_single_range *r = spriv->range; |
01fca473 HS |
538 | |
539 | /* Use ranges in kN or we will overflow around 2000N! */ | |
4af8c819 IA |
540 | r[0].l.range[0].min = -get_s16(&fs->fx) * 1000; |
541 | r[0].l.range[0].max = get_s16(&fs->fx) * 1000; | |
542 | r[1].l.range[0].min = -get_s16(&fs->fy) * 1000; | |
543 | r[1].l.range[0].max = get_s16(&fs->fy) * 1000; | |
544 | r[2].l.range[0].min = -get_s16(&fs->fz) * 1000; | |
545 | r[2].l.range[0].max = get_s16(&fs->fz) * 1000; | |
546 | r[3].l.range[0].min = -get_s16(&fs->mx) * 100; | |
547 | r[3].l.range[0].max = get_s16(&fs->mx) * 100; | |
548 | r[4].l.range[0].min = -get_s16(&fs->my) * 100; | |
549 | r[4].l.range[0].max = get_s16(&fs->my) * 100; | |
550 | r[5].l.range[0].min = -get_s16(&fs->mz) * 100; | |
01fca473 | 551 | /* the next five are questionable */ |
4af8c819 IA |
552 | r[5].l.range[0].max = get_s16(&fs->mz) * 100; |
553 | r[6].l.range[0].min = -get_s16(&fs->v1) * 100; | |
554 | r[6].l.range[0].max = get_s16(&fs->v1) * 100; | |
555 | r[7].l.range[0].min = -get_s16(&fs->v2) * 100; | |
556 | r[7].l.range[0].max = get_s16(&fs->v2) * 100; | |
557 | r[8].l.range[0].min = 0; | |
558 | r[8].l.range[0].max = 65535; | |
01fca473 HS |
559 | |
560 | use_offset(channel, 0); | |
561 | spriv->state = state_jr3_init_use_offset_complete; | |
562 | /* Allow 40 ms for completion */ | |
563 | result = poll_delay_min_max(40, 100); | |
564 | } | |
565 | break; | |
566 | case state_jr3_init_use_offset_complete: | |
567 | if (!is_complete(channel)) { | |
568 | result = poll_delay_min_max(20, 100); | |
569 | } else { | |
570 | set_s16(&channel->offsets.fx, 0); | |
571 | set_s16(&channel->offsets.fy, 0); | |
572 | set_s16(&channel->offsets.fz, 0); | |
573 | set_s16(&channel->offsets.mx, 0); | |
574 | set_s16(&channel->offsets.my, 0); | |
575 | set_s16(&channel->offsets.mz, 0); | |
576 | ||
577 | set_offset(channel); | |
578 | ||
579 | spriv->state = state_jr3_done; | |
580 | } | |
581 | break; | |
582 | case state_jr3_done: | |
583 | result = poll_delay_min_max(10000, 20000); | |
584 | break; | |
585 | default: | |
586 | break; | |
07b509e6 | 587 | } |
01fca473 | 588 | |
07b509e6 AB |
589 | return result; |
590 | } | |
591 | ||
592 | static void jr3_pci_poll_dev(unsigned long data) | |
593 | { | |
0a85b6f0 | 594 | struct comedi_device *dev = (struct comedi_device *)data; |
217fbbbc | 595 | struct jr3_pci_dev_private *devpriv = dev->private; |
a448376e HS |
596 | struct jr3_pci_subdev_private *spriv; |
597 | struct comedi_subdevice *s; | |
598 | unsigned long flags; | |
07b509e6 AB |
599 | unsigned long now; |
600 | int delay; | |
601 | int i; | |
602 | ||
5f74ea14 | 603 | spin_lock_irqsave(&dev->spinlock, flags); |
07b509e6 AB |
604 | delay = 1000; |
605 | now = jiffies; | |
a448376e HS |
606 | |
607 | /* Poll all channels that are ready to be polled */ | |
ed8cd560 | 608 | for (i = 0; i < dev->n_subdevices; i++) { |
a448376e HS |
609 | s = &dev->subdevices[i]; |
610 | spriv = s->private; | |
611 | ||
8ec04a49 | 612 | if (time_after_eq(now, spriv->next_time_min)) { |
da1331a5 | 613 | struct jr3_pci_poll_delay sub_delay; |
07b509e6 | 614 | |
a448376e HS |
615 | sub_delay = jr3_pci_poll_subdevice(s); |
616 | ||
617 | spriv->next_time_min = jiffies + | |
618 | msecs_to_jiffies(sub_delay.min); | |
a448376e | 619 | |
abcdc99f IA |
620 | if (sub_delay.max && sub_delay.max < delay) |
621 | /* | |
622 | * Wake up as late as possible -> | |
623 | * poll as many channels as possible at once. | |
624 | */ | |
07b509e6 | 625 | delay = sub_delay.max; |
07b509e6 AB |
626 | } |
627 | } | |
5f74ea14 | 628 | spin_unlock_irqrestore(&dev->spinlock, flags); |
07b509e6 AB |
629 | |
630 | devpriv->timer.expires = jiffies + msecs_to_jiffies(delay); | |
631 | add_timer(&devpriv->timer); | |
632 | } | |
633 | ||
9e4d6742 HS |
634 | static struct jr3_pci_subdev_private * |
635 | jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) | |
636 | { | |
637 | struct jr3_pci_dev_private *devpriv = dev->private; | |
638 | struct jr3_pci_subdev_private *spriv; | |
639 | int j; | |
640 | int k; | |
641 | ||
642 | spriv = comedi_alloc_spriv(s, sizeof(*spriv)); | |
643 | if (!spriv) | |
644 | return NULL; | |
645 | ||
646 | spriv->channel = &devpriv->iobase->channel[s->index].data; | |
9e4d6742 HS |
647 | |
648 | for (j = 0; j < 8; j++) { | |
4af8c819 IA |
649 | spriv->range[j].l.length = 1; |
650 | spriv->range[j].l.range[0].min = -1000000; | |
651 | spriv->range[j].l.range[0].max = 1000000; | |
9e4d6742 HS |
652 | |
653 | for (k = 0; k < 7; k++) { | |
4af8c819 | 654 | spriv->range_table_list[j + k * 8] = &spriv->range[j].l; |
9e4d6742 HS |
655 | spriv->maxdata_list[j + k * 8] = 0x7fff; |
656 | } | |
657 | } | |
4af8c819 IA |
658 | spriv->range[8].l.length = 1; |
659 | spriv->range[8].l.range[0].min = 0; | |
660 | spriv->range[8].l.range[0].max = 65536; | |
661 | ||
662 | spriv->range_table_list[56] = &spriv->range[8].l; | |
663 | spriv->range_table_list[57] = &spriv->range[8].l; | |
9e4d6742 HS |
664 | spriv->maxdata_list[56] = 0xffff; |
665 | spriv->maxdata_list[57] = 0xffff; | |
666 | ||
667 | dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", | |
668 | spriv->channel, devpriv->iobase, | |
669 | ((char __iomem *)spriv->channel - | |
670 | (char __iomem *)devpriv->iobase)); | |
671 | ||
672 | return spriv; | |
673 | } | |
674 | ||
048ad49a IA |
675 | static void jr3_pci_show_copyright(struct comedi_device *dev) |
676 | { | |
677 | struct jr3_pci_dev_private *devpriv = dev->private; | |
678 | struct jr3_channel __iomem *ch0data = &devpriv->iobase->channel[0].data; | |
679 | char copy[ARRAY_SIZE(ch0data->copyright) + 1]; | |
680 | int i; | |
681 | ||
682 | for (i = 0; i < ARRAY_SIZE(ch0data->copyright); i++) | |
683 | copy[i] = (char)(get_u16(&ch0data->copyright[i]) >> 8); | |
684 | copy[i] = '\0'; | |
685 | dev_dbg(dev->class_dev, "Firmware copyright: %s\n", copy); | |
686 | } | |
687 | ||
a690b7e5 | 688 | static int jr3_pci_auto_attach(struct comedi_device *dev, |
7211806a | 689 | unsigned long context) |
07b509e6 | 690 | { |
6af0cf76 | 691 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
165356c7 | 692 | static const struct jr3_pci_board *board; |
217fbbbc | 693 | struct jr3_pci_dev_private *devpriv; |
3c77274c | 694 | struct jr3_pci_subdev_private *spriv; |
050389f5 | 695 | struct comedi_subdevice *s; |
3c77274c | 696 | int ret; |
050389f5 | 697 | int i; |
07b509e6 | 698 | |
67080790 | 699 | if (sizeof(struct jr3_channel) != 0xc00) { |
f41ad667 IA |
700 | dev_err(dev->class_dev, |
701 | "sizeof(struct jr3_channel) = %x [expected %x]\n", | |
5efe1159 | 702 | (unsigned int)sizeof(struct jr3_channel), 0xc00); |
07b509e6 AB |
703 | return -EINVAL; |
704 | } | |
705 | ||
7211806a HS |
706 | if (context < ARRAY_SIZE(jr3_pci_boards)) |
707 | board = &jr3_pci_boards[context]; | |
708 | if (!board) | |
709 | return -ENODEV; | |
710 | dev->board_ptr = board; | |
711 | dev->board_name = board->name; | |
712 | ||
0bdab509 | 713 | devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); |
c34fa261 HS |
714 | if (!devpriv) |
715 | return -ENOMEM; | |
9a1a6cf8 | 716 | |
3c77274c HS |
717 | ret = comedi_pci_enable(dev); |
718 | if (ret) | |
719 | return ret; | |
818f569f | 720 | |
8567a851 | 721 | devpriv->iobase = pci_ioremap_bar(pcidev, 0); |
fa5c5f4c IA |
722 | if (!devpriv->iobase) |
723 | return -ENOMEM; | |
724 | ||
ed8cd560 | 725 | ret = comedi_alloc_subdevices(dev, board->n_subdevs); |
3c77274c HS |
726 | if (ret) |
727 | return ret; | |
07b509e6 AB |
728 | |
729 | dev->open = jr3_pci_open; | |
ed8cd560 | 730 | for (i = 0; i < dev->n_subdevices; i++) { |
050389f5 HS |
731 | s = &dev->subdevices[i]; |
732 | s->type = COMEDI_SUBD_AI; | |
733 | s->subdev_flags = SDF_READABLE | SDF_GROUND; | |
734 | s->n_chan = 8 * 7 + 2; | |
735 | s->insn_read = jr3_pci_ai_insn_read; | |
736 | ||
3c77274c | 737 | spriv = jr3_pci_alloc_spriv(dev, s); |
45292be0 IA |
738 | if (!spriv) |
739 | return -ENOMEM; | |
740 | ||
741 | /* Channel specific range and maxdata */ | |
742 | s->range_table_list = spriv->range_table_list; | |
743 | s->maxdata_list = spriv->maxdata_list; | |
07b509e6 AB |
744 | } |
745 | ||
d5e59c96 | 746 | /* Reset DSP card */ |
800f35d7 IA |
747 | for (i = 0; i < dev->n_subdevices; i++) |
748 | writel(0, &devpriv->iobase->channel[i].reset); | |
07b509e6 | 749 | |
3c77274c HS |
750 | ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, |
751 | "comedi/jr3pci.idm", | |
752 | jr3_download_firmware, 0); | |
cb14a0b4 | 753 | dev_dbg(dev->class_dev, "Firmware load %d\n", ret); |
3c77274c HS |
754 | if (ret < 0) |
755 | return ret; | |
abcdc99f IA |
756 | /* |
757 | * TODO: use firmware to load preferred offset tables. Suggested | |
758 | * format: | |
759 | * model serial Fx Fy Fz Mx My Mz\n | |
760 | * | |
9ff8b151 HS |
761 | * comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, |
762 | * "comedi/jr3_offsets_table", | |
d569541e | 763 | * jr3_download_firmware, 1); |
abcdc99f | 764 | */ |
07b509e6 | 765 | |
abcdc99f IA |
766 | /* |
767 | * It takes a few milliseconds for software to settle as much as we | |
768 | * can read firmware version | |
769 | */ | |
07b509e6 | 770 | msleep_interruptible(25); |
048ad49a | 771 | jr3_pci_show_copyright(dev); |
07b509e6 | 772 | |
d5e59c96 | 773 | /* Start card timer */ |
ed8cd560 | 774 | for (i = 0; i < dev->n_subdevices; i++) { |
050389f5 | 775 | s = &dev->subdevices[i]; |
3c77274c | 776 | spriv = s->private; |
07b509e6 | 777 | |
3c77274c | 778 | spriv->next_time_min = jiffies + msecs_to_jiffies(500); |
07b509e6 AB |
779 | } |
780 | ||
81906c35 | 781 | setup_timer(&devpriv->timer, jr3_pci_poll_dev, (unsigned long)dev); |
07b509e6 AB |
782 | devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); |
783 | add_timer(&devpriv->timer); | |
784 | ||
fb780d21 | 785 | return 0; |
07b509e6 AB |
786 | } |
787 | ||
484ecc95 | 788 | static void jr3_pci_detach(struct comedi_device *dev) |
07b509e6 | 789 | { |
217fbbbc | 790 | struct jr3_pci_dev_private *devpriv = dev->private; |
07b509e6 | 791 | |
07b509e6 AB |
792 | if (devpriv) { |
793 | del_timer_sync(&devpriv->timer); | |
794 | ||
c77049ef | 795 | if (devpriv->iobase) |
95b24682 | 796 | iounmap(devpriv->iobase); |
07b509e6 | 797 | } |
7f072f54 | 798 | comedi_pci_disable(dev); |
07b509e6 AB |
799 | } |
800 | ||
75e6301b | 801 | static struct comedi_driver jr3_pci_driver = { |
df61178c HS |
802 | .driver_name = "jr3_pci", |
803 | .module = THIS_MODULE, | |
b7703d7d | 804 | .auto_attach = jr3_pci_auto_attach, |
df61178c HS |
805 | .detach = jr3_pci_detach, |
806 | }; | |
807 | ||
a690b7e5 | 808 | static int jr3_pci_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 809 | const struct pci_device_id *id) |
727b286b | 810 | { |
b8f4ac23 | 811 | return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data); |
727b286b AT |
812 | } |
813 | ||
41e043fc | 814 | static const struct pci_device_id jr3_pci_pci_table[] = { |
7211806a HS |
815 | { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, |
816 | { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, | |
817 | { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, | |
818 | { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, | |
819 | { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, | |
df61178c HS |
820 | { 0 } |
821 | }; | |
822 | MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); | |
823 | ||
75e6301b HS |
824 | static struct pci_driver jr3_pci_pci_driver = { |
825 | .name = "jr3_pci", | |
df61178c | 826 | .id_table = jr3_pci_pci_table, |
75e6301b | 827 | .probe = jr3_pci_pci_probe, |
9901a4d7 | 828 | .remove = comedi_pci_auto_unconfig, |
727b286b | 829 | }; |
75e6301b | 830 | module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); |
90f703d3 AT |
831 | |
832 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
833 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
834 | MODULE_LICENSE("GPL"); | |
df61178c | 835 | MODULE_FIRMWARE("comedi/jr3pci.idm"); |