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