Commit | Line | Data |
---|---|---|
e184e2be | 1 | // SPDX-License-Identifier: GPL-2.0+ |
309231d7 HS |
2 | /* |
3 | * comedi_pcmcia.c | |
4 | * Comedi PCMCIA driver specific functions. | |
5 | * | |
6 | * COMEDI - Linux Control and Measurement Device Interface | |
7 | * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> | |
309231d7 HS |
8 | */ |
9 | ||
aae434b3 | 10 | #include <linux/module.h> |
309231d7 | 11 | #include <linux/kernel.h> |
df0e68c1 | 12 | #include <linux/comedi/comedi_pcmcia.h> |
309231d7 | 13 | |
1f021e1f | 14 | /** |
127a0cf9 IA |
15 | * comedi_to_pcmcia_dev() - Return PCMCIA device attached to COMEDI device |
16 | * @dev: COMEDI device. | |
17 | * | |
18 | * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
19 | * a &struct device embedded in a &struct pcmcia_device. | |
20 | * | |
21 | * Return: Attached PCMCIA device if @dev->hw_dev is non-%NULL. | |
22 | * Return %NULL if @dev->hw_dev is %NULL. | |
1f021e1f HS |
23 | */ |
24 | struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev) | |
25 | { | |
26 | return dev->hw_dev ? to_pcmcia_dev(dev->hw_dev) : NULL; | |
27 | } | |
28 | EXPORT_SYMBOL_GPL(comedi_to_pcmcia_dev); | |
29 | ||
ddb2d0a0 HS |
30 | static int comedi_pcmcia_conf_check(struct pcmcia_device *link, |
31 | void *priv_data) | |
32 | { | |
33 | if (link->config_index == 0) | |
34 | return -EINVAL; | |
35 | ||
36 | return pcmcia_request_io(link); | |
37 | } | |
38 | ||
39 | /** | |
127a0cf9 IA |
40 | * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device |
41 | * @dev: COMEDI device. | |
42 | * @conf_check: Optional callback to check each configuration option of the | |
43 | * PCMCIA device and request I/O regions. | |
44 | * | |
45 | * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a a | |
46 | * &struct device embedded in a &struct pcmcia_device. The comedi PCMCIA | |
47 | * driver needs to set the 'config_flags' member in the &struct pcmcia_device, | |
48 | * as appropriate for that driver, before calling this function in order to | |
49 | * allow pcmcia_loop_config() to do its internal autoconfiguration. | |
50 | * | |
51 | * If @conf_check is %NULL it is set to a default function. If is | |
52 | * passed to pcmcia_loop_config() and should return %0 if the configuration | |
53 | * is valid and I/O regions requested successfully, otherwise it should return | |
54 | * a negative error value. The default function returns -%EINVAL if the | |
55 | * 'config_index' member is %0, otherwise it calls pcmcia_request_io() and | |
56 | * returns the result. | |
57 | * | |
58 | * If the above configuration check passes, pcmcia_enable_device() is called | |
59 | * to set up and activate the PCMCIA device. | |
ddb2d0a0 | 60 | * |
127a0cf9 IA |
61 | * If this function returns an error, comedi_pcmcia_disable() should be called |
62 | * to release requested resources. | |
63 | * | |
64 | * Return: | |
65 | * 0 on success, | |
66 | * -%ENODEV id @dev->hw_dev is %NULL, | |
67 | * a negative error number from pcmcia_loop_config() if it fails, | |
68 | * or a negative error number from pcmcia_enable_device() if it fails. | |
ddb2d0a0 | 69 | */ |
a3ac9519 | 70 | int comedi_pcmcia_enable(struct comedi_device *dev, |
514871ef IA |
71 | int (*conf_check)(struct pcmcia_device *p_dev, |
72 | void *priv_data)) | |
ddb2d0a0 HS |
73 | { |
74 | struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); | |
75 | int ret; | |
76 | ||
77 | if (!link) | |
78 | return -ENODEV; | |
79 | ||
a3ac9519 HS |
80 | if (!conf_check) |
81 | conf_check = comedi_pcmcia_conf_check; | |
82 | ||
83 | ret = pcmcia_loop_config(link, conf_check, NULL); | |
ddb2d0a0 HS |
84 | if (ret) |
85 | return ret; | |
86 | ||
87 | return pcmcia_enable_device(link); | |
88 | } | |
89 | EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); | |
90 | ||
91 | /** | |
127a0cf9 IA |
92 | * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions |
93 | * @dev: COMEDI device. | |
94 | * | |
95 | * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
96 | * a &struct device embedded in a &struct pcmcia_device. Call | |
97 | * pcmcia_disable_device() to disable and clean up the PCMCIA device. | |
ddb2d0a0 HS |
98 | */ |
99 | void comedi_pcmcia_disable(struct comedi_device *dev) | |
100 | { | |
101 | struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); | |
102 | ||
103 | if (link) | |
104 | pcmcia_disable_device(link); | |
105 | } | |
106 | EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); | |
107 | ||
1f021e1f | 108 | /** |
127a0cf9 IA |
109 | * comedi_pcmcia_auto_config() - Configure/probe a PCMCIA COMEDI device |
110 | * @link: PCMCIA device. | |
111 | * @driver: Registered COMEDI driver. | |
112 | * | |
113 | * Typically called from the pcmcia_driver (*probe) function. Auto-configure | |
114 | * a COMEDI device, using a pointer to the &struct device embedded in *@link | |
115 | * as the hardware device. The @driver's "auto_attach" handler may call | |
116 | * comedi_to_pcmcia_dev() on the passed in COMEDI device to recover @link. | |
1f021e1f | 117 | * |
127a0cf9 IA |
118 | * Return: The result of calling comedi_auto_config() (0 on success, or a |
119 | * negative error number on failure). | |
1f021e1f HS |
120 | */ |
121 | int comedi_pcmcia_auto_config(struct pcmcia_device *link, | |
122 | struct comedi_driver *driver) | |
123 | { | |
124 | return comedi_auto_config(&link->dev, driver, 0); | |
125 | } | |
126 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); | |
127 | ||
128 | /** | |
127a0cf9 IA |
129 | * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a PCMCIA COMEDI device |
130 | * @link: PCMCIA device. | |
1f021e1f HS |
131 | * |
132 | * Typically called from the pcmcia_driver (*remove) function. | |
127a0cf9 IA |
133 | * Auto-unconfigure a COMEDI device attached to this PCMCIA device, using a |
134 | * pointer to the &struct device embedded in *@link as the hardware device. | |
135 | * The COMEDI driver's "detach" handler will be called during unconfiguration | |
136 | * of the COMEDI device. | |
137 | * | |
138 | * Note that the COMEDI device may have already been unconfigured using the | |
139 | * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it | |
140 | * again should be ignored. | |
1f021e1f HS |
141 | */ |
142 | void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) | |
143 | { | |
144 | comedi_auto_unconfig(&link->dev); | |
145 | } | |
146 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); | |
147 | ||
309231d7 | 148 | /** |
127a0cf9 IA |
149 | * comedi_pcmcia_driver_register() - Register a PCMCIA COMEDI driver |
150 | * @comedi_driver: COMEDI driver to be registered. | |
151 | * @pcmcia_driver: PCMCIA driver to be registered. | |
152 | * | |
153 | * This function is used for the module_init() of PCMCIA COMEDI driver modules | |
154 | * to register the COMEDI driver and the PCMCIA driver. Do not call it | |
155 | * directly, use the module_comedi_pcmcia_driver() helper macro instead. | |
309231d7 | 156 | * |
127a0cf9 | 157 | * Return: 0 on success, or a negative error number on failure. |
309231d7 HS |
158 | */ |
159 | int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, | |
160 | struct pcmcia_driver *pcmcia_driver) | |
161 | { | |
162 | int ret; | |
163 | ||
164 | ret = comedi_driver_register(comedi_driver); | |
165 | if (ret < 0) | |
166 | return ret; | |
167 | ||
168 | ret = pcmcia_register_driver(pcmcia_driver); | |
169 | if (ret < 0) { | |
170 | comedi_driver_unregister(comedi_driver); | |
171 | return ret; | |
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); | |
177 | ||
178 | /** | |
127a0cf9 IA |
179 | * comedi_pcmcia_driver_unregister() - Unregister a PCMCIA COMEDI driver |
180 | * @comedi_driver: COMEDI driver to be registered. | |
181 | * @pcmcia_driver: PCMCIA driver to be registered. | |
309231d7 | 182 | * |
127a0cf9 IA |
183 | * This function is called from the module_exit() of PCMCIA COMEDI driver |
184 | * modules to unregister the PCMCIA driver and the COMEDI driver. Do not call | |
185 | * it directly, use the module_comedi_pcmcia_driver() helper macro instead. | |
309231d7 HS |
186 | */ |
187 | void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, | |
188 | struct pcmcia_driver *pcmcia_driver) | |
189 | { | |
190 | pcmcia_unregister_driver(pcmcia_driver); | |
191 | comedi_driver_unregister(comedi_driver); | |
192 | } | |
193 | EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister); | |
aae434b3 IA |
194 | |
195 | static int __init comedi_pcmcia_init(void) | |
196 | { | |
197 | return 0; | |
198 | } | |
199 | module_init(comedi_pcmcia_init); | |
200 | ||
201 | static void __exit comedi_pcmcia_exit(void) | |
202 | { | |
203 | } | |
204 | module_exit(comedi_pcmcia_exit); | |
205 | ||
13d8b1f3 | 206 | MODULE_AUTHOR("https://www.comedi.org"); |
aae434b3 IA |
207 | MODULE_DESCRIPTION("Comedi PCMCIA interface module"); |
208 | MODULE_LICENSE("GPL"); |