diff options
33 files changed, 1160 insertions, 519 deletions
@@ -768,6 +768,7 @@ D: Z85230 driver D: Former security contact point (please use vendor-sec@lst.de) D: ex 2.2 maintainer D: 2.1.x modular sound +D: Assigned major/minor numbers maintainer at lanana.org S: c/o Red Hat UK Ltd S: Alexandra House S: Alexandra Terrace diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 87b4c5e82d39..4035eca87144 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -1,20 +1,17 @@ - LINUX ALLOCATED DEVICES (2.6+ version) - - Maintained by Alan Cox <device@lanana.org> - - Last revised: 6th April 2009 + LINUX ALLOCATED DEVICES (4.x+ version) This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating system. -The latest version of this list is available from -http://www.lanana.org/docs/device-list/ or -ftp://ftp.kernel.org/pub/linux/docs/device-list/. This version may be -newer than the one distributed with the Linux kernel. - -The LaTeX version of this document is no longer maintained. +The LaTeX version of this document is no longer maintained, nor is +the document that used to reside at lanana.org. This version in the +mainline Linux kernel is the master document. Updates shall be sent +as patches to the kernel maintainers (see the SubmittingPatches document). +Specifically explore the sections titled "CHAR and MISC DRIVERS", and +"BLOCK LAYER" in the MAINTAINERS file to find the right maintainers +to involve for character and block devices. This document is included by reference into the Filesystem Hierarchy Standard (FHS). The FHS is available from http://www.pathname.com/fhs/. @@ -23,60 +20,33 @@ Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on the Atari platform only. -The symbol {2.6} means the allocation is obsolete and scheduled for -removal once kernel version 2.6 (or equivalent) is released. Some of these -allocations have already been removed. - -This document is in the public domain. The author requests, however, +This document is in the public domain. The authors requests, however, that semantically altered versions are not distributed without -permission of the author, assuming the author can be contacted without +permission of the authors, assuming the authors can be contacted without an unreasonable effort. -In particular, please don't sent patches for this list to Linus, at -least not without contacting me first. - -I do not have any information about these devices beyond what appears -on this list. Any such information requests will be deleted without -reply. - **** DEVICE DRIVERS AUTHORS PLEASE READ THIS **** -To have a major number allocated, or a minor number in situations -where that applies (e.g. busmice), please contact me with the -appropriate device information. Also, if you have additional -information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. - -I do, however, make a few requests about the nature of your report. -This is necessary for me to be able to keep this list up to date and -correct in a timely manner. First of all, *please* send it to the -correct address... <device@lanana.org>. I receive hundreds of email -messages a day, so mail sent to other addresses may very well get lost -in the avalanche. Please put in a descriptive subject, so I can find -your mail again should I need to. Too many people send me email -saying just "device number request" in the subject. - -Second, please include a description of the device *in the same format -as this list*. The reason for this is that it is the only way I have -found to ensure I have all the requisite information to publish your -device and avoid conflicts. +Linux now has extensive support for dynamic allocation of device numbering +and can use sysfs and udev (systemd) to handle the naming needs. There are +still some exceptions in the serial and boot device area. Before asking +for a device number make sure you actually need one. -Third, please don't assume that the distributed version of the list is -up to date. Due to the number of registrations I have to maintain it -in "batch mode", so there is likely additional registrations that -haven't been listed yet. +To have a major number allocated, or a minor number in situations +where that applies (e.g. busmice), please submit a patch and send to +the authors as indicated above. -Fourth, remember that Linux now has extensive support for dynamic allocation -of device numbering and can use sysfs and udev to handle the naming needs. -There are still some exceptions in the serial and boot device area. Before -asking for a device number make sure you actually need one. +Keep the description of the device *in the same format +as this list*. The reason for this is that it is the only way we have +found to ensure we have all the requisite information to publish your +device and avoid conflicts. -Finally, sometimes I have to play "namespace police." Please don't be -offended. I often get submissions for /dev names that would be bound -to cause conflicts down the road. I am trying to avoid getting in a +Finally, sometimes we have to play "namespace police." Please don't be +offended. We often get submissions for /dev names that would be bound +to cause conflicts down the road. We are trying to avoid getting in a situation where we would have to suffer an incompatible forward -change. Therefore, please consult with me *before* you make your +change. Therefore, please consult with us *before* you make your device names and numbers in any way public, at least to the point where it would be at all difficult to get them changed. @@ -3099,9 +3069,9 @@ Your cooperation is appreciated. 129 = /dev/ipath_sma Device used by Subnet Management Agent 130 = /dev/ipath_diag Device used by diagnostics programs -234-239 UNASSIGNED - -240-254 char LOCAL/EXPERIMENTAL USE +234-254 char RESERVED FOR DYNAMIC ASSIGNMENT + Character devices that request a dynamic allocation of major number will + take numbers starting from 254 and downward. 240-254 block LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not diff --git a/Documentation/isa.txt b/Documentation/isa.txt new file mode 100644 index 000000000000..f232c26a40be --- /dev/null +++ b/Documentation/isa.txt @@ -0,0 +1,121 @@ +ISA Drivers +----------- + +The following text is adapted from the commit message of the initial +commit of the ISA bus driver authored by Rene Herman. + +During the recent "isa drivers using platform devices" discussion it was +pointed out that (ALSA) ISA drivers ran into the problem of not having +the option to fail driver load (device registration rather) upon not +finding their hardware due to a probe() error not being passed up +through the driver model. In the course of that, I suggested a separate +ISA bus might be best; Russell King agreed and suggested this bus could +use the .match() method for the actual device discovery. + +The attached does this. For this old non (generically) discoverable ISA +hardware only the driver itself can do discovery so as a difference with +the platform_bus, this isa_bus also distributes match() up to the +driver. + +As another difference: these devices only exist in the driver model due +to the driver creating them because it might want to drive them, meaning +that all device creation has been made internal as well. + +The usage model this provides is nice, and has been acked from the ALSA +side by Takashi Iwai and Jaroslav Kysela. The ALSA driver module_init's +now (for oldisa-only drivers) become: + +static int __init alsa_card_foo_init(void) +{ + return isa_register_driver(&snd_foo_isa_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_foo_exit(void) +{ + isa_unregister_driver(&snd_foo_isa_driver); +} + +Quite like the other bus models therefore. This removes a lot of +duplicated init code from the ALSA ISA drivers. + +The passed in isa_driver struct is the regular driver struct embedding a +struct device_driver, the normal probe/remove/shutdown/suspend/resume +callbacks, and as indicated that .match callback. + +The "SNDRV_CARDS" you see being passed in is a "unsigned int ndev" +parameter, indicating how many devices to create and call our methods +with. + +The platform_driver callbacks are called with a platform_device param; +the isa_driver callbacks are being called with a "struct device *dev, +unsigned int id" pair directly -- with the device creation completely +internal to the bus it's much cleaner to not leak isa_dev's by passing +them in at all. The id is the only thing we ever want other then the +struct device * anyways, and it makes for nicer code in the callbacks as +well. + +With this additional .match() callback ISA drivers have all options. If +ALSA would want to keep the old non-load behaviour, it could stick all +of the old .probe in .match, which would only keep them registered after +everything was found to be present and accounted for. If it wanted the +behaviour of always loading as it inadvertently did for a bit after the +changeover to platform devices, it could just not provide a .match() and +do everything in .probe() as before. + +If it, as Takashi Iwai already suggested earlier as a way of following +the model from saner buses more closely, wants to load when a later bind +could conceivably succeed, it could use .match() for the prerequisites +(such as checking the user wants the card enabled and that port/irq/dma +values have been passed in) and .probe() for everything else. This is +the nicest model. + +To the code... + +This exports only two functions; isa_{,un}register_driver(). + +isa_register_driver() register's the struct device_driver, and then +loops over the passed in ndev creating devices and registering them. +This causes the bus match method to be called for them, which is: + +int isa_bus_match(struct device *dev, struct device_driver *driver) +{ + struct isa_driver *isa_driver = to_isa_driver(driver); + + if (dev->platform_data == isa_driver) { + if (!isa_driver->match || + isa_driver->match(dev, to_isa_dev(dev)->id)) + return 1; + dev->platform_data = NULL; + } + return 0; +} + +The first thing this does is check if this device is in fact one of this +driver's devices by seeing if the device's platform_data pointer is set +to this driver. Platform devices compare strings, but we don't need to +do that with everything being internal, so isa_register_driver() abuses +dev->platform_data as a isa_driver pointer which we can then check here. +I believe platform_data is available for this, but if rather not, moving +the isa_driver pointer to the private struct isa_dev is ofcourse fine as +well. + +Then, if the the driver did not provide a .match, it matches. If it did, +the driver match() method is called to determine a match. + +If it did _not_ match, dev->platform_data is reset to indicate this to +isa_register_driver which can then unregister the device again. + +If during all this, there's any error, or no devices matched at all +everything is backed out again and the error, or -ENODEV, is returned. + +isa_unregister_driver() just unregisters the matched devices and the +driver itself. + +module_isa_driver is a helper macro for ISA drivers which do not do +anything special in module init/exit. This eliminates a lot of +boilerplate code. Each module may only use this macro once, and calling +it replaces module_init and module_exit. + +max_num_isa_dev is a macro to determine the maximum possible number of +ISA devices which may be registered in the I/O port address space given +the address extent of the ISA devices. diff --git a/MAINTAINERS b/MAINTAINERS index 3dc5d894713b..5504c0de47ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6067,6 +6067,13 @@ F: include/linux/irqdomain.h F: kernel/irq/irqdomain.c F: kernel/irq/msi.c +ISA +M: William Breathitt Gray <vilhelm.gray@gmail.com> +S: Maintained +F: Documentation/isa.txt +F: drivers/base/isa.c +F: include/linux/isa.h + ISAPNP M: Jaroslav Kysela <perex@perex.cz> S: Maintained diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ace79d2da2c3..15f827678843 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2445,8 +2445,6 @@ config ISA_DMA_API Enables ISA-style DMA support for devices requiring such controllers. If unsure, say Y. -if X86_32 - config ISA bool "ISA support" ---help--- @@ -2456,6 +2454,8 @@ config ISA (MCA) or VESA. ISA is an older system, now being displaced by PCI; newer boards don't support it. If you have ISA, say Y, otherwise N. +if X86_32 + config EISA bool "EISA support" depends on ISA diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 1bd120a0b084..240374fd1838 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -4,6 +4,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -41,12 +42,12 @@ static bool devcd_disabled; struct devcd_entry { struct device devcd_dev; - const void *data; + void *data; size_t datalen; struct module *owner; ssize_t (*read)(char *buffer, loff_t offset, size_t count, - const void *data, size_t datalen); - void (*free)(const void *data); + void *data, size_t datalen); + void (*free)(void *data); struct delayed_work del_wk; struct device *failing_dev; }; @@ -174,7 +175,7 @@ static struct class devcd_class = { }; static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, - const void *data, size_t datalen) + void *data, size_t datalen) { if (offset > datalen) return -EINVAL; @@ -188,6 +189,11 @@ static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, return count; } +static void devcd_freev(void *data) +{ + vfree(data); +} + /** * dev_coredumpv - create device coredump with vmalloc data * @dev: the struct device for the crashed device @@ -198,10 +204,10 @@ static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, * This function takes ownership of the vmalloc'ed data and will free * it when it is no longer used. See dev_coredumpm() for more information. */ -void dev_coredumpv(struct device *dev, const void *data, size_t datalen, +void dev_coredumpv(struct device *dev, void *data, size_t datalen, gfp_t gfp) { - dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, vfree); + dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev); } EXPORT_SYMBOL_GPL(dev_coredumpv); @@ -213,6 +219,44 @@ static int devcd_match_failing(struct device *dev, const void *failing) } /** + * devcd_free_sgtable - free all the memory of the given scatterlist table + * (i.e. both pages and scatterlist instances) + * NOTE: if two tables allocated with devcd_alloc_sgtable and then chained + * using the sg_chain function then that function should be called only once + * on the chained table + * @table: pointer to sg_table to free + */ +static void devcd_free_sgtable(void *data) +{ + _devcd_free_sgtable(data); +} + +/** + * devcd_read_from_table - copy data from sg_table to a given buffer + * and return the number of bytes read + * @buffer: the buffer to copy the data to it + * @buf_len: the length of the buffer + * @data: the scatterlist table to copy from + * @offset: start copy from @offset@ bytes from the head of the data + * in the given scatterlist + * @data_len: the length of the data in the sg_table + */ +static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, + size_t buf_len, void *data, + size_t data_len) +{ + struct scatterlist *table = data; + + if (offset > data_len) + return -EINVAL; + + if (offset + buf_len > data_len) + buf_len = data_len - offset; + return sg_pcopy_to_buffer(table, sg_nents(table), buffer, buf_len, + offset); +} + +/** * dev_coredumpm - create device coredump with read/free methods * @dev: the struct device for the crashed device * @owner: the module that contains the read/free functions, use %THIS_MODULE @@ -228,10 +272,10 @@ static int devcd_match_failing(struct device *dev, const void *failing) * function will be called to free the data. */ void dev_coredumpm(struct device *dev, struct module *owner, - const void *data, size_t datalen, gfp_t gfp, + void *data, size_t datalen, gfp_t gfp, ssize_t (*read)(char *buffer, loff_t offset, size_t count, - const void *data, size_t datalen), - void (*free)(const void *data)) + void *data, size_t datalen), + void (*free)(void *data)) { static atomic_t devcd_count = ATOMIC_INIT(0); struct devcd_entry *devcd; @@ -291,6 +335,27 @@ void dev_coredumpm(struct device *dev, struct module *owner, } EXPORT_SYMBOL_GPL(dev_coredumpm); +/** + * dev_coredumpmsg - create device coredump that uses scatterlist as data + * parameter + * @dev: the struct device for the crashed device + * @table: the dump data + * @datalen: length of the data + * @gfp: allocation flags + * + * Creates a new device coredump for the given device. If a previous one hasn't + * been read yet, the new coredump is discarded. The data lifetime is determined + * by the device coredump framework and when it is no longer needed + * it will free the data. + */ +void dev_coredumpsg(struct device *dev, struct scatterlist *table, + size_t datalen, gfp_t gfp) +{ + dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable, + devcd_free_sgtable); +} +EXPORT_SYMBOL_GPL(dev_coredumpsg); + static int __init devcoredump_init(void) { return class_register(&devcd_class); diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 1b95475b6aef..0e2011636fbb 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -125,9 +125,7 @@ static void fw_cfg_io_cleanup(void) # define FW_CFG_CTRL_OFF 0x00 # define FW_CFG_DATA_OFF 0x01 # else -# warning "QEMU FW_CFG may not be available on this architecture!" -# define FW_CFG_CTRL_OFF 0x00 -# define FW_CFG_DATA_OFF 0x01 +# error "QEMU FW_CFG not available on this architecture!" # endif #endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d00e7b67be9a..48da857f4774 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -530,30 +530,35 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" + depends on ISA select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-DIO-48E family. The base port - address for the device may be configured via the dio_48e_base module - parameter. The interrupt line number for the device may be configured - via the dio_48e_irq module parameter. + Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, + 104-DIO-24E). The base port addresses for the devices may be + configured via the base module parameter. The interrupt line numbers + for the devices may be configured via the irq module parameter. config GPIO_104_IDIO_16 tristate "ACCES 104-IDIO-16 GPIO support" + depends on ISA select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-IDIO-16 family. The base port - address for the device may be set via the idio_16_base module - parameter. The interrupt line number for the device may be set via the - idio_16_irq module parameter. + Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, + 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, 104-IDO-8). The + base port addresses for the devices may be configured via the base + module parameter. The interrupt line numbers for the devices may be + configured via the irq module parameter. config GPIO_104_IDI_48 tristate "ACCES 104-IDI-48 GPIO support" + depends on ISA select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-IDI-48 family. The base port - address for the device may be configured via the idi_48_base module - parameter. The interrupt line number for the device may be configured - via the idi_48_irq module parameter. + Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, + 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for + the devices may be configured via the base module parameter. The + interrupt line numbers for the devices may be configured via the irq + module parameter. config GPIO_F7188X tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support" @@ -622,12 +627,13 @@ config GPIO_TS5500 config GPIO_WS16C48 tristate "WinSystems WS16C48 GPIO support" + depends on ISA select GPIOLIB_IRQCHIP help - Enables GPIO support for the WinSystems WS16C48. The base port address - for the device may be configured via the ws16c48_base module - parameter. The interrupt line number for the device may be configured - via the ws16c48_irq module parameter. + Enables GPIO support for the WinSystems WS16C48. The base port + addresses for the devices may be configured via the base module + parameter. The interrupt line numbers for the devices may be + configured via the irq module parameter. endmenu diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 448a903089ef..1a647c07be67 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -1,5 +1,5 @@ /* - * GPIO driver for the ACCES 104-DIO-48E + * GPIO driver for the ACCES 104-DIO-48E series * Copyright (C) 2016 William Breathitt Gray * * This program is free software; you can redistribute it and/or modify @@ -10,6 +10,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. + * + * This driver supports the following ACCES devices: 104-DIO-48E and + * 104-DIO-24E. */ #include <linux/bitops.h> #include <linux/device.h> @@ -19,18 +22,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned dio_48e_base; -module_param(dio_48e_base, uint, 0); -MODULE_PARM_DESC(dio_48e_base, "ACCES 104-DIO-48E base address"); -static unsigned dio_48e_irq; -module_param(dio_48e_irq, uint, 0); -MODULE_PARM_DESC(dio_48e_irq, "ACCES 104-DIO-48E interrupt line number"); +#define DIO48E_EXTENT 16 +#define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) + +static unsigned int base[MAX_NUM_DIO48E]; +static unsigned int num_dio48e; +module_param_array(base, uint, &num_dio48e, 0); +MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses"); + +static unsigned int irq[MAX_NUM_DIO48E]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); /** * struct dio48e_gpio - GPIO device private data structure @@ -294,23 +302,19 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init dio48e_probe(struct platform_device *pdev) +static int dio48e_probe(struct device *dev, unsigned int id) { - struct device *dev = &pdev->dev; struct dio48e_gpio *dio48egpio; - const unsigned base = dio_48e_base; - const unsigned extent = 16; const char *const name = dev_name(dev); int err; - const unsigned irq = dio_48e_irq; dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); if (!dio48egpio) return -ENOMEM; - if (!devm_request_region(dev, base, extent, name)) { + if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base, base + extent); + base[id], base[id] + DIO48E_EXTENT); return -EBUSY; } @@ -324,8 +328,8 @@ static int __init dio48e_probe(struct platform_device *pdev) dio48egpio->chip.direction_output = dio48e_gpio_direction_output; dio48egpio->chip.get = dio48e_gpio_get; dio48egpio->chip.set = dio48e_gpio_set; - dio48egpio->base = base; - dio48egpio->irq = irq; + dio48egpio->base = base[id]; + dio48egpio->irq = irq[id]; spin_lock_init(&dio48egpio->lock); @@ -338,19 +342,19 @@ static int __init dio48e_probe(struct platform_device *pdev) } /* initialize all GPIO as output */ - outb(0x80, base + 3); - outb(0x00, base); - outb(0x00, base + 1); - outb(0x00, base + 2); - outb(0x00, base + 3); - outb(0x80, base + 7); - outb(0x00, base + 4); - outb(0x00, base + 5); - outb(0x00, base + 6); - outb(0x00, base + 7); + outb(0x80, base[id] + 3); + outb(0x00, base[id]); + outb(0x00, base[id] + 1); + outb(0x00, base[id] + 2); + outb(0x00, base[id] + 3); + outb(0x80, base[id] + 7); + outb(0x00, base[id] + 4); + outb(0x00, base[id] + 5); + outb(0x00, base[id] + 6); + outb(0x00, base[id] + 7); /* disable IRQ by default */ - inb(base + 0xB); + inb(base[id] + 0xB); err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -359,7 +363,7 @@ static int __init dio48e_probe(struct platform_device *pdev) goto err_gpiochip_remove; } - err = request_irq(irq, dio48e_irq_handler, 0, name, dio48egpio); + err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); goto err_gpiochip_remove; @@ -372,9 +376,9 @@ err_gpiochip_remove: return err; } -static int dio48e_remove(struct platform_device *pdev) +static int dio48e_remove(struct device *dev, unsigned int id) { - struct dio48e_gpio *const dio48egpio = platform_get_drvdata(pdev); + struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev); free_irq(dio48egpio->irq, dio48egpio); gpiochip_remove(&dio48egpio->chip); @@ -382,48 +386,14 @@ static int dio48e_remove(struct platform_device *pdev) return 0; } -static struct platform_device *dio48e_device; - -static struct platform_driver dio48e_driver = { +static struct isa_driver dio48e_driver = { + .probe = dio48e_probe, .driver = { .name = "104-dio-48e" }, .remove = dio48e_remove }; - -static void __exit dio48e_exit(void) -{ - platform_device_unregister(dio48e_device); - platform_driver_unregister(&dio48e_driver); -} - -static int __init dio48e_init(void) -{ - int err; - - dio48e_device = platform_device_alloc(dio48e_driver.driver.name, -1); - if (!dio48e_device) - return -ENOMEM; - - err = platform_device_add(dio48e_device); - if (err) - goto err_platform_device; - - err = platform_driver_probe(&dio48e_driver, dio48e_probe); - if (err) - goto err_platform_driver; - - return 0; - -err_platform_driver: - platform_device_del(dio48e_device); -err_platform_device: - platform_device_put(dio48e_device); - return err; -} - -module_init(dio48e_init); -module_exit(dio48e_exit); +module_isa_driver(dio48e_driver, num_dio48e); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver"); diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index e37cd4cdda35..6c75c83baf5a 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -10,6 +10,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. + * + * This driver supports the following ACCES devices: 104-IDI-48A, + * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ #include <linux/bitops.h> #include <linux/device.h> @@ -19,18 +22,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned idi_48_base; -module_param(idi_48_base, uint, 0); -MODULE_PARM_DESC(idi_48_base, "ACCES 104-IDI-48 base address"); -static unsigned idi_48_irq; -module_param(idi_48_irq, uint, 0); -MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number"); +#define IDI_48_EXTENT 8 +#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) + +static unsigned int base[MAX_NUM_IDI_48]; +static unsigned int num_idi_48; +module_param_array(base, uint, &num_idi_48, 0); +MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses"); + +static unsigned int irq[MAX_NUM_IDI_48]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); /** * struct idi_48_gpio - GPIO device private data structure @@ -211,23 +219,19 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -st |