1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * comedi/drivers/8255.c |
4 | * Driver for 8255 |
5 | * |
6 | * COMEDI - Linux Control and Measurement Device Interface |
7 | * Copyright (C) 1998 David A. Schleef <ds@schleef.org> |
8 | */ |
9 | |
10 | /* |
11 | * Driver: 8255 |
12 | * Description: generic 8255 support |
13 | * Devices: [standard] 8255 (8255) |
14 | * Author: ds |
15 | * Status: works |
16 | * Updated: Fri, 7 Jun 2002 12:56:45 -0700 |
17 | * |
18 | * The classic in digital I/O. The 8255 appears in Comedi as a single |
19 | * digital I/O subdevice with 24 channels. The channel 0 corresponds |
20 | * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit |
21 | * 7. Direction configuration is done in blocks, with channels 0-7, |
22 | * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode |
23 | * supported is mode 0. |
24 | * |
25 | * You should enable compilation this driver if you plan to use a board |
26 | * that has an 8255 chip. For multifunction boards, the main driver will |
27 | * configure the 8255 subdevice automatically. |
28 | * |
29 | * This driver also works independently with ISA and PCI cards that |
30 | * directly map the 8255 registers to I/O ports, including cards with |
31 | * multiple 8255 chips. To configure the driver for such a card, the |
32 | * option list should be a list of the I/O port bases for each of the |
33 | * 8255 chips. For example, |
34 | * |
35 | * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c |
36 | * |
37 | * Note that most PCI 8255 boards do NOT work with this driver, and |
38 | * need a separate driver as a wrapper. For those that do work, the |
39 | * I/O port base address can be found in the output of 'lspci -v'. |
40 | */ |
41 | |
42 | #include <linux/module.h> |
43 | #include <linux/comedi/comedidev.h> |
44 | #include <linux/comedi/comedi_8255.h> |
45 | |
46 | static int dev_8255_attach(struct comedi_device *dev, |
47 | struct comedi_devconfig *it) |
48 | { |
49 | struct comedi_subdevice *s; |
50 | unsigned long iobase; |
51 | int ret; |
52 | int i; |
53 | |
54 | for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) { |
55 | iobase = it->options[i]; |
56 | if (!iobase) |
57 | break; |
58 | } |
59 | if (i == 0) { |
60 | dev_warn(dev->class_dev, "no devices specified\n" ); |
61 | return -EINVAL; |
62 | } |
63 | |
64 | ret = comedi_alloc_subdevices(dev, num_subdevices: i); |
65 | if (ret) |
66 | return ret; |
67 | |
68 | for (i = 0; i < dev->n_subdevices; i++) { |
69 | s = &dev->subdevices[i]; |
70 | iobase = it->options[i]; |
71 | |
72 | /* |
73 | * __comedi_request_region() does not set dev->iobase. |
74 | * |
75 | * For 8255 devices that are manually attached using |
76 | * comedi_config, the 'iobase' is the actual I/O port |
77 | * base address of the chip. |
78 | */ |
79 | ret = __comedi_request_region(dev, start: iobase, I8255_SIZE); |
80 | if (ret) { |
81 | s->type = COMEDI_SUBD_UNUSED; |
82 | } else { |
83 | ret = subdev_8255_io_init(dev, s, regbase: iobase); |
84 | if (ret) { |
85 | /* |
86 | * Release the I/O port region here, as the |
87 | * "detach" handler cannot find it. |
88 | */ |
89 | release_region(iobase, I8255_SIZE); |
90 | s->type = COMEDI_SUBD_UNUSED; |
91 | return ret; |
92 | } |
93 | } |
94 | } |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static void dev_8255_detach(struct comedi_device *dev) |
100 | { |
101 | struct comedi_subdevice *s; |
102 | int i; |
103 | |
104 | for (i = 0; i < dev->n_subdevices; i++) { |
105 | s = &dev->subdevices[i]; |
106 | if (s->type != COMEDI_SUBD_UNUSED) { |
107 | unsigned long regbase = subdev_8255_regbase(s); |
108 | |
109 | release_region(regbase, I8255_SIZE); |
110 | } |
111 | } |
112 | } |
113 | |
114 | static struct comedi_driver dev_8255_driver = { |
115 | .driver_name = "8255" , |
116 | .module = THIS_MODULE, |
117 | .attach = dev_8255_attach, |
118 | .detach = dev_8255_detach, |
119 | }; |
120 | module_comedi_driver(dev_8255_driver); |
121 | |
122 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
123 | MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices" ); |
124 | MODULE_LICENSE("GPL" ); |
125 | |