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 "../comedidev.h" 29 30 #include "8255.h" 31 32 struct pcl724_board { 33 const char *name; 34 unsigned int io_range; 35 unsigned int can_have96:1; 36 unsigned int is_pet48:1; 37 int numofports; 38 }; 39 40 static const struct pcl724_board boardtypes[] = { 41 { 42 .name = "pcl724", 43 .io_range = 0x04, 44 .numofports = 1, /* 24 DIO channels */ 45 }, { 46 .name = "pcl722", 47 .io_range = 0x20, 48 .can_have96 = 1, 49 .numofports = 6, /* 144 (or 96) DIO channels */ 50 }, { 51 .name = "pcl731", 52 .io_range = 0x08, 53 .numofports = 2, /* 48 DIO channels */ 54 }, { 55 .name = "acl7122", 56 .io_range = 0x20, 57 .can_have96 = 1, 58 .numofports = 6, /* 144 (or 96) DIO channels */ 59 }, { 60 .name = "acl7124", 61 .io_range = 0x04, 62 .numofports = 1, /* 24 DIO channels */ 63 }, { 64 .name = "pet48dio", 65 .io_range = 0x02, 66 .is_pet48 = 1, 67 .numofports = 2, /* 48 DIO channels */ 68 }, { 69 .name = "pcmio48", 70 .io_range = 0x08, 71 .numofports = 2, /* 48 DIO channels */ 72 }, { 73 .name = "onyx-mm-dio", 74 .io_range = 0x10, 75 .numofports = 2, /* 48 DIO channels */ 76 }, 77 }; 78 79 static int pcl724_8255mapped_io(struct comedi_device *dev, 80 int dir, int port, int data, 81 unsigned long iobase) 82 { 83 int movport = I8255_SIZE * (iobase >> 12); 84 85 iobase &= 0x0fff; 86 87 outb(port + movport, iobase); 88 if (dir) { 89 outb(data, iobase + 1); 90 return 0; 91 } 92 return inb(iobase + 1); 93 } 94 95 static int pcl724_attach(struct comedi_device *dev, 96 struct comedi_devconfig *it) 97 { 98 const struct pcl724_board *board = dev->board_ptr; 99 struct comedi_subdevice *s; 100 unsigned long iobase; 101 unsigned int iorange; 102 int n_subdevices; 103 int ret; 104 int i; 105 106 iorange = board->io_range; 107 n_subdevices = board->numofports; 108 109 /* Handle PCL-724 in 96 DIO configuration */ 110 if (board->can_have96 && 111 (it->options[2] == 1 || it->options[2] == 96)) { 112 iorange = 0x10; 113 n_subdevices = 4; 114 } 115 116 ret = comedi_request_region(dev, it->options[0], iorange); 117 if (ret) 118 return ret; 119 120 ret = comedi_alloc_subdevices(dev, n_subdevices); 121 if (ret) 122 return ret; 123 124 for (i = 0; i < dev->n_subdevices; i++) { 125 s = &dev->subdevices[i]; 126 if (board->is_pet48) { 127 iobase = dev->iobase + (i * 0x1000); 128 ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, 129 iobase); 130 } else { 131 ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE); 132 } 133 if (ret) 134 return ret; 135 } 136 137 return 0; 138 } 139 140 static struct comedi_driver pcl724_driver = { 141 .driver_name = "pcl724", 142 .module = THIS_MODULE, 143 .attach = pcl724_attach, 144 .detach = comedi_legacy_detach, 145 .board_name = &boardtypes[0].name, 146 .num_names = ARRAY_SIZE(boardtypes), 147 .offset = sizeof(struct pcl724_board), 148 }; 149 module_comedi_driver(pcl724_driver); 150 151 MODULE_AUTHOR("Comedi https://www.comedi.org"); 152 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards"); 153 MODULE_LICENSE("GPL"); 154