1 | // SPDX-License-Identifier: GPL-2.0+ |
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> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/comedi/comedi_pcmcia.h> |
13 | |
14 | /** |
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. |
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 | |
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(p_dev: link); |
37 | } |
38 | |
39 | /** |
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. |
60 | * |
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. |
69 | */ |
70 | int comedi_pcmcia_enable(struct comedi_device *dev, |
71 | int (*conf_check)(struct pcmcia_device *p_dev, |
72 | void *priv_data)) |
73 | { |
74 | struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); |
75 | int ret; |
76 | |
77 | if (!link) |
78 | return -ENODEV; |
79 | |
80 | if (!conf_check) |
81 | conf_check = comedi_pcmcia_conf_check; |
82 | |
83 | ret = pcmcia_loop_config(p_dev: link, conf_check, NULL); |
84 | if (ret) |
85 | return ret; |
86 | |
87 | return pcmcia_enable_device(p_dev: link); |
88 | } |
89 | EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); |
90 | |
91 | /** |
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. |
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(p_dev: link); |
105 | } |
106 | EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); |
107 | |
108 | /** |
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. |
117 | * |
118 | * Return: The result of calling comedi_auto_config() (0 on success, or a |
119 | * negative error number on failure). |
120 | */ |
121 | int comedi_pcmcia_auto_config(struct pcmcia_device *link, |
122 | struct comedi_driver *driver) |
123 | { |
124 | return comedi_auto_config(hardware_device: &link->dev, driver, context: 0); |
125 | } |
126 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); |
127 | |
128 | /** |
129 | * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a PCMCIA COMEDI device |
130 | * @link: PCMCIA device. |
131 | * |
132 | * Typically called from the pcmcia_driver (*remove) function. |
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. |
141 | */ |
142 | void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) |
143 | { |
144 | comedi_auto_unconfig(hardware_device: &link->dev); |
145 | } |
146 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); |
147 | |
148 | /** |
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. |
156 | * |
157 | * Return: 0 on success, or a negative error number on failure. |
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(driver: comedi_driver); |
165 | if (ret < 0) |
166 | return ret; |
167 | |
168 | ret = pcmcia_register_driver(driver: pcmcia_driver); |
169 | if (ret < 0) { |
170 | comedi_driver_unregister(driver: comedi_driver); |
171 | return ret; |
172 | } |
173 | |
174 | return 0; |
175 | } |
176 | EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); |
177 | |
178 | /** |
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. |
182 | * |
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. |
186 | */ |
187 | void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, |
188 | struct pcmcia_driver *pcmcia_driver) |
189 | { |
190 | pcmcia_unregister_driver(driver: pcmcia_driver); |
191 | comedi_driver_unregister(driver: comedi_driver); |
192 | } |
193 | EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister); |
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 | |
206 | MODULE_AUTHOR("https://www.comedi.org" ); |
207 | MODULE_DESCRIPTION("Comedi PCMCIA interface module" ); |
208 | MODULE_LICENSE("GPL" ); |
209 | |