18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
28ffdff6aSGreg Kroah-Hartman /*
38ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia.c
48ffdff6aSGreg Kroah-Hartman  * Comedi PCMCIA driver specific functions.
58ffdff6aSGreg Kroah-Hartman  *
68ffdff6aSGreg Kroah-Hartman  * COMEDI - Linux Control and Measurement Device Interface
78ffdff6aSGreg Kroah-Hartman  * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
88ffdff6aSGreg Kroah-Hartman  */
98ffdff6aSGreg Kroah-Hartman 
108ffdff6aSGreg Kroah-Hartman #include <linux/module.h>
118ffdff6aSGreg Kroah-Hartman #include <linux/kernel.h>
12*df0e68c1SIan Abbott #include <linux/comedi/comedi_pcmcia.h>
138ffdff6aSGreg Kroah-Hartman 
148ffdff6aSGreg Kroah-Hartman /**
158ffdff6aSGreg Kroah-Hartman  * comedi_to_pcmcia_dev() - Return PCMCIA device attached to COMEDI device
168ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
178ffdff6aSGreg Kroah-Hartman  *
188ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a
198ffdff6aSGreg Kroah-Hartman  * a &struct device embedded in a &struct pcmcia_device.
208ffdff6aSGreg Kroah-Hartman  *
218ffdff6aSGreg Kroah-Hartman  * Return: Attached PCMCIA device if @dev->hw_dev is non-%NULL.
228ffdff6aSGreg Kroah-Hartman  * Return %NULL if @dev->hw_dev is %NULL.
238ffdff6aSGreg Kroah-Hartman  */
comedi_to_pcmcia_dev(struct comedi_device * dev)248ffdff6aSGreg Kroah-Hartman struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev)
258ffdff6aSGreg Kroah-Hartman {
268ffdff6aSGreg Kroah-Hartman 	return dev->hw_dev ? to_pcmcia_dev(dev->hw_dev) : NULL;
278ffdff6aSGreg Kroah-Hartman }
288ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_to_pcmcia_dev);
298ffdff6aSGreg Kroah-Hartman 
comedi_pcmcia_conf_check(struct pcmcia_device * link,void * priv_data)308ffdff6aSGreg Kroah-Hartman static int comedi_pcmcia_conf_check(struct pcmcia_device *link,
318ffdff6aSGreg Kroah-Hartman 				    void *priv_data)
328ffdff6aSGreg Kroah-Hartman {
338ffdff6aSGreg Kroah-Hartman 	if (link->config_index == 0)
348ffdff6aSGreg Kroah-Hartman 		return -EINVAL;
358ffdff6aSGreg Kroah-Hartman 
368ffdff6aSGreg Kroah-Hartman 	return pcmcia_request_io(link);
378ffdff6aSGreg Kroah-Hartman }
388ffdff6aSGreg Kroah-Hartman 
398ffdff6aSGreg Kroah-Hartman /**
408ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device
418ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
428ffdff6aSGreg Kroah-Hartman  * @conf_check: Optional callback to check each configuration option of the
438ffdff6aSGreg Kroah-Hartman  *	PCMCIA device and request I/O regions.
448ffdff6aSGreg Kroah-Hartman  *
458ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a a
468ffdff6aSGreg Kroah-Hartman  * &struct device embedded in a &struct pcmcia_device.  The comedi PCMCIA
478ffdff6aSGreg Kroah-Hartman  * driver needs to set the 'config_flags' member in the &struct pcmcia_device,
488ffdff6aSGreg Kroah-Hartman  * as appropriate for that driver, before calling this function in order to
498ffdff6aSGreg Kroah-Hartman  * allow pcmcia_loop_config() to do its internal autoconfiguration.
508ffdff6aSGreg Kroah-Hartman  *
518ffdff6aSGreg Kroah-Hartman  * If @conf_check is %NULL it is set to a default function.  If is
528ffdff6aSGreg Kroah-Hartman  * passed to pcmcia_loop_config() and should return %0 if the configuration
538ffdff6aSGreg Kroah-Hartman  * is valid and I/O regions requested successfully, otherwise it should return
548ffdff6aSGreg Kroah-Hartman  * a negative error value.  The default function returns -%EINVAL if the
558ffdff6aSGreg Kroah-Hartman  * 'config_index' member is %0, otherwise it calls pcmcia_request_io() and
568ffdff6aSGreg Kroah-Hartman  * returns the result.
578ffdff6aSGreg Kroah-Hartman  *
588ffdff6aSGreg Kroah-Hartman  * If the above configuration check passes, pcmcia_enable_device() is called
598ffdff6aSGreg Kroah-Hartman  * to set up and activate the PCMCIA device.
608ffdff6aSGreg Kroah-Hartman  *
618ffdff6aSGreg Kroah-Hartman  * If this function returns an error, comedi_pcmcia_disable() should be called
628ffdff6aSGreg Kroah-Hartman  * to release requested resources.
638ffdff6aSGreg Kroah-Hartman  *
648ffdff6aSGreg Kroah-Hartman  * Return:
658ffdff6aSGreg Kroah-Hartman  *	0 on success,
668ffdff6aSGreg Kroah-Hartman  *	-%ENODEV id @dev->hw_dev is %NULL,
678ffdff6aSGreg Kroah-Hartman  *	a negative error number from pcmcia_loop_config() if it fails,
688ffdff6aSGreg Kroah-Hartman  *	or a negative error number from pcmcia_enable_device() if it fails.
698ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_enable(struct comedi_device * dev,int (* conf_check)(struct pcmcia_device * p_dev,void * priv_data))708ffdff6aSGreg Kroah-Hartman int comedi_pcmcia_enable(struct comedi_device *dev,
718ffdff6aSGreg Kroah-Hartman 			 int (*conf_check)(struct pcmcia_device *p_dev,
728ffdff6aSGreg Kroah-Hartman 					   void *priv_data))
738ffdff6aSGreg Kroah-Hartman {
748ffdff6aSGreg Kroah-Hartman 	struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
758ffdff6aSGreg Kroah-Hartman 	int ret;
768ffdff6aSGreg Kroah-Hartman 
778ffdff6aSGreg Kroah-Hartman 	if (!link)
788ffdff6aSGreg Kroah-Hartman 		return -ENODEV;
798ffdff6aSGreg Kroah-Hartman 
808ffdff6aSGreg Kroah-Hartman 	if (!conf_check)
818ffdff6aSGreg Kroah-Hartman 		conf_check = comedi_pcmcia_conf_check;
828ffdff6aSGreg Kroah-Hartman 
838ffdff6aSGreg Kroah-Hartman 	ret = pcmcia_loop_config(link, conf_check, NULL);
848ffdff6aSGreg Kroah-Hartman 	if (ret)
858ffdff6aSGreg Kroah-Hartman 		return ret;
868ffdff6aSGreg Kroah-Hartman 
878ffdff6aSGreg Kroah-Hartman 	return pcmcia_enable_device(link);
888ffdff6aSGreg Kroah-Hartman }
898ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_enable);
908ffdff6aSGreg Kroah-Hartman 
918ffdff6aSGreg Kroah-Hartman /**
928ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions
938ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
948ffdff6aSGreg Kroah-Hartman  *
958ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a
968ffdff6aSGreg Kroah-Hartman  * a &struct device embedded in a &struct pcmcia_device.  Call
978ffdff6aSGreg Kroah-Hartman  * pcmcia_disable_device() to disable and clean up the PCMCIA device.
988ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_disable(struct comedi_device * dev)998ffdff6aSGreg Kroah-Hartman void comedi_pcmcia_disable(struct comedi_device *dev)
1008ffdff6aSGreg Kroah-Hartman {
1018ffdff6aSGreg Kroah-Hartman 	struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
1028ffdff6aSGreg Kroah-Hartman 
1038ffdff6aSGreg Kroah-Hartman 	if (link)
1048ffdff6aSGreg Kroah-Hartman 		pcmcia_disable_device(link);
1058ffdff6aSGreg Kroah-Hartman }
1068ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_disable);
1078ffdff6aSGreg Kroah-Hartman 
1088ffdff6aSGreg Kroah-Hartman /**
1098ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_auto_config() - Configure/probe a PCMCIA COMEDI device
1108ffdff6aSGreg Kroah-Hartman  * @link: PCMCIA device.
1118ffdff6aSGreg Kroah-Hartman  * @driver: Registered COMEDI driver.
1128ffdff6aSGreg Kroah-Hartman  *
1138ffdff6aSGreg Kroah-Hartman  * Typically called from the pcmcia_driver (*probe) function.  Auto-configure
1148ffdff6aSGreg Kroah-Hartman  * a COMEDI device, using a pointer to the &struct device embedded in *@link
1158ffdff6aSGreg Kroah-Hartman  * as the hardware device.  The @driver's "auto_attach" handler may call
1168ffdff6aSGreg Kroah-Hartman  * comedi_to_pcmcia_dev() on the passed in COMEDI device to recover @link.
1178ffdff6aSGreg Kroah-Hartman  *
1188ffdff6aSGreg Kroah-Hartman  * Return: The result of calling comedi_auto_config() (0 on success, or a
1198ffdff6aSGreg Kroah-Hartman  * negative error number on failure).
1208ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_auto_config(struct pcmcia_device * link,struct comedi_driver * driver)1218ffdff6aSGreg Kroah-Hartman int comedi_pcmcia_auto_config(struct pcmcia_device *link,
1228ffdff6aSGreg Kroah-Hartman 			      struct comedi_driver *driver)
1238ffdff6aSGreg Kroah-Hartman {
1248ffdff6aSGreg Kroah-Hartman 	return comedi_auto_config(&link->dev, driver, 0);
1258ffdff6aSGreg Kroah-Hartman }
1268ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config);
1278ffdff6aSGreg Kroah-Hartman 
1288ffdff6aSGreg Kroah-Hartman /**
1298ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a PCMCIA COMEDI device
1308ffdff6aSGreg Kroah-Hartman  * @link: PCMCIA device.
1318ffdff6aSGreg Kroah-Hartman  *
1328ffdff6aSGreg Kroah-Hartman  * Typically called from the pcmcia_driver (*remove) function.
1338ffdff6aSGreg Kroah-Hartman  * Auto-unconfigure a COMEDI device attached to this PCMCIA device, using a
1348ffdff6aSGreg Kroah-Hartman  * pointer to the &struct device embedded in *@link as the hardware device.
1358ffdff6aSGreg Kroah-Hartman  * The COMEDI driver's "detach" handler will be called during unconfiguration
1368ffdff6aSGreg Kroah-Hartman  * of the COMEDI device.
1378ffdff6aSGreg Kroah-Hartman  *
1388ffdff6aSGreg Kroah-Hartman  * Note that the COMEDI device may have already been unconfigured using the
1398ffdff6aSGreg Kroah-Hartman  * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it
1408ffdff6aSGreg Kroah-Hartman  * again should be ignored.
1418ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_auto_unconfig(struct pcmcia_device * link)1428ffdff6aSGreg Kroah-Hartman void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link)
1438ffdff6aSGreg Kroah-Hartman {
1448ffdff6aSGreg Kroah-Hartman 	comedi_auto_unconfig(&link->dev);
1458ffdff6aSGreg Kroah-Hartman }
1468ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig);
1478ffdff6aSGreg Kroah-Hartman 
1488ffdff6aSGreg Kroah-Hartman /**
1498ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_driver_register() - Register a PCMCIA COMEDI driver
1508ffdff6aSGreg Kroah-Hartman  * @comedi_driver: COMEDI driver to be registered.
1518ffdff6aSGreg Kroah-Hartman  * @pcmcia_driver: PCMCIA driver to be registered.
1528ffdff6aSGreg Kroah-Hartman  *
1538ffdff6aSGreg Kroah-Hartman  * This function is used for the module_init() of PCMCIA COMEDI driver modules
1548ffdff6aSGreg Kroah-Hartman  * to register the COMEDI driver and the PCMCIA driver.  Do not call it
1558ffdff6aSGreg Kroah-Hartman  * directly, use the module_comedi_pcmcia_driver() helper macro instead.
1568ffdff6aSGreg Kroah-Hartman  *
1578ffdff6aSGreg Kroah-Hartman  * Return: 0 on success, or a negative error number on failure.
1588ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_driver_register(struct comedi_driver * comedi_driver,struct pcmcia_driver * pcmcia_driver)1598ffdff6aSGreg Kroah-Hartman int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver,
1608ffdff6aSGreg Kroah-Hartman 				  struct pcmcia_driver *pcmcia_driver)
1618ffdff6aSGreg Kroah-Hartman {
1628ffdff6aSGreg Kroah-Hartman 	int ret;
1638ffdff6aSGreg Kroah-Hartman 
1648ffdff6aSGreg Kroah-Hartman 	ret = comedi_driver_register(comedi_driver);
1658ffdff6aSGreg Kroah-Hartman 	if (ret < 0)
1668ffdff6aSGreg Kroah-Hartman 		return ret;
1678ffdff6aSGreg Kroah-Hartman 
1688ffdff6aSGreg Kroah-Hartman 	ret = pcmcia_register_driver(pcmcia_driver);
1698ffdff6aSGreg Kroah-Hartman 	if (ret < 0) {
1708ffdff6aSGreg Kroah-Hartman 		comedi_driver_unregister(comedi_driver);
1718ffdff6aSGreg Kroah-Hartman 		return ret;
1728ffdff6aSGreg Kroah-Hartman 	}
1738ffdff6aSGreg Kroah-Hartman 
1748ffdff6aSGreg Kroah-Hartman 	return 0;
1758ffdff6aSGreg Kroah-Hartman }
1768ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register);
1778ffdff6aSGreg Kroah-Hartman 
1788ffdff6aSGreg Kroah-Hartman /**
1798ffdff6aSGreg Kroah-Hartman  * comedi_pcmcia_driver_unregister() - Unregister a PCMCIA COMEDI driver
1808ffdff6aSGreg Kroah-Hartman  * @comedi_driver: COMEDI driver to be registered.
1818ffdff6aSGreg Kroah-Hartman  * @pcmcia_driver: PCMCIA driver to be registered.
1828ffdff6aSGreg Kroah-Hartman  *
1838ffdff6aSGreg Kroah-Hartman  * This function is called from the module_exit() of PCMCIA COMEDI driver
1848ffdff6aSGreg Kroah-Hartman  * modules to unregister the PCMCIA driver and the COMEDI driver.  Do not call
1858ffdff6aSGreg Kroah-Hartman  * it directly, use the module_comedi_pcmcia_driver() helper macro instead.
1868ffdff6aSGreg Kroah-Hartman  */
comedi_pcmcia_driver_unregister(struct comedi_driver * comedi_driver,struct pcmcia_driver * pcmcia_driver)1878ffdff6aSGreg Kroah-Hartman void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver,
1888ffdff6aSGreg Kroah-Hartman 				     struct pcmcia_driver *pcmcia_driver)
1898ffdff6aSGreg Kroah-Hartman {
1908ffdff6aSGreg Kroah-Hartman 	pcmcia_unregister_driver(pcmcia_driver);
1918ffdff6aSGreg Kroah-Hartman 	comedi_driver_unregister(comedi_driver);
1928ffdff6aSGreg Kroah-Hartman }
1938ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister);
1948ffdff6aSGreg Kroah-Hartman 
comedi_pcmcia_init(void)1958ffdff6aSGreg Kroah-Hartman static int __init comedi_pcmcia_init(void)
1968ffdff6aSGreg Kroah-Hartman {
1978ffdff6aSGreg Kroah-Hartman 	return 0;
1988ffdff6aSGreg Kroah-Hartman }
1998ffdff6aSGreg Kroah-Hartman module_init(comedi_pcmcia_init);
2008ffdff6aSGreg Kroah-Hartman 
comedi_pcmcia_exit(void)2018ffdff6aSGreg Kroah-Hartman static void __exit comedi_pcmcia_exit(void)
2028ffdff6aSGreg Kroah-Hartman {
2038ffdff6aSGreg Kroah-Hartman }
2048ffdff6aSGreg Kroah-Hartman module_exit(comedi_pcmcia_exit);
2058ffdff6aSGreg Kroah-Hartman 
2068ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("https://www.comedi.org");
2078ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi PCMCIA interface module");
2088ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL");
209