1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * pcl724.c 4 * Comedi driver for 8255 based ISA and PC/104 DIO boards 5 * 6 * Michal Dobes <dobes@tesnet.cz> 7 */ 8 9 /* 10 * Driver: pcl724 11 * Description: Comedi driver for 8255 based ISA DIO boards 12 * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731), 13 * [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio), 14 * [WinSystems] PCM-IO48 (pcmio48), 15 * [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio) 16 * Author: Michal Dobes <dobes@tesnet.cz> 17 * Status: untested 18 * 19 * Configuration options: 20 * [0] - IO Base 21 * [1] - IRQ (not supported) 22 * [2] - number of DIO (pcl722 and acl7122 boards) 23 * 0, 144: 144 DIO configuration 24 * 1, 96: 96 DIO configuration 25 */ 26 27 #include <linux/module.h> 28 #include <linux/comedi/comedidev.h> 29 #include <linux/comedi/comedi_8255.h> 30 31 struct pcl724_board { 32 const char *name; 33 unsigned int io_range; 34 unsigned int can_have96:1; 35 unsigned int is_pet48:1; 36 int numofports; 37 }; 38 39 static const struct pcl724_board boardtypes[] = { 40 { 41 .name = "pcl724", 42 .io_range = 0x04, 43 .numofports = 1, /* 24 DIO channels */ 44 }, { 45 .name = "pcl722", 46 .io_range = 0x20, 47 .can_have96 = 1, 48 .numofports = 6, /* 144 (or 96) DIO channels */ 49 }, { 50 .name = "pcl731", 51 .io_range = 0x08, 52 .numofports = 2, /* 48 DIO channels */ 53 }, { 54 .name = "acl7122", 55 .io_range = 0x20, 56 .can_have96 = 1, 57 .numofports = 6, /* 144 (or 96) DIO channels */ 58 }, { 59 .name = "acl7124", 60 .io_range = 0x04, 61 .numofports = 1, /* 24 DIO channels */ 62 }, { 63 .name = "pet48dio", 64 .io_range = 0x02, 65 .is_pet48 = 1, 66 .numofports = 2, /* 48 DIO channels */ 67 }, { 68 .name = "pcmio48", 69 .io_range = 0x08, 70 .numofports = 2, /* 48 DIO channels */ 71 }, { 72 .name = "onyx-mm-dio", 73 .io_range = 0x10, 74 .numofports = 2, /* 48 DIO channels */ 75 }, 76 }; 77 78 static int pcl724_8255mapped_io(struct comedi_device *dev, 79 int dir, int port, int data, 80 unsigned long iobase) 81 { 82 int movport = I8255_SIZE * (iobase >> 12); 83 84 iobase &= 0x0fff; 85 86 outb(port + movport, iobase); 87 if (dir) { 88 outb(data, iobase + 1); 89 return 0; 90 } 91 return inb(iobase + 1); 92 } 93 94 static int pcl724_attach(struct comedi_device *dev, 95 struct comedi_devconfig *it) 96 { 97 const struct pcl724_board *board = dev->board_ptr; 98 struct comedi_subdevice *s; 99 unsigned long iobase; 100 unsigned int iorange; 101 int n_subdevices; 102 int ret; 103 int i; 104 105 iorange = board->io_range; 106 n_subdevices = board->numofports; 107 108 /* Handle PCL-724 in 96 DIO configuration */ 109 if (board->can_have96 && 110 (it->options[2] == 1 || it->options[2] == 96)) { 111 iorange = 0x10; 112 n_subdevices = 4; 113 } 114 115 ret = comedi_request_region(dev, it->options[0], iorange); 116 if (ret) 117 return ret; 118 119 ret = comedi_alloc_subdevices(dev, n_subdevices); 120 if (ret) 121 return ret; 122 123 for (i = 0; i < dev->n_subdevices; i++) { 124 s = &dev->subdevices[i]; 125 if (board->is_pet48) { 126 iobase = dev->iobase + (i * 0x1000); 127 ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, 128 iobase); 129 } else { 130 ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); 131 } 132 if (ret) 133 return ret; 134 } 135 136 return 0; 137 } 138 139 static struct comedi_driver pcl724_driver = { 140 .driver_name = "pcl724", 141 .module = THIS_MODULE, 142 .attach = pcl724_attach, 143 .detach = comedi_legacy_detach, 144 .board_name = &boardtypes[0].name, 145 .num_names = ARRAY_SIZE(boardtypes), 146 .offset = sizeof(struct pcl724_board), 147 }; 148 module_comedi_driver(pcl724_driver); 149 150 MODULE_AUTHOR("Comedi https://www.comedi.org"); 151 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards"); 152 MODULE_LICENSE("GPL"); 153