1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/cdev.h>
19#include <linux/delay.h>
20#include <linux/device.h>
21#include <linux/dma-mapping.h>
22#include <linux/errno.h>
23#include <linux/init.h>
24#include <linux/ioctl.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/module.h>
28#include <linux/pagemap.h>
29#include <linux/pci.h>
30#include <linux/semaphore.h>
31#include <linux/spinlock.h>
32#include <linux/syscalls.h>
33#include <linux/types.h>
34#include <linux/version.h>
35
36#include <asm/io.h>
37#include <asm/uaccess.h>
38
39#include "../vme.h"
40#include "vme_user.h"
41
42static char driver_name[] = "vme_user";
43
44static int bus[USER_BUS_MAX];
45static int bus_num;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78#define VME_MAJOR 221
79#define VME_DEVS 9
80
81#define MASTER_MINOR 0
82#define MASTER_MAX 3
83#define SLAVE_MINOR 4
84#define SLAVE_MAX 7
85#define CONTROL_MINOR 8
86
87#define PCI_BUF_SIZE 0x20000
88
89
90
91
92typedef struct {
93 void __iomem *kern_buf;
94 dma_addr_t pci_buf;
95 unsigned long long size_buf;
96 struct semaphore sem;
97 struct device *device;
98 struct vme_resource *resource;
99 int users;
100} image_desc_t;
101static image_desc_t image[VME_DEVS];
102
103typedef struct {
104 unsigned long reads;
105 unsigned long writes;
106 unsigned long ioctls;
107 unsigned long irqs;
108 unsigned long berrs;
109 unsigned long dmaErrors;
110 unsigned long timeouts;
111 unsigned long external;
112} driver_stats_t;
113static driver_stats_t statistics;
114
115struct cdev *vme_user_cdev;
116struct class *vme_user_sysfs_class;
117struct device *vme_user_bridge;
118
119
120static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR,
121 MASTER_MINOR, MASTER_MINOR,
122 SLAVE_MINOR, SLAVE_MINOR,
123 SLAVE_MINOR, SLAVE_MINOR,
124 CONTROL_MINOR
125 };
126
127
128static int vme_user_open(struct inode *, struct file *);
129static int vme_user_release(struct inode *, struct file *);
130static ssize_t vme_user_read(struct file *, char *, size_t, loff_t *);
131static ssize_t vme_user_write(struct file *, const char *, size_t, loff_t *);
132static loff_t vme_user_llseek(struct file *, loff_t, int);
133static int vme_user_ioctl(struct inode *, struct file *, unsigned int,
134 unsigned long);
135
136static int __init vme_user_probe(struct device *, int, int);
137static int __exit vme_user_remove(struct device *, int, int);
138
139static struct file_operations vme_user_fops = {
140 .open = vme_user_open,
141 .release = vme_user_release,
142 .read = vme_user_read,
143 .write = vme_user_write,
144 .llseek = vme_user_llseek,
145 .ioctl = vme_user_ioctl,
146};
147
148
149
150
151
152static void reset_counters(void)
153{
154 statistics.reads = 0;
155 statistics.writes = 0;
156 statistics.ioctls = 0;
157 statistics.irqs = 0;
158 statistics.berrs = 0;
159 statistics.dmaErrors = 0;
160 statistics.timeouts = 0;
161}
162
163static int vme_user_open(struct inode *inode, struct file *file)
164{
165 int err;
166 unsigned int minor = MINOR(inode->i_rdev);
167
168 down(&image[minor].sem);
169
170 if (image[minor].resource == NULL) {
171 printk(KERN_ERR "No resources allocated for device\n");
172 err = -EINVAL;
173 goto err_res;
174 }
175
176
177 image[minor].users++;
178
179 up(&image[minor].sem);
180
181 return 0;
182
183err_res:
184 up(&image[minor].sem);
185
186 return err;
187}
188
189static int vme_user_release(struct inode *inode, struct file *file)
190{
191 unsigned int minor = MINOR(inode->i_rdev);
192
193 down(&image[minor].sem);
194
195
196 image[minor].users--;
197
198 up(&image[minor].sem);
199
200 return 0;
201}
202
203
204
205
206
207
208
209static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
210 loff_t *ppos)
211{
212 ssize_t retval;
213 ssize_t copied = 0;
214
215 if (count <= image[minor].size_buf) {
216
217 copied = vme_master_read(image[minor].resource,
218 image[minor].kern_buf, count, *ppos);
219 if (copied < 0) {
220 return (int)copied;
221 }
222
223 retval = __copy_to_user(buf, image[minor].kern_buf,
224 (unsigned long)copied);
225 if (retval != 0) {
226 copied = (copied - retval);
227 printk("User copy failed\n");
228 return -EINVAL;
229 }
230
231 } else {
232
233 printk("Currently don't support large transfers\n");
234
235
236
237 return -EINVAL;
238 }
239
240 return copied;
241}
242
243
244
245
246
247
248
249static ssize_t resource_from_user(unsigned int minor, const char *buf,
250 size_t count, loff_t *ppos)
251{
252 ssize_t retval;
253 ssize_t copied = 0;
254
255 if (count <= image[minor].size_buf) {
256 retval = __copy_from_user(image[minor].kern_buf, buf,
257 (unsigned long)count);
258 if (retval != 0)
259 copied = (copied - retval);
260 else
261 copied = count;
262
263 copied = vme_master_write(image[minor].resource,
264 image[minor].kern_buf, copied, *ppos);
265 } else {
266
267 printk("Currently don't support large transfers\n");
268
269
270
271 return -EINVAL;
272 }
273
274 return copied;
275}
276
277static ssize_t buffer_to_user(unsigned int minor, char __user *buf,
278 size_t count, loff_t *ppos)
279{
280 void __iomem *image_ptr;
281 ssize_t retval;
282
283 image_ptr = image[minor].kern_buf + *ppos;
284
285 retval = __copy_to_user(buf, image_ptr, (unsigned long)count);
286 if (retval != 0) {
287 retval = (count - retval);
288 printk(KERN_WARNING "Partial copy to userspace\n");
289 } else
290 retval = count;
291
292
293 return retval;
294}
295
296static ssize_t buffer_from_user(unsigned int minor, const char *buf,
297 size_t count, loff_t *ppos)
298{
299 void __iomem *image_ptr;
300 size_t retval;
301
302 image_ptr = image[minor].kern_buf + *ppos;
303
304 retval = __copy_from_user(image_ptr, buf, (unsigned long)count);
305 if (retval != 0) {
306 retval = (count - retval);
307 printk(KERN_WARNING "Partial copy to userspace\n");
308 } else
309 retval = count;
310
311
312 return retval;
313}
314
315static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
316 loff_t * ppos)
317{
318 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
319 ssize_t retval;
320 size_t image_size;
321 size_t okcount;
322
323 down(&image[minor].sem);
324
325
326 image_size = vme_get_size(image[minor].resource);
327
328
329 if ((*ppos < 0) || (*ppos > (image_size - 1))) {
330 up(&image[minor].sem);
331 return 0;
332 }
333
334
335 if (*ppos + count > image_size)
336 okcount = image_size - *ppos;
337 else
338 okcount = count;
339
340 switch (type[minor]){
341 case MASTER_MINOR:
342 retval = resource_to_user(minor, buf, okcount, ppos);
343 break;
344 case SLAVE_MINOR:
345 retval = buffer_to_user(minor, buf, okcount, ppos);
346 break;
347 default:
348 retval = -EINVAL;
349 }
350
351 up(&image[minor].sem);
352
353 if (retval > 0)
354 *ppos += retval;
355
356 return retval;
357}
358
359static ssize_t vme_user_write(struct file *file, const char *buf, size_t count,
360 loff_t *ppos)
361{
362 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
363 ssize_t retval;
364 size_t image_size;
365 size_t okcount;
366
367 down(&image[minor].sem);
368
369 image_size = vme_get_size(image[minor].resource);
370
371
372 if ((*ppos < 0) || (*ppos > (image_size - 1))) {
373 up(&image[minor].sem);
374 return 0;
375 }
376
377
378 if (*ppos + count > image_size)
379 okcount = image_size - *ppos;
380 else
381 okcount = count;
382
383 switch (type[minor]){
384 case MASTER_MINOR:
385 retval = resource_from_user(minor, buf, okcount, ppos);
386 break;
387 case SLAVE_MINOR:
388 retval = buffer_from_user(minor, buf, okcount, ppos);
389 break;
390 default:
391 retval = -EINVAL;
392 }
393
394 up(&image[minor].sem);
395
396 if (retval > 0)
397 *ppos += retval;
398
399 return retval;
400}
401
402static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
403{
404 printk(KERN_ERR "Llseek currently incomplete\n");
405 return -EINVAL;
406}
407
408
409
410
411
412
413
414
415
416
417
418static int vme_user_ioctl(struct inode *inode, struct file *file,
419 unsigned int cmd, unsigned long arg)
420{
421 struct vme_master master;
422 struct vme_slave slave;
423 unsigned long copied;
424 unsigned int minor = MINOR(inode->i_rdev);
425 int retval;
426 dma_addr_t pci_addr;
427
428 statistics.ioctls++;
429
430 switch (type[minor]) {
431 case CONTROL_MINOR:
432 break;
433 case MASTER_MINOR:
434 switch (cmd) {
435 case VME_GET_MASTER:
436 memset(&master, 0, sizeof(struct vme_master));
437
438
439
440
441 retval = vme_master_get(image[minor].resource,
442 &(master.enable), &(master.vme_addr),
443 &(master.size), &(master.aspace),
444 &(master.cycle), &(master.dwidth));
445
446 copied = copy_to_user((char *)arg, &master,
447 sizeof(struct vme_master));
448 if (copied != 0) {
449 printk(KERN_WARNING "Partial copy to "
450 "userspace\n");
451 return -EFAULT;
452 }
453
454 return retval;
455 break;
456
457 case VME_SET_MASTER:
458
459 copied = copy_from_user(&master, (char *)arg,
460 sizeof(master));
461 if (copied != 0) {
462 printk(KERN_WARNING "Partial copy from "
463 "userspace\n");
464 return -EFAULT;
465 }
466
467
468
469
470 return vme_master_set(image[minor].resource,
471 master.enable, master.vme_addr, master.size,
472 master.aspace, master.cycle, master.dwidth);
473
474 break;
475 }
476 break;
477 case SLAVE_MINOR:
478 switch (cmd) {
479 case VME_GET_SLAVE:
480 memset(&slave, 0, sizeof(struct vme_slave));
481
482
483
484
485 retval = vme_slave_get(image[minor].resource,
486 &(slave.enable), &(slave.vme_addr),
487 &(slave.size), &pci_addr, &(slave.aspace),
488 &(slave.cycle));
489
490 copied = copy_to_user((char *)arg, &slave,
491 sizeof(struct vme_slave));
492 if (copied != 0) {
493 printk(KERN_WARNING "Partial copy to "
494 "userspace\n");
495 return -EFAULT;
496 }
497
498 return retval;
499 break;
500
501 case VME_SET_SLAVE:
502
503 copied = copy_from_user(&slave, (char *)arg,
504 sizeof(slave));
505 if (copied != 0) {
506 printk(KERN_WARNING "Partial copy from "
507 "userspace\n");
508 return -EFAULT;
509 }
510
511
512
513
514 return vme_slave_set(image[minor].resource,
515 slave.enable, slave.vme_addr, slave.size,
516 image[minor].pci_buf, slave.aspace,
517 slave.cycle);
518
519 break;
520 }
521 break;
522 }
523
524 return -EINVAL;
525}
526
527
528
529
530
531static void buf_unalloc (int num)
532{
533 if (image[num].kern_buf) {
534#ifdef VME_DEBUG
535 printk(KERN_DEBUG "UniverseII:Releasing buffer at %p\n",
536 image[num].pci_buf);
537#endif
538
539 vme_free_consistent(image[num].resource, image[num].size_buf,
540 image[num].kern_buf, image[num].pci_buf);
541
542 image[num].kern_buf = NULL;
543 image[num].pci_buf = 0;
544 image[num].size_buf = 0;
545
546#ifdef VME_DEBUG
547 } else {
548 printk(KERN_DEBUG "UniverseII: Buffer not allocated\n");
549#endif
550 }
551}
552
553static struct vme_driver vme_user_driver = {
554 .name = driver_name,
555 .probe = vme_user_probe,
556 .remove = vme_user_remove,
557};
558
559
560static int __init vme_user_init(void)
561{
562 int retval = 0;
563 int i;
564 struct vme_device_id *ids;
565
566 printk(KERN_INFO "VME User Space Access Driver\n");
567
568 if (bus_num == 0) {
569 printk(KERN_ERR "%s: No cards, skipping registration\n",
570 driver_name);
571 goto err_nocard;
572 }
573
574
575
576
577 if (bus_num > USER_BUS_MAX) {
578 printk(KERN_ERR "%s: Driver only able to handle %d PIO2 "
579 "Cards\n", driver_name, USER_BUS_MAX);
580 bus_num = USER_BUS_MAX;
581 }
582
583
584
585 ids = kmalloc(sizeof(struct vme_device_id) * (bus_num + 1), GFP_KERNEL);
586 if (ids == NULL) {
587 printk(KERN_ERR "%s: Unable to allocate ID table\n",
588 driver_name);
589 goto err_id;
590 }
591
592 memset(ids, 0, (sizeof(struct vme_device_id) * (bus_num + 1)));
593
594 for (i = 0; i < bus_num; i++) {
595 ids[i].bus = bus[i];
596
597
598
599
600
601 ids[i].slot = VME_SLOT_CURRENT;
602 }
603
604 vme_user_driver.bind_table = ids;
605
606 retval = vme_register_driver(&vme_user_driver);
607 if (retval != 0)
608 goto err_reg;
609
610 return retval;
611
612 vme_unregister_driver(&vme_user_driver);
613err_reg:
614 kfree(ids);
615err_id:
616err_nocard:
617 return retval;
618}
619
620
621
622
623
624
625static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
626{
627 int i, err;
628 char name[8];
629
630
631 if (vme_user_bridge != NULL) {
632 printk(KERN_ERR "%s: Driver can only be loaded for 1 device\n",
633 driver_name);
634 err = -EINVAL;
635 goto err_dev;
636 }
637 vme_user_bridge = dev;
638
639
640 for (i = 0; i < VME_DEVS; i++) {
641 image[i].kern_buf = NULL;
642 image[i].pci_buf = 0;
643 init_MUTEX(&(image[i].sem));
644 image[i].device = NULL;
645 image[i].resource = NULL;
646 image[i].users = 0;
647 }
648
649
650 reset_counters();
651
652
653 err = register_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS,
654 driver_name);
655 if (err) {
656 printk(KERN_WARNING "%s: Error getting Major Number %d for "
657 "driver.\n", driver_name, VME_MAJOR);
658 goto err_region;
659 }
660
661
662 vme_user_cdev = cdev_alloc();
663 vme_user_cdev->ops = &vme_user_fops;
664 vme_user_cdev->owner = THIS_MODULE;
665 err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS);
666 if (err) {
667 printk(KERN_WARNING "%s: cdev_all failed\n", driver_name);
668 goto err_char;
669 }
670
671
672 for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
673
674 image[i].resource = vme_slave_request(vme_user_bridge,
675 VME_A16, VME_SCT);
676 if (image[i].resource == NULL) {
677 printk(KERN_WARNING "Unable to allocate slave "
678 "resource\n");
679 goto err_slave;
680 }
681 image[i].size_buf = PCI_BUF_SIZE;
682 image[i].kern_buf = vme_alloc_consistent(image[i].resource,
683 image[i].size_buf, &(image[i].pci_buf));
684 if (image[i].kern_buf == NULL) {
685 printk(KERN_WARNING "Unable to allocate memory for "
686 "buffer\n");
687 image[i].pci_buf = 0;
688 vme_slave_free(image[i].resource);
689 err = -ENOMEM;
690 goto err_slave;
691 }
692 }
693
694
695
696
697
698 for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
699
700 image[i].resource = vme_master_request(vme_user_bridge,
701 VME_A32, VME_SCT, VME_D32);
702 if (image[i].resource == NULL) {
703 printk(KERN_WARNING "Unable to allocate master "
704 "resource\n");
705 goto err_master;
706 }
707 }
708
709
710 vme_user_sysfs_class = class_create(THIS_MODULE, driver_name);
711 if (IS_ERR(vme_user_sysfs_class)) {
712 printk(KERN_ERR "Error creating vme_user class.\n");
713 err = PTR_ERR(vme_user_sysfs_class);
714 goto err_class;
715 }
716
717
718 for (i=0; i<VME_DEVS; i++) {
719 switch (type[i]) {
720 case MASTER_MINOR:
721 sprintf(name,"bus/vme/m%%d");
722 break;
723 case CONTROL_MINOR:
724 sprintf(name,"bus/vme/ctl");
725 break;
726 case SLAVE_MINOR:
727 sprintf(name,"bus/vme/s%%d");
728 break;
729 default:
730 err = -EINVAL;
731 goto err_sysfs;
732 break;
733 }
734
735 image[i].device =
736 device_create(vme_user_sysfs_class, NULL,
737 MKDEV(VME_MAJOR, i), NULL, name,
738 (type[i] == SLAVE_MINOR)? i - (MASTER_MAX + 1) : i);
739 if (IS_ERR(image[i].device)) {
740 printk("%s: Error creating sysfs device\n",
741 driver_name);
742 err = PTR_ERR(image[i].device);
743 goto err_sysfs;
744 }
745 }
746
747 return 0;
748
749
750 i = VME_DEVS;
751err_sysfs:
752 while (i > 0){
753 i--;
754 device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
755 }
756 class_destroy(vme_user_sysfs_class);
757
758
759 i = MASTER_MAX + 1;
760err_master:
761 while (i > MASTER_MINOR) {
762 i--;
763 vme_master_free(image[i].resource);
764 }
765
766
767
768
769 i = SLAVE_MAX + 1;
770err_slave:
771 while (i > SLAVE_MINOR) {
772 i--;
773 vme_slave_free(image[i].resource);
774 buf_unalloc(i);
775 }
776err_class:
777 cdev_del(vme_user_cdev);
778err_char:
779 unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
780err_region:
781err_dev:
782 return err;
783}
784
785static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
786{
787 int i;
788
789
790 for(i=0; i<VME_DEVS; i++) {
791 device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
792 }
793 class_destroy(vme_user_sysfs_class);
794
795 for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
796 vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
797 vme_slave_free(image[i].resource);
798 buf_unalloc(i);
799 }
800
801
802 cdev_del(vme_user_cdev);
803
804
805 unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
806
807 return 0;
808}
809
810static void __exit vme_user_exit(void)
811{
812 vme_unregister_driver(&vme_user_driver);
813
814 kfree(vme_user_driver.bind_table);
815}
816
817
818MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected");
819module_param_array(bus, int, &bus_num, 0);
820
821MODULE_DESCRIPTION("VME User Space Access Driver");
822MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
823MODULE_LICENSE("GPL");
824
825module_init(vme_user_init);
826module_exit(vme_user_exit);
827