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