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