diff -ruN drvGPIOIITK.orig/BB-GPIOIITK.dts drvGPIOIITK/BB-GPIOIITK.dts --- drvGPIOIITK.orig/BB-GPIOIITK.dts 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/BB-GPIOIITK.dts 2020-11-26 04:44:40.316988000 +0100 @@ -0,0 +1,43 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include + +/ { + compatible = "ti,am335x-bone-black"; + + /* identification */ + part-number = "BB-GPIOIITK"; + version = "00A0"; + + fragment@0 { + target = <&am33xx_pinmux>; + __overlay__ { + input_pins: pinmux-input-pins { + pinctrl-single,pins = < + /* P8_08 (T7) gpio2_3 */ + AM33XX_IOPAD(0x0894, PIN_INPUT | MUX_MODE7) + + /* P8_10 (U6) gpio2_4 */ + AM33XX_IOPAD(0x0898, PIN_INPUT | MUX_MODE7) + >; + }; + }; + }; + + fragment@1 { + target-path="/"; + __overlay__ { + gpio_int_test { + pinctrl-names = "default"; + pinctrl-0 = <&input_pins>; + compatible = "gpioiitk"; + + input-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>, + <&gpio2 4 GPIO_ACTIVE_HIGH>; + }; + }; + }; +}; diff -ruN drvGPIOIITK.orig/Makefile drvGPIOIITK/Makefile --- drvGPIOIITK.orig/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/Makefile 2020-11-26 04:44:40.316685000 +0100 @@ -0,0 +1,4 @@ +KMOD= gpioiitk +SRCS= gpioiitk.c + +.include diff -ruN drvGPIOIITK.orig/bus_if.h drvGPIOIITK/bus_if.h --- drvGPIOIITK.orig/bus_if.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/bus_if.h 2020-11-26 04:44:40.316737000 +0100 @@ -0,0 +1,1255 @@ +/* + * This file is @generated automatically. + * Do not modify anything in here by hand. + * + * Created from source file + * /usr/src/sys/kern/bus_if.m + * with + * makeobjops.awk + * + * See the source file for legal information + */ + +/** + * @defgroup BUS bus - KObj methods for drivers of devices with children + * @brief A set of methods required device drivers that support + * child devices. + * @{ + */ + +#ifndef _bus_if_h_ +#define _bus_if_h_ + +/** @brief Unique descriptor for the BUS_PRINT_CHILD() method */ +extern struct kobjop_desc bus_print_child_desc; +/** @brief A function implementing the BUS_PRINT_CHILD() method */ +typedef int bus_print_child_t(device_t _dev, device_t _child); +/** + * @brief Print a description of a child device + * + * This is called from system code which prints out a description of a + * device. It should describe the attachment that the child has with + * the parent. For instance the TurboLaser bus prints which node the + * device is attached to. See bus_generic_print_child() for more + * information. + * + * @param _dev the device whose child is being printed + * @param _child the child device to describe + * + * @returns the number of characters output. + */ + +static __inline int BUS_PRINT_CHILD(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_print_child); + rc = ((bus_print_child_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_PROBE_NOMATCH() method */ +extern struct kobjop_desc bus_probe_nomatch_desc; +/** @brief A function implementing the BUS_PROBE_NOMATCH() method */ +typedef void bus_probe_nomatch_t(device_t _dev, device_t _child); +/** + * @brief Print a notification about an unprobed child device. + * + * Called for each child device that did not succeed in probing for a + * driver. + * + * @param _dev the device whose child was being probed + * @param _child the child device which failed to probe + */ + +static __inline void BUS_PROBE_NOMATCH(device_t _dev, device_t _child) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_probe_nomatch); + ((bus_probe_nomatch_t *) _m)(_dev, _child); +} + +/** @brief Unique descriptor for the BUS_READ_IVAR() method */ +extern struct kobjop_desc bus_read_ivar_desc; +/** @brief A function implementing the BUS_READ_IVAR() method */ +typedef int bus_read_ivar_t(device_t _dev, device_t _child, int _index, + uintptr_t *_result); +/** + * @brief Read the value of a bus-specific attribute of a device + * + * This method, along with BUS_WRITE_IVAR() manages a bus-specific set + * of instance variables of a child device. The intention is that + * each different type of bus defines a set of appropriate instance + * variables (such as ports and irqs for ISA bus etc.) + * + * This information could be given to the child device as a struct but + * that makes it hard for a bus to add or remove variables without + * forcing an edit and recompile for all drivers which may not be + * possible for vendor supplied binary drivers. + * + * This method copies the value of an instance variable to the + * location specified by @p *_result. + * + * @param _dev the device whose child was being examined + * @param _child the child device whose instance variable is + * being read + * @param _index the instance variable to read + * @param _result a location to receive the instance variable + * value + * + * @retval 0 success + * @retval ENOENT no such instance variable is supported by @p + * _dev + */ + +static __inline int BUS_READ_IVAR(device_t _dev, device_t _child, int _index, + uintptr_t *_result) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_read_ivar); + rc = ((bus_read_ivar_t *) _m)(_dev, _child, _index, _result); + return (rc); +} + +/** @brief Unique descriptor for the BUS_WRITE_IVAR() method */ +extern struct kobjop_desc bus_write_ivar_desc; +/** @brief A function implementing the BUS_WRITE_IVAR() method */ +typedef int bus_write_ivar_t(device_t _dev, device_t _child, int _indx, + uintptr_t _value); +/** + * @brief Write the value of a bus-specific attribute of a device + * + * This method sets the value of an instance variable to @p _value. + * + * @param _dev the device whose child was being updated + * @param _child the child device whose instance variable is + * being written + * @param _index the instance variable to write + * @param _value the value to write to that instance variable + * + * @retval 0 success + * @retval ENOENT no such instance variable is supported by @p + * _dev + * @retval EINVAL the instance variable was recognised but + * contains a read-only value + */ + +static __inline int BUS_WRITE_IVAR(device_t _dev, device_t _child, int _indx, + uintptr_t _value) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_write_ivar); + rc = ((bus_write_ivar_t *) _m)(_dev, _child, _indx, _value); + return (rc); +} + +/** @brief Unique descriptor for the BUS_CHILD_DELETED() method */ +extern struct kobjop_desc bus_child_deleted_desc; +/** @brief A function implementing the BUS_CHILD_DELETED() method */ +typedef void bus_child_deleted_t(device_t _dev, device_t _child); +/** + * @brief Notify a bus that a child was deleted + * + * Called at the beginning of device_delete_child() to allow the parent + * to teardown any bus-specific state for the child. + * + * @param _dev the device whose child is being deleted + * @param _child the child device which is being deleted + */ + +static __inline void BUS_CHILD_DELETED(device_t _dev, device_t _child) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_child_deleted); + ((bus_child_deleted_t *) _m)(_dev, _child); +} + +/** @brief Unique descriptor for the BUS_CHILD_DETACHED() method */ +extern struct kobjop_desc bus_child_detached_desc; +/** @brief A function implementing the BUS_CHILD_DETACHED() method */ +typedef void bus_child_detached_t(device_t _dev, device_t _child); +/** + * @brief Notify a bus that a child was detached + * + * Called after the child's DEVICE_DETACH() method to allow the parent + * to reclaim any resources allocated on behalf of the child. + * + * @param _dev the device whose child changed state + * @param _child the child device which changed state + */ + +static __inline void BUS_CHILD_DETACHED(device_t _dev, device_t _child) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_child_detached); + ((bus_child_detached_t *) _m)(_dev, _child); +} + +/** @brief Unique descriptor for the BUS_DRIVER_ADDED() method */ +extern struct kobjop_desc bus_driver_added_desc; +/** @brief A function implementing the BUS_DRIVER_ADDED() method */ +typedef void bus_driver_added_t(device_t _dev, driver_t *_driver); +/** + * @brief Notify a bus that a new driver was added + * + * Called when a new driver is added to the devclass which owns this + * bus. The generic implementation of this method attempts to probe and + * attach any un-matched children of the bus. + * + * @param _dev the device whose devclass had a new driver + * added to it + * @param _driver the new driver which was added + */ + +static __inline void BUS_DRIVER_ADDED(device_t _dev, driver_t *_driver) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_driver_added); + ((bus_driver_added_t *) _m)(_dev, _driver); +} + +/** @brief Unique descriptor for the BUS_ADD_CHILD() method */ +extern struct kobjop_desc bus_add_child_desc; +/** @brief A function implementing the BUS_ADD_CHILD() method */ +typedef device_t bus_add_child_t(device_t _dev, u_int _order, const char *_name, + int _unit); +/** + * @brief Create a new child device + * + * For buses which use use drivers supporting DEVICE_IDENTIFY() to + * enumerate their devices, this method is used to create new + * device instances. The new device will be added after the last + * existing child with the same order. Implementations of bus_add_child + * call device_add_child_ordered to add the child and often add + * a suitable ivar to the device specific to that bus. + * + * @param _dev the bus device which will be the parent of the + * new child device + * @param _order a value which is used to partially sort the + * children of @p _dev - devices created using + * lower values of @p _order appear first in @p + * _dev's list of children + * @param _name devclass name for new device or @c NULL if not + * specified + * @param _unit unit number for new device or @c -1 if not + * specified + */ + +static __inline device_t BUS_ADD_CHILD(device_t _dev, u_int _order, + const char *_name, int _unit) +{ + kobjop_t _m; + device_t rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_add_child); + rc = ((bus_add_child_t *) _m)(_dev, _order, _name, _unit); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESCAN() method */ +extern struct kobjop_desc bus_rescan_desc; +/** @brief A function implementing the BUS_RESCAN() method */ +typedef int bus_rescan_t(device_t _dev); +/** + * @brief Rescan the bus + * + * This method is called by a parent bridge or devctl to trigger a bus + * rescan. The rescan should delete devices no longer present and + * enumerate devices that have newly arrived. + * + * @param _dev the bus device + */ + +static __inline int BUS_RESCAN(device_t _dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_rescan); + rc = ((bus_rescan_t *) _m)(_dev); + return (rc); +} + +/** @brief Unique descriptor for the BUS_ALLOC_RESOURCE() method */ +extern struct kobjop_desc bus_alloc_resource_desc; +/** @brief A function implementing the BUS_ALLOC_RESOURCE() method */ +typedef struct resource * bus_alloc_resource_t(device_t _dev, device_t _child, + int _type, int *_rid, + rman_res_t _start, + rman_res_t _end, + rman_res_t _count, u_int _flags); +/** + * @brief Allocate a system resource + * + * This method is called by child devices of a bus to allocate resources. + * The types are defined in ; the meaning of the + * resource-ID field varies from bus to bus (but @p *rid == 0 is always + * valid if the resource type is). If a resource was allocated and the + * caller did not use the RF_ACTIVE to specify that it should be + * activated immediately, the caller is responsible for calling + * BUS_ACTIVATE_RESOURCE() when it actually uses the resource. + * + * @param _dev the parent device of @p _child + * @param _child the device which is requesting an allocation + * @param _type the type of resource to allocate + * @param _rid a pointer to the resource identifier + * @param _start hint at the start of the resource range - pass + * @c 0 for any start address + * @param _end hint at the end of the resource range - pass + * @c ~0 for any end address + * @param _count hint at the size of range required - pass @c 1 + * for any size + * @param _flags any extra flags to control the resource + * allocation - see @c RF_XXX flags in + * for details + * + * @returns the resource which was allocated or @c NULL if no + * resource could be allocated + */ + +static __inline struct resource * BUS_ALLOC_RESOURCE(device_t _dev, + device_t _child, int _type, + int *_rid, + rman_res_t _start, + rman_res_t _end, + rman_res_t _count, + u_int _flags) +{ + kobjop_t _m; + struct resource * rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_alloc_resource); + rc = ((bus_alloc_resource_t *) _m)(_dev, _child, _type, _rid, _start, _end, _count, _flags); + return (rc); +} + +/** @brief Unique descriptor for the BUS_ACTIVATE_RESOURCE() method */ +extern struct kobjop_desc bus_activate_resource_desc; +/** @brief A function implementing the BUS_ACTIVATE_RESOURCE() method */ +typedef int bus_activate_resource_t(device_t _dev, device_t _child, int _type, + int _rid, struct resource *_r); +/** + * @brief Activate a resource + * + * Activate a resource previously allocated with + * BUS_ALLOC_RESOURCE(). This may enable decoding of this resource in a + * device for instance. It will also establish a mapping for the resource + * unless RF_UNMAPPED was set when allocating the resource. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _rid the resource identifier + * @param _r the resource to activate + */ + +static __inline int BUS_ACTIVATE_RESOURCE(device_t _dev, device_t _child, + int _type, int _rid, + struct resource *_r) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_activate_resource); + rc = ((bus_activate_resource_t *) _m)(_dev, _child, _type, _rid, _r); + return (rc); +} + +/** @brief Unique descriptor for the BUS_MAP_RESOURCE() method */ +extern struct kobjop_desc bus_map_resource_desc; +/** @brief A function implementing the BUS_MAP_RESOURCE() method */ +typedef int bus_map_resource_t(device_t _dev, device_t _child, int _type, + struct resource *_r, + struct resource_map_request *_args, + struct resource_map *_map); +/** + * @brief Map a resource + * + * Allocate a mapping for a range of an active resource. The mapping + * is described by a struct resource_map object. This may for instance + * map a memory region into the kernel's virtual address space. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _r the resource to map + * @param _args optional attributes of the mapping + * @param _map the mapping + */ + +static __inline int BUS_MAP_RESOURCE(device_t _dev, device_t _child, int _type, + struct resource *_r, + struct resource_map_request *_args, + struct resource_map *_map) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_map_resource); + rc = ((bus_map_resource_t *) _m)(_dev, _child, _type, _r, _args, _map); + return (rc); +} + +/** @brief Unique descriptor for the BUS_UNMAP_RESOURCE() method */ +extern struct kobjop_desc bus_unmap_resource_desc; +/** @brief A function implementing the BUS_UNMAP_RESOURCE() method */ +typedef int bus_unmap_resource_t(device_t _dev, device_t _child, int _type, + struct resource *_r, + struct resource_map *_map); +/** + * @brief Unmap a resource + * + * Release a mapping previously allocated with + * BUS_MAP_RESOURCE(). This may for instance unmap a memory region + * from the kernel's virtual address space. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _r the resource + * @param _map the mapping to release + */ + +static __inline int BUS_UNMAP_RESOURCE(device_t _dev, device_t _child, + int _type, struct resource *_r, + struct resource_map *_map) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_unmap_resource); + rc = ((bus_unmap_resource_t *) _m)(_dev, _child, _type, _r, _map); + return (rc); +} + +/** @brief Unique descriptor for the BUS_DEACTIVATE_RESOURCE() method */ +extern struct kobjop_desc bus_deactivate_resource_desc; +/** @brief A function implementing the BUS_DEACTIVATE_RESOURCE() method */ +typedef int bus_deactivate_resource_t(device_t _dev, device_t _child, int _type, + int _rid, struct resource *_r); +/** + * @brief Deactivate a resource + * + * Deactivate a resource previously allocated with + * BUS_ALLOC_RESOURCE(). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _rid the resource identifier + * @param _r the resource to deactivate + */ + +static __inline int BUS_DEACTIVATE_RESOURCE(device_t _dev, device_t _child, + int _type, int _rid, + struct resource *_r) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_deactivate_resource); + rc = ((bus_deactivate_resource_t *) _m)(_dev, _child, _type, _rid, _r); + return (rc); +} + +/** @brief Unique descriptor for the BUS_ADJUST_RESOURCE() method */ +extern struct kobjop_desc bus_adjust_resource_desc; +/** @brief A function implementing the BUS_ADJUST_RESOURCE() method */ +typedef int bus_adjust_resource_t(device_t _dev, device_t _child, int _type, + struct resource *_res, rman_res_t _start, + rman_res_t _end); +/** + * @brief Adjust a resource + * + * Adjust the start and/or end of a resource allocated by + * BUS_ALLOC_RESOURCE. At least part of the new address range must overlap + * with the existing address range. If the successful, the resource's range + * will be adjusted to [start, end] on return. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _res the resource to adjust + * @param _start the new starting address of the resource range + * @param _end the new ending address of the resource range + */ + +static __inline int BUS_ADJUST_RESOURCE(device_t _dev, device_t _child, + int _type, struct resource *_res, + rman_res_t _start, rman_res_t _end) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_adjust_resource); + rc = ((bus_adjust_resource_t *) _m)(_dev, _child, _type, _res, _start, _end); + return (rc); +} + +/** @brief Unique descriptor for the BUS_TRANSLATE_RESOURCE() method */ +extern struct kobjop_desc bus_translate_resource_desc; +/** @brief A function implementing the BUS_TRANSLATE_RESOURCE() method */ +typedef int bus_translate_resource_t(device_t _dev, int _type, + rman_res_t _start, rman_res_t *_newstart); +/** + * @brief translate a resource value + * + * + * @param _dev the device associated with the resource + * @param _type the type of resource + * @param _start the starting address of the resource range + * @param _newstart the new starting address of the resource range + */ + +static __inline int BUS_TRANSLATE_RESOURCE(device_t _dev, int _type, + rman_res_t _start, + rman_res_t *_newstart) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_translate_resource); + rc = ((bus_translate_resource_t *) _m)(_dev, _type, _start, _newstart); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RELEASE_RESOURCE() method */ +extern struct kobjop_desc bus_release_resource_desc; +/** @brief A function implementing the BUS_RELEASE_RESOURCE() method */ +typedef int bus_release_resource_t(device_t _dev, device_t _child, int _type, + int _rid, struct resource *_res); +/** + * @brief Release a resource + * + * Free a resource allocated by the BUS_ALLOC_RESOURCE. The @p _rid + * value must be the same as the one returned by BUS_ALLOC_RESOURCE() + * (which is not necessarily the same as the one the client passed). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _rid the resource identifier + * @param _r the resource to release + */ + +static __inline int BUS_RELEASE_RESOURCE(device_t _dev, device_t _child, + int _type, int _rid, + struct resource *_res) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_release_resource); + rc = ((bus_release_resource_t *) _m)(_dev, _child, _type, _rid, _res); + return (rc); +} + +/** @brief Unique descriptor for the BUS_SETUP_INTR() method */ +extern struct kobjop_desc bus_setup_intr_desc; +/** @brief A function implementing the BUS_SETUP_INTR() method */ +typedef int bus_setup_intr_t(device_t _dev, device_t _child, + struct resource *_irq, int _flags, + driver_filter_t *_filter, driver_intr_t *_intr, + void *_arg, void **_cookiep); +/** + * @brief Install an interrupt handler + * + * This method is used to associate an interrupt handler function with + * an irq resource. When the interrupt triggers, the function @p _intr + * will be called with the value of @p _arg as its single + * argument. The value returned in @p *_cookiep is used to cancel the + * interrupt handler - the caller should save this value to use in a + * future call to BUS_TEARDOWN_INTR(). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + * @param _flags a set of bits from enum intr_type specifying + * the class of interrupt + * @param _intr the function to call when the interrupt + * triggers + * @param _arg a value to use as the single argument in calls + * to @p _intr + * @param _cookiep a pointer to a location to receive a cookie + * value that may be used to remove the interrupt + * handler + */ + +static __inline int BUS_SETUP_INTR(device_t _dev, device_t _child, + struct resource *_irq, int _flags, + driver_filter_t *_filter, + driver_intr_t *_intr, void *_arg, + void **_cookiep) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_setup_intr); + rc = ((bus_setup_intr_t *) _m)(_dev, _child, _irq, _flags, _filter, _intr, _arg, _cookiep); + return (rc); +} + +/** @brief Unique descriptor for the BUS_TEARDOWN_INTR() method */ +extern struct kobjop_desc bus_teardown_intr_desc; +/** @brief A function implementing the BUS_TEARDOWN_INTR() method */ +typedef int bus_teardown_intr_t(device_t _dev, device_t _child, + struct resource *_irq, void *_cookie); +/** + * @brief Uninstall an interrupt handler + * + * This method is used to disassociate an interrupt handler function + * with an irq resource. The value of @p _cookie must be the value + * returned from a previous call to BUS_SETUP_INTR(). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + * @param _cookie the cookie value returned when the interrupt + * was originally registered + */ + +static __inline int BUS_TEARDOWN_INTR(device_t _dev, device_t _child, + struct resource *_irq, void *_cookie) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_teardown_intr); + rc = ((bus_teardown_intr_t *) _m)(_dev, _child, _irq, _cookie); + return (rc); +} + +/** @brief Unique descriptor for the BUS_SUSPEND_INTR() method */ +extern struct kobjop_desc bus_suspend_intr_desc; +/** @brief A function implementing the BUS_SUSPEND_INTR() method */ +typedef int bus_suspend_intr_t(device_t _dev, device_t _child, + struct resource *_irq); +/** + * @brief Suspend an interrupt handler + * + * This method is used to mark a handler as suspended in the case + * that the associated device is powered down and cannot be a source + * for the, typically shared, interrupt. + * The value of @p _irq must be the interrupt resource passed + * to a previous call to BUS_SETUP_INTR(). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + */ + +static __inline int BUS_SUSPEND_INTR(device_t _dev, device_t _child, + struct resource *_irq) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_suspend_intr); + rc = ((bus_suspend_intr_t *) _m)(_dev, _child, _irq); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESUME_INTR() method */ +extern struct kobjop_desc bus_resume_intr_desc; +/** @brief A function implementing the BUS_RESUME_INTR() method */ +typedef int bus_resume_intr_t(device_t _dev, device_t _child, + struct resource *_irq); +/** + * @brief Resume an interrupt handler + * + * This method is used to clear suspended state of a handler when + * the associated device is powered up and can be an interrupt source + * again. + * The value of @p _irq must be the interrupt resource passed + * to a previous call to BUS_SETUP_INTR(). + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + */ + +static __inline int BUS_RESUME_INTR(device_t _dev, device_t _child, + struct resource *_irq) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_resume_intr); + rc = ((bus_resume_intr_t *) _m)(_dev, _child, _irq); + return (rc); +} + +/** @brief Unique descriptor for the BUS_SET_RESOURCE() method */ +extern struct kobjop_desc bus_set_resource_desc; +/** @brief A function implementing the BUS_SET_RESOURCE() method */ +typedef int bus_set_resource_t(device_t _dev, device_t _child, int _type, + int _rid, rman_res_t _start, rman_res_t _count); +/** + * @brief Define a resource which can be allocated with + * BUS_ALLOC_RESOURCE(). + * + * This method is used by some buses (typically ISA) to allow a + * driver to describe a resource range that it would like to + * allocate. The resource defined by @p _type and @p _rid is defined + * to start at @p _start and to include @p _count indices in its + * range. + * + * @param _dev the parent device of @p _child + * @param _child the device which owns the resource + * @param _type the type of resource + * @param _rid the resource identifier + * @param _start the start of the resource range + * @param _count the size of the resource range + */ + +static __inline int BUS_SET_RESOURCE(device_t _dev, device_t _child, int _type, + int _rid, rman_res_t _start, + rman_res_t _count) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_set_resource); + rc = ((bus_set_resource_t *) _m)(_dev, _child, _type, _rid, _start, _count); + return (rc); +} + +/** @brief Unique descriptor for the BUS_GET_RESOURCE() method */ +extern struct kobjop_desc bus_get_resource_desc; +/** @brief A function implementing the BUS_GET_RESOURCE() method */ +typedef int bus_get_resource_t(device_t _dev, device_t _child, int _type, + int _rid, rman_res_t *_startp, + rman_res_t *_countp); +/** + * @brief Describe a resource + * + * This method allows a driver to examine the range used for a given + * resource without actually allocating it. + * + * @param _dev the parent device of @p _child + * @param _child the device which owns the resource + * @param _type the type of resource + * @param _rid the resource identifier + * @param _start the address of a location to receive the start + * index of the resource range + * @param _count the address of a location to receive the size + * of the resource range + */ + +static __inline int BUS_GET_RESOURCE(device_t _dev, device_t _child, int _type, + int _rid, rman_res_t *_startp, + rman_res_t *_countp) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_resource); + rc = ((bus_get_resource_t *) _m)(_dev, _child, _type, _rid, _startp, _countp); + return (rc); +} + +/** @brief Unique descriptor for the BUS_DELETE_RESOURCE() method */ +extern struct kobjop_desc bus_delete_resource_desc; +/** @brief A function implementing the BUS_DELETE_RESOURCE() method */ +typedef void bus_delete_resource_t(device_t _dev, device_t _child, int _type, + int _rid); +/** + * @brief Delete a resource. + * + * Use this to delete a resource (possibly one previously added with + * BUS_SET_RESOURCE()). + * + * @param _dev the parent device of @p _child + * @param _child the device which owns the resource + * @param _type the type of resource + * @param _rid the resource identifier + */ + +static __inline void BUS_DELETE_RESOURCE(device_t _dev, device_t _child, + int _type, int _rid) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_delete_resource); + ((bus_delete_resource_t *) _m)(_dev, _child, _type, _rid); +} + +/** @brief Unique descriptor for the BUS_GET_RESOURCE_LIST() method */ +extern struct kobjop_desc bus_get_resource_list_desc; +/** @brief A function implementing the BUS_GET_RESOURCE_LIST() method */ +typedef struct resource_list * bus_get_resource_list_t(device_t _dev, + device_t _child); +/** + * @brief Return a struct resource_list. + * + * Used by drivers which use bus_generic_rl_alloc_resource() etc. to + * implement their resource handling. It should return the resource + * list of the given child device. + * + * @param _dev the parent device of @p _child + * @param _child the device which owns the resource list + */ + +static __inline struct resource_list * BUS_GET_RESOURCE_LIST(device_t _dev, + device_t _child) +{ + kobjop_t _m; + struct resource_list * rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_resource_list); + rc = ((bus_get_resource_list_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_CHILD_PRESENT() method */ +extern struct kobjop_desc bus_child_present_desc; +/** @brief A function implementing the BUS_CHILD_PRESENT() method */ +typedef int bus_child_present_t(device_t _dev, device_t _child); +/** + * @brief Is the hardware described by @p _child still attached to the + * system? + * + * This method should return 0 if the device is not present. It + * should return -1 if it is present. Any errors in determining + * should be returned as a normal errno value. Client drivers are to + * assume that the device is present, even if there is an error + * determining if it is there. Buses are to try to avoid returning + * errors, but newcard will return an error if the device fails to + * implement this method. + * + * @param _dev the parent device of @p _child + * @param _child the device which is being examined + */ + +static __inline int BUS_CHILD_PRESENT(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_child_present); + rc = ((bus_child_present_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_CHILD_PNPINFO_STR() method */ +extern struct kobjop_desc bus_child_pnpinfo_str_desc; +/** @brief A function implementing the BUS_CHILD_PNPINFO_STR() method */ +typedef int bus_child_pnpinfo_str_t(device_t _dev, device_t _child, char *_buf, + size_t _buflen); +/** + * @brief Returns the pnp info for this device. + * + * Return it as a string. If the storage is insufficient for the + * string, then return EOVERFLOW. + * + * The string must be formatted as a space-separated list of + * name=value pairs. Names may only contain alphanumeric characters, + * underscores ('_') and hyphens ('-'). Values can contain any + * non-whitespace characters. Values containing whitespace can be + * quoted with double quotes ('"'). Double quotes and backslashes in + * quoted values can be escaped with backslashes ('\'). + * + * @param _dev the parent device of @p _child + * @param _child the device which is being examined + * @param _buf the address of a buffer to receive the pnp + * string + * @param _buflen the size of the buffer pointed to by @p _buf + */ + +static __inline int BUS_CHILD_PNPINFO_STR(device_t _dev, device_t _child, + char *_buf, size_t _buflen) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_child_pnpinfo_str); + rc = ((bus_child_pnpinfo_str_t *) _m)(_dev, _child, _buf, _buflen); + return (rc); +} + +/** @brief Unique descriptor for the BUS_CHILD_LOCATION_STR() method */ +extern struct kobjop_desc bus_child_location_str_desc; +/** @brief A function implementing the BUS_CHILD_LOCATION_STR() method */ +typedef int bus_child_location_str_t(device_t _dev, device_t _child, char *_buf, + size_t _buflen); +/** + * @brief Returns the location for this device. + * + * Return it as a string. If the storage is insufficient for the + * string, then return EOVERFLOW. + * + * The string must be formatted as a space-separated list of + * name=value pairs. Names may only contain alphanumeric characters, + * underscores ('_') and hyphens ('-'). Values can contain any + * non-whitespace characters. Values containing whitespace can be + * quoted with double quotes ('"'). Double quotes and backslashes in + * quoted values can be escaped with backslashes ('\'). + * + * @param _dev the parent device of @p _child + * @param _child the device which is being examined + * @param _buf the address of a buffer to receive the location + * string + * @param _buflen the size of the buffer pointed to by @p _buf + */ + +static __inline int BUS_CHILD_LOCATION_STR(device_t _dev, device_t _child, + char *_buf, size_t _buflen) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_child_location_str); + rc = ((bus_child_location_str_t *) _m)(_dev, _child, _buf, _buflen); + return (rc); +} + +/** @brief Unique descriptor for the BUS_BIND_INTR() method */ +extern struct kobjop_desc bus_bind_intr_desc; +/** @brief A function implementing the BUS_BIND_INTR() method */ +typedef int bus_bind_intr_t(device_t _dev, device_t _child, + struct resource *_irq, int _cpu); +/** + * @brief Allow drivers to request that an interrupt be bound to a specific + * CPU. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + * @param _cpu the CPU to bind the interrupt to + */ + +static __inline int BUS_BIND_INTR(device_t _dev, device_t _child, + struct resource *_irq, int _cpu) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_bind_intr); + rc = ((bus_bind_intr_t *) _m)(_dev, _child, _irq, _cpu); + return (rc); +} + +/** @brief Unique descriptor for the BUS_CONFIG_INTR() method */ +extern struct kobjop_desc bus_config_intr_desc; +/** @brief A function implementing the BUS_CONFIG_INTR() method */ +typedef int bus_config_intr_t(device_t _dev, int _irq, enum intr_trigger _trig, + enum intr_polarity _pol); +/** + * @brief Allow (bus) drivers to specify the trigger mode and polarity + * of the specified interrupt. + * + * @param _dev the bus device + * @param _irq the interrupt number to modify + * @param _trig the trigger mode required + * @param _pol the interrupt polarity required + */ + +static __inline int BUS_CONFIG_INTR(device_t _dev, int _irq, + enum intr_trigger _trig, + enum intr_polarity _pol) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_config_intr); + rc = ((bus_config_intr_t *) _m)(_dev, _irq, _trig, _pol); + return (rc); +} + +/** @brief Unique descriptor for the BUS_DESCRIBE_INTR() method */ +extern struct kobjop_desc bus_describe_intr_desc; +/** @brief A function implementing the BUS_DESCRIBE_INTR() method */ +typedef int bus_describe_intr_t(device_t _dev, device_t _child, + struct resource *_irq, void *_cookie, + const char *_descr); +/** + * @brief Allow drivers to associate a description with an active + * interrupt handler. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + * @param _cookie the cookie value returned when the interrupt + * was originally registered + * @param _descr the description to associate with the interrupt + */ + +static __inline int BUS_DESCRIBE_INTR(device_t _dev, device_t _child, + struct resource *_irq, void *_cookie, + const char *_descr) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_describe_intr); + rc = ((bus_describe_intr_t *) _m)(_dev, _child, _irq, _cookie, _descr); + return (rc); +} + +/** @brief Unique descriptor for the BUS_HINTED_CHILD() method */ +extern struct kobjop_desc bus_hinted_child_desc; +/** @brief A function implementing the BUS_HINTED_CHILD() method */ +typedef void bus_hinted_child_t(device_t _dev, const char *_dname, int _dunit); +/** + * @brief Notify a (bus) driver about a child that the hints mechanism + * believes it has discovered. + * + * The bus is responsible for then adding the child in the right order + * and discovering other things about the child. The bus driver is + * free to ignore this hint, to do special things, etc. It is all up + * to the bus driver to interpret. + * + * This method is only called in response to the parent bus asking for + * hinted devices to be enumerated. + * + * @param _dev the bus device + * @param _dname the name of the device w/o unit numbers + * @param _dunit the unit number of the device + */ + +static __inline void BUS_HINTED_CHILD(device_t _dev, const char *_dname, + int _dunit) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_hinted_child); + ((bus_hinted_child_t *) _m)(_dev, _dname, _dunit); +} + +/** @brief Unique descriptor for the BUS_GET_DMA_TAG() method */ +extern struct kobjop_desc bus_get_dma_tag_desc; +/** @brief A function implementing the BUS_GET_DMA_TAG() method */ +typedef bus_dma_tag_t bus_get_dma_tag_t(device_t _dev, device_t _child); +/** + * @brief Returns bus_dma_tag_t for use w/ devices on the bus. + * + * @param _dev the parent device of @p _child + * @param _child the device to which the tag will belong + */ + +static __inline bus_dma_tag_t BUS_GET_DMA_TAG(device_t _dev, device_t _child) +{ + kobjop_t _m; + bus_dma_tag_t rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_dma_tag); + rc = ((bus_get_dma_tag_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_GET_BUS_TAG() method */ +extern struct kobjop_desc bus_get_bus_tag_desc; +/** @brief A function implementing the BUS_GET_BUS_TAG() method */ +typedef bus_space_tag_t bus_get_bus_tag_t(device_t _dev, device_t _child); +/** + * @brief Returns bus_space_tag_t for use w/ devices on the bus. + * + * @param _dev the parent device of @p _child + * @param _child the device to which the tag will belong + */ + +static __inline bus_space_tag_t BUS_GET_BUS_TAG(device_t _dev, device_t _child) +{ + kobjop_t _m; + bus_space_tag_t rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_bus_tag); + rc = ((bus_get_bus_tag_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_HINT_DEVICE_UNIT() method */ +extern struct kobjop_desc bus_hint_device_unit_desc; +/** @brief A function implementing the BUS_HINT_DEVICE_UNIT() method */ +typedef void bus_hint_device_unit_t(device_t _dev, device_t _child, + const char *_name, int *_unitp); +/** + * @brief Allow the bus to determine the unit number of a device. + * + * @param _dev the parent device of @p _child + * @param _child the device whose unit is to be wired + * @param _name the name of the device's new devclass + * @param _unitp a pointer to the device's new unit value + */ + +static __inline void BUS_HINT_DEVICE_UNIT(device_t _dev, device_t _child, + const char *_name, int *_unitp) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_hint_device_unit); + ((bus_hint_device_unit_t *) _m)(_dev, _child, _name, _unitp); +} + +/** @brief Unique descriptor for the BUS_NEW_PASS() method */ +extern struct kobjop_desc bus_new_pass_desc; +/** @brief A function implementing the BUS_NEW_PASS() method */ +typedef void bus_new_pass_t(device_t _dev); +/** + * @brief Notify a bus that the bus pass level has been changed + * + * @param _dev the bus device + */ + +static __inline void BUS_NEW_PASS(device_t _dev) +{ + kobjop_t _m; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_new_pass); + ((bus_new_pass_t *) _m)(_dev); +} + +/** @brief Unique descriptor for the BUS_REMAP_INTR() method */ +extern struct kobjop_desc bus_remap_intr_desc; +/** @brief A function implementing the BUS_REMAP_INTR() method */ +typedef int bus_remap_intr_t(device_t _dev, device_t _child, u_int _irq); +/** + * @brief Notify a bus that specified child's IRQ should be remapped. + * + * @param _dev the bus device + * @param _child the child device + * @param _irq the irq number + */ + +static __inline int BUS_REMAP_INTR(device_t _dev, device_t _child, u_int _irq) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_remap_intr); + rc = ((bus_remap_intr_t *) _m)(_dev, _child, _irq); + return (rc); +} + +/** @brief Unique descriptor for the BUS_SUSPEND_CHILD() method */ +extern struct kobjop_desc bus_suspend_child_desc; +/** @brief A function implementing the BUS_SUSPEND_CHILD() method */ +typedef int bus_suspend_child_t(device_t _dev, device_t _child); +/** + * @brief Suspend a given child + * + * @param _dev the parent device of @p _child + * @param _child the device to suspend + */ + +static __inline int BUS_SUSPEND_CHILD(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_suspend_child); + rc = ((bus_suspend_child_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESUME_CHILD() method */ +extern struct kobjop_desc bus_resume_child_desc; +/** @brief A function implementing the BUS_RESUME_CHILD() method */ +typedef int bus_resume_child_t(device_t _dev, device_t _child); +/** + * @brief Resume a given child + * + * @param _dev the parent device of @p _child + * @param _child the device to resume + */ + +static __inline int BUS_RESUME_CHILD(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_resume_child); + rc = ((bus_resume_child_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_GET_DOMAIN() method */ +extern struct kobjop_desc bus_get_domain_desc; +/** @brief A function implementing the BUS_GET_DOMAIN() method */ +typedef int bus_get_domain_t(device_t _dev, device_t _child, int *_domain); +/** + * @brief Get the VM domain handle for the given bus and child. + * + * @param _dev the bus device + * @param _child the child device + * @param _domain a pointer to the bus's domain handle identifier + */ + +static __inline int BUS_GET_DOMAIN(device_t _dev, device_t _child, int *_domain) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_domain); + rc = ((bus_get_domain_t *) _m)(_dev, _child, _domain); + return (rc); +} + +/** @brief Unique descriptor for the BUS_GET_CPUS() method */ +extern struct kobjop_desc bus_get_cpus_desc; +/** @brief A function implementing the BUS_GET_CPUS() method */ +typedef int bus_get_cpus_t(device_t _dev, device_t _child, enum cpu_sets _op, + size_t _setsize, struct _cpuset *_cpuset); +/** + * @brief Request a set of CPUs + * + * @param _dev the bus device + * @param _child the child device + * @param _op type of CPUs to request + * @param _setsize the size of the set passed in _cpuset + * @param _cpuset a pointer to a cpuset to receive the requested + * set of CPUs + */ + +static __inline int BUS_GET_CPUS(device_t _dev, device_t _child, + enum cpu_sets _op, size_t _setsize, + struct _cpuset *_cpuset) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_get_cpus); + rc = ((bus_get_cpus_t *) _m)(_dev, _child, _op, _setsize, _cpuset); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESET_PREPARE() method */ +extern struct kobjop_desc bus_reset_prepare_desc; +/** @brief A function implementing the BUS_RESET_PREPARE() method */ +typedef int bus_reset_prepare_t(device_t _dev, device_t _child); +/** + * @brief Prepares the given child of the bus for reset + * + * Typically bus detaches or suspends children' drivers, and then + * calls this method to save bus-specific information, for instance, + * PCI config space, which is damaged by reset. + * + * The bus_helper_reset_prepare() helper is provided to ease + * implementing bus reset methods. + * + * @param _dev the bus device + * @param _child the child device + */ + +static __inline int BUS_RESET_PREPARE(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_reset_prepare); + rc = ((bus_reset_prepare_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESET_POST() method */ +extern struct kobjop_desc bus_reset_post_desc; +/** @brief A function implementing the BUS_RESET_POST() method */ +typedef int bus_reset_post_t(device_t _dev, device_t _child); +/** + * @brief Restores the child operations after the reset + * + * The bus_helper_reset_post() helper is provided to ease + * implementing bus reset methods. + * + * @param _dev the bus device + * @param _child the child device + */ + +static __inline int BUS_RESET_POST(device_t _dev, device_t _child) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_reset_post); + rc = ((bus_reset_post_t *) _m)(_dev, _child); + return (rc); +} + +/** @brief Unique descriptor for the BUS_RESET_CHILD() method */ +extern struct kobjop_desc bus_reset_child_desc; +/** @brief A function implementing the BUS_RESET_CHILD() method */ +typedef int bus_reset_child_t(device_t _dev, device_t _child, int _flags); +/** + * @brief Performs reset of the child + * + * @param _dev the bus device + * @param _child the child device + * @param _flags DEVF_RESET_ flags + */ + +static __inline int BUS_RESET_CHILD(device_t _dev, device_t _child, int _flags) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)_dev)->ops,bus_reset_child); + rc = ((bus_reset_child_t *) _m)(_dev, _child, _flags); + return (rc); +} + +#endif /* _bus_if_h_ */ diff -ruN drvGPIOIITK.orig/device_if.h drvGPIOIITK/device_if.h --- drvGPIOIITK.orig/device_if.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/device_if.h 2020-11-26 04:44:40.316773000 +0100 @@ -0,0 +1,402 @@ +/* + * This file is @generated automatically. + * Do not modify anything in here by hand. + * + * Created from source file + * /usr/src/sys/kern/device_if.m + * with + * makeobjops.awk + * + * See the source file for legal information + */ + +/** + * @defgroup DEVICE device - KObj methods for all device drivers + * @brief A basic set of methods required for all device drivers. + * + * The device interface is used to match devices to drivers during + * autoconfiguration and provides methods to allow drivers to handle + * system-wide events such as suspend, resume or shutdown. + * @{ + */ + +#ifndef _device_if_h_ +#define _device_if_h_ + + +#include + +/** @brief Unique descriptor for the DEVICE_PROBE() method */ +extern struct kobjop_desc device_probe_desc; +/** @brief A function implementing the DEVICE_PROBE() method */ +typedef int device_probe_t(device_t dev); +/** + * @brief Probe to see if a device matches a driver. + * + * Users should not call this method directly. Normally, this + * is called via device_probe_and_attach() to select a driver + * calling the DEVICE_PROBE() of all candidate drivers and attach + * the winning driver (if any) to the device. + * + * This function is used to match devices to device drivers. + * Typically, the driver will examine the device to see if + * it is suitable for this driver. This might include checking + * the values of various device instance variables or reading + * hardware registers. + * + * In some cases, there may be more than one driver available + * which can be used for a device (for instance there might + * be a generic driver which works for a set of many types of + * device and a more specific driver which works for a subset + * of devices). Because of this, a driver should not assume + * that it will be the driver that attaches to the device even + * if it returns a success status from DEVICE_PROBE(). In particular, + * a driver must free any resources which it allocated during + * the probe before returning. The return value of DEVICE_PROBE() + * is used to elect which driver is used - the driver which returns + * the largest non-error value wins the election and attaches to + * the device. Common non-error values are described in the + * DEVICE_PROBE(9) manual page. + * + * If a driver matches the hardware, it should set the device + * description string using device_set_desc() or + * device_set_desc_copy(). This string is used to generate an + * informative message when DEVICE_ATTACH() is called. + * + * As a special case, if a driver returns zero, the driver election + * is cut short and that driver will attach to the device + * immediately. This should rarely be used. + * + * For example, a probe method for a PCI device driver might look + * like this: + * + * @code + * int + * foo_probe(device_t dev) + * { + * if (pci_get_vendor(dev) == FOOVENDOR && + * pci_get_device(dev) == FOODEVICE) { + * device_set_desc(dev, "Foo device"); + * return (BUS_PROBE_DEFAULT); + * } + * return (ENXIO); + * } + * @endcode + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_probe, foo_probe) + * @endcode + * + * @param dev the device to probe + * + * @retval 0 if this is the only possible driver for this + * device + * @retval negative if the driver can match this device - the + * least negative value is used to select the + * driver + * @retval ENXIO if the driver does not match the device + * @retval positive if some kind of error was detected during + * the probe, a regular unix error code should + * be returned to indicate the type of error + * @see DEVICE_ATTACH(), pci_get_vendor(), pci_get_device() + */ + +static __inline int DEVICE_PROBE(device_t dev) +{ + kobjop_t _m; + int rc; + +TSENTER2(device_get_name(dev)); + + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_probe); + rc = ((device_probe_t *) _m)(dev); + +TSEXIT2(device_get_name(dev)); + + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_IDENTIFY() method */ +extern struct kobjop_desc device_identify_desc; +/** @brief A function implementing the DEVICE_IDENTIFY() method */ +typedef void device_identify_t(driver_t *driver, device_t parent); +/** + * @brief Allow a device driver to detect devices not otherwise enumerated. + * + * The DEVICE_IDENTIFY() method is used by some drivers (e.g. the ISA + * bus driver) to help populate the bus device with a useful set of + * child devices, normally by calling the BUS_ADD_CHILD() method of + * the parent device. For instance, the ISA bus driver uses several + * special drivers, including the isahint driver and the pnp driver to + * create child devices based on configuration hints and PnP bus + * probes respectively. + * + * Many bus drivers which support true plug-and-play do not need to + * use this method at all since child devices can be discovered + * automatically without help from child drivers. + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_identify, foo_identify) + * @endcode + * + * @param driver the driver whose identify method is being called + * @param parent the parent device to use when adding new children + */ + +static __inline void DEVICE_IDENTIFY(driver_t *driver, device_t parent) +{ + kobjop_t _m; + KOBJOPLOOKUP(driver->ops,device_identify); + ((device_identify_t *) _m)(driver, parent); +} + +/** @brief Unique descriptor for the DEVICE_ATTACH() method */ +extern struct kobjop_desc device_attach_desc; +/** @brief A function implementing the DEVICE_ATTACH() method */ +typedef int device_attach_t(device_t dev); +/** + * @brief Attach a device to a device driver + * + * Normally only called via device_probe_and_attach(), this is called + * when a driver has succeeded in probing against a device. + * This method should initialise the hardware and allocate other + * system resources (e.g. devfs entries) as required. + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_attach, foo_attach) + * @endcode + * + * @param dev the device to probe + * + * @retval 0 success + * @retval non-zero if some kind of error was detected during + * the attach, a regular unix error code should + * be returned to indicate the type of error + * @see DEVICE_PROBE() + */ + +static __inline int DEVICE_ATTACH(device_t dev) +{ + kobjop_t _m; + int rc; + +TSENTER2(device_get_name(dev)); + + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_attach); + rc = ((device_attach_t *) _m)(dev); + +TSEXIT2(device_get_name(dev)); + + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_DETACH() method */ +extern struct kobjop_desc device_detach_desc; +/** @brief A function implementing the DEVICE_DETACH() method */ +typedef int device_detach_t(device_t dev); +/** + * @brief Detach a driver from a device. + * + * This can be called if the user is replacing the + * driver software or if a device is about to be physically removed + * from the system (e.g. for removable hardware such as USB or PCCARD). + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_detach, foo_detach) + * @endcode + * + * @param dev the device to detach + * + * @retval 0 success + * @retval non-zero the detach could not be performed, e.g. if the + * driver does not support detaching. + * + * @see DEVICE_ATTACH() + */ + +static __inline int DEVICE_DETACH(device_t dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_detach); + rc = ((device_detach_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_SHUTDOWN() method */ +extern struct kobjop_desc device_shutdown_desc; +/** @brief A function implementing the DEVICE_SHUTDOWN() method */ +typedef int device_shutdown_t(device_t dev); +/** + * @brief Called during system shutdown. + * + * This method allows drivers to detect when the system is being shut down. + * Some drivers need to use this to place their hardware in a consistent + * state before rebooting the computer. + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_shutdown, foo_shutdown) + * @endcode + */ + +static __inline int DEVICE_SHUTDOWN(device_t dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_shutdown); + rc = ((device_shutdown_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_SUSPEND() method */ +extern struct kobjop_desc device_suspend_desc; +/** @brief A function implementing the DEVICE_SUSPEND() method */ +typedef int device_suspend_t(device_t dev); +/** + * @brief This is called by the power-management subsystem when a + * suspend has been requested by the user or by some automatic + * mechanism. + * + * This gives drivers a chance to veto the suspend or save their + * configuration before power is removed. + * + * To include this method in a device driver, use a line like this in + * the driver's method list: + * + * @code + * KOBJMETHOD(device_suspend, foo_suspend) + * @endcode + * + * @param dev the device being suspended + * + * @retval 0 success + * @retval non-zero an error occurred while attempting to prepare the + * device for suspension + * + * @see DEVICE_RESUME() + */ + +static __inline int DEVICE_SUSPEND(device_t dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_suspend); + rc = ((device_suspend_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_RESUME() method */ +extern struct kobjop_desc device_resume_desc; +/** @brief A function implementing the DEVICE_RESUME() method */ +typedef int device_resume_t(device_t dev); +/** + * @brief This is called when the system resumes after a suspend. + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_resume, foo_resume) + * @endcode + * + * @param dev the device being resumed + * + * @retval 0 success + * @retval non-zero an error occurred while attempting to restore the + * device from suspension + * + * @see DEVICE_SUSPEND() + */ + +static __inline int DEVICE_RESUME(device_t dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_resume); + rc = ((device_resume_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_QUIESCE() method */ +extern struct kobjop_desc device_quiesce_desc; +/** @brief A function implementing the DEVICE_QUIESCE() method */ +typedef int device_quiesce_t(device_t dev); +/** + * @brief This is called when the driver is asked to quiesce itself. + * + * The driver should arrange for the orderly shutdown of this device. + * All further access to the device should be curtailed. Soon there + * will be a request to detach, but there won't necessarily be one. + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_quiesce, foo_quiesce) + * @endcode + * + * @param dev the device being quiesced + * + * @retval 0 success + * @retval non-zero an error occurred while attempting to quiesce the + * device + * + * @see DEVICE_DETACH() + */ + +static __inline int DEVICE_QUIESCE(device_t dev) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_quiesce); + rc = ((device_quiesce_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the DEVICE_REGISTER() method */ +extern struct kobjop_desc device_register_desc; +/** @brief A function implementing the DEVICE_REGISTER() method */ +typedef void * device_register_t(device_t dev); +/** + * @brief This is called when the driver is asked to register handlers. + * + * + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_register, foo_register) + * @endcode + * + * @param dev the device for which handlers are being registered + * + * @retval NULL method not implemented + * @retval non-NULL a pointer to implementation specific static driver state + * + */ + +static __inline void * DEVICE_REGISTER(device_t dev) +{ + kobjop_t _m; + void * rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,device_register); + rc = ((device_register_t *) _m)(dev); + return (rc); +} + +#endif /* _device_if_h_ */ diff -ruN drvGPIOIITK.orig/gpio_if.h drvGPIOIITK/gpio_if.h --- drvGPIOIITK.orig/gpio_if.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/gpio_if.h 2020-11-26 04:44:40.316805000 +0100 @@ -0,0 +1,206 @@ +/* + * This file is @generated automatically. + * Do not modify anything in here by hand. + * + * Created from source file + * /usr/src/sys/dev/gpio/gpio_if.m + * with + * makeobjops.awk + * + * See the source file for legal information + */ + + +#ifndef _gpio_if_h_ +#define _gpio_if_h_ + + +#include + +/** @brief Unique descriptor for the GPIO_GET_BUS() method */ +extern struct kobjop_desc gpio_get_bus_desc; +/** @brief A function implementing the GPIO_GET_BUS() method */ +typedef device_t gpio_get_bus_t(device_t dev); + +static __inline device_t GPIO_GET_BUS(device_t dev) +{ + kobjop_t _m; + device_t rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_get_bus); + rc = ((gpio_get_bus_t *) _m)(dev); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_MAX() method */ +extern struct kobjop_desc gpio_pin_max_desc; +/** @brief A function implementing the GPIO_PIN_MAX() method */ +typedef int gpio_pin_max_t(device_t dev, int *maxpin); + +static __inline int GPIO_PIN_MAX(device_t dev, int *maxpin) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_max); + rc = ((gpio_pin_max_t *) _m)(dev, maxpin); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_SET() method */ +extern struct kobjop_desc gpio_pin_set_desc; +/** @brief A function implementing the GPIO_PIN_SET() method */ +typedef int gpio_pin_set_t(device_t dev, uint32_t pin_num, uint32_t pin_value); + +static __inline int GPIO_PIN_SET(device_t dev, uint32_t pin_num, + uint32_t pin_value) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_set); + rc = ((gpio_pin_set_t *) _m)(dev, pin_num, pin_value); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_GET() method */ +extern struct kobjop_desc gpio_pin_get_desc; +/** @brief A function implementing the GPIO_PIN_GET() method */ +typedef int gpio_pin_get_t(device_t dev, uint32_t pin_num, uint32_t *pin_value); + +static __inline int GPIO_PIN_GET(device_t dev, uint32_t pin_num, + uint32_t *pin_value) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_get); + rc = ((gpio_pin_get_t *) _m)(dev, pin_num, pin_value); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_TOGGLE() method */ +extern struct kobjop_desc gpio_pin_toggle_desc; +/** @brief A function implementing the GPIO_PIN_TOGGLE() method */ +typedef int gpio_pin_toggle_t(device_t dev, uint32_t pin_num); + +static __inline int GPIO_PIN_TOGGLE(device_t dev, uint32_t pin_num) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_toggle); + rc = ((gpio_pin_toggle_t *) _m)(dev, pin_num); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_GETCAPS() method */ +extern struct kobjop_desc gpio_pin_getcaps_desc; +/** @brief A function implementing the GPIO_PIN_GETCAPS() method */ +typedef int gpio_pin_getcaps_t(device_t dev, uint32_t pin_num, uint32_t *caps); + +static __inline int GPIO_PIN_GETCAPS(device_t dev, uint32_t pin_num, + uint32_t *caps) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_getcaps); + rc = ((gpio_pin_getcaps_t *) _m)(dev, pin_num, caps); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_GETFLAGS() method */ +extern struct kobjop_desc gpio_pin_getflags_desc; +/** @brief A function implementing the GPIO_PIN_GETFLAGS() method */ +typedef int gpio_pin_getflags_t(device_t dev, uint32_t pin_num, + uint32_t *flags); + +static __inline int GPIO_PIN_GETFLAGS(device_t dev, uint32_t pin_num, + uint32_t *flags) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_getflags); + rc = ((gpio_pin_getflags_t *) _m)(dev, pin_num, flags); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_GETNAME() method */ +extern struct kobjop_desc gpio_pin_getname_desc; +/** @brief A function implementing the GPIO_PIN_GETNAME() method */ +typedef int gpio_pin_getname_t(device_t dev, uint32_t pin_num, char *name); + +static __inline int GPIO_PIN_GETNAME(device_t dev, uint32_t pin_num, char *name) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_getname); + rc = ((gpio_pin_getname_t *) _m)(dev, pin_num, name); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_SETFLAGS() method */ +extern struct kobjop_desc gpio_pin_setflags_desc; +/** @brief A function implementing the GPIO_PIN_SETFLAGS() method */ +typedef int gpio_pin_setflags_t(device_t dev, uint32_t pin_num, uint32_t flags); + +static __inline int GPIO_PIN_SETFLAGS(device_t dev, uint32_t pin_num, + uint32_t flags) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_setflags); + rc = ((gpio_pin_setflags_t *) _m)(dev, pin_num, flags); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_MAP_GPIOS() method */ +extern struct kobjop_desc gpio_map_gpios_desc; +/** @brief A function implementing the GPIO_MAP_GPIOS() method */ +typedef int gpio_map_gpios_t(device_t bus, phandle_t dev, phandle_t gparent, + int gcells, pcell_t *gpios, uint32_t *pin, + uint32_t *flags); + +static __inline int GPIO_MAP_GPIOS(device_t bus, phandle_t dev, + phandle_t gparent, int gcells, + pcell_t *gpios, uint32_t *pin, + uint32_t *flags) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,gpio_map_gpios); + rc = ((gpio_map_gpios_t *) _m)(bus, dev, gparent, gcells, gpios, pin, flags); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_ACCESS_32() method */ +extern struct kobjop_desc gpio_pin_access_32_desc; +/** @brief A function implementing the GPIO_PIN_ACCESS_32() method */ +typedef int gpio_pin_access_32_t(device_t dev, uint32_t first_pin, + uint32_t clear_pins, uint32_t change_pins, + uint32_t *orig_pins); + +static __inline int GPIO_PIN_ACCESS_32(device_t dev, uint32_t first_pin, + uint32_t clear_pins, + uint32_t change_pins, + uint32_t *orig_pins) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_access_32); + rc = ((gpio_pin_access_32_t *) _m)(dev, first_pin, clear_pins, change_pins, orig_pins); + return (rc); +} + +/** @brief Unique descriptor for the GPIO_PIN_CONFIG_32() method */ +extern struct kobjop_desc gpio_pin_config_32_desc; +/** @brief A function implementing the GPIO_PIN_CONFIG_32() method */ +typedef int gpio_pin_config_32_t(device_t dev, uint32_t first_pin, + uint32_t num_pins, uint32_t *pin_flags); + +static __inline int GPIO_PIN_CONFIG_32(device_t dev, uint32_t first_pin, + uint32_t num_pins, uint32_t *pin_flags) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)dev)->ops,gpio_pin_config_32); + rc = ((gpio_pin_config_32_t *) _m)(dev, first_pin, num_pins, pin_flags); + return (rc); +} + +#endif /* _gpio_if_h_ */ diff -ruN drvGPIOIITK.orig/gpioiitk.c drvGPIOIITK/gpioiitk.c --- drvGPIOIITK.orig/gpioiitk.c 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/gpioiitk.c 2020-11-26 04:44:40.316838000 +0100 @@ -0,0 +1,454 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Oskar Holmlund. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * GPIO input interrupt to kevent. + * + * DTS example check out BB-GPIOIITK.dts + * + * Inspired by GSoC 2018 User space interface for GPIO interrupts + * by Christian Krämer + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gpio_if.h" +#include "gpioiitk_ioctl.h" + +#define GPIOIITK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define GPIOIITK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define GPIOIITK_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_device), \ + "gpio_mux", MTX_DEF) +#define GPIOIITK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define GPIOIITK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define GPIOIITK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + +/* Defines for the ofw_compat_data table */ +#define GPIOIITK 0x01 +#define GPIOIITK_END 0x00 + +static d_open_t gpioiitk_open; +static d_close_t gpioiitk_close; +static d_ioctl_t gpioiitk_ioctl; +static d_kqfilter_t gpioiitk_kqfilter; + +static int gpioiitk_kqread(struct knote*, long); +static void gpioiitk_kqdetach(struct knote*); +static void input_intr(void *); +static int gpioiitk_detach(device_t); + +static struct cdevsw gpioiitk_cdevsw = { + .d_version = D_VERSION, + .d_open = gpioiitk_open, + .d_close = gpioiitk_close, + .d_ioctl = gpioiitk_ioctl, + .d_kqfilter = gpioiitk_kqfilter, + .d_name = GPIOIITK_NAME +}; + +static struct filterops gpioiitk_read_filterops = { + .f_isfd = true, + .f_attach = NULL, + .f_detach = gpioiitk_kqdetach, + .f_event = gpioiitk_kqread, + .f_touch = NULL +}; + +/* compatible */ +static struct ofw_compat_data compat_data[] = { + { "gpioiitk", GPIOIITK }, + { NULL, GPIOIITK_END }, +}; + +#define MAX_INPUTS 10 +struct gpio_input_softc; + +struct gpio_input_pin { + struct gpio_input_softc *sc_parent; + + gpio_pin_t sc_pin; + int sc_irid; + struct resource *sc_ires; + void *sc_ihandler; + + uint16_t sc_counter; + bool sc_state; +}; + +struct gpio_input_softc { + struct mtx sc_mtx; + device_t sc_device; + + struct gpio_input_pin sc_inputs[MAX_INPUTS]; + uint8_t sc_num_inputs; + bool sc_changed; + + /* Character device interface */ + struct cdev *sc_cdev; + + /* Kernel events */ + struct knlist sc_note; +}; + +/* --- Device methods --- */ +static int +gpioiitk_probe(device_t dev) +{ + const struct ofw_compat_data *compatible; + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + compatible = ofw_bus_search_compatible(dev, compat_data); + + switch (compatible->ocd_data) { + case GPIOIITK_END: + return (ENXIO); + case GPIOIITK: + device_set_desc(dev, "GPIO Input Interrupt To Kevent"); + break; + } + + return (BUS_PROBE_DEFAULT); +} + +static int +gpioiitk_attach(device_t dev) +{ + struct gpio_input_softc *sc; + const struct ofw_compat_data *compatible; + int unit, err, pincaps, idx; + phandle_t node; + + sc = device_get_softc(dev); + sc->sc_device = dev; + GPIOIITK_LOCK_INIT(sc); + + knlist_init_mtx(&sc->sc_note, &sc->sc_mtx); + + /* Look at the dts again and grab the type */ + compatible = ofw_bus_search_compatible(sc->sc_device, compat_data); + + node = ofw_bus_get_node(sc->sc_device); + + for (idx = 0; idx < MAX_INPUTS; idx++) { + + /* ------ Get the pin ------ */ + err = gpio_pin_get_by_ofw_propidx(sc->sc_device, node, + "input-gpios", idx, &sc->sc_inputs[idx].sc_pin); + if (err != 0 && idx == 0) { + /* Error at the first pin */ + /* something are actually wrong */ + /* probably no pins in DTS */ + device_printf(sc->sc_device, "inputs[%d]: err %d\n", + idx, err); + break; + } else if (err != 0) { + /* Error later on indicates the last pin are found */ + err = 0; + + /* sc_num_inputs are total number of pins + (not 0-index based) */ + sc->sc_num_inputs = idx; + break; + } + + + /* Check the state of the gpio pin */ + err = GPIO_PIN_GETFLAGS(sc->sc_inputs[idx].sc_pin->dev, + sc->sc_inputs[idx].sc_pin->pin, &pincaps); + if (err != 0) { + device_printf(dev, "Failed to get pin flags gpio[%d]\n", + idx); + break; + } + + /* Ensure the pin are in INPUT mode */ + if (!(pincaps & GPIO_PIN_INPUT)) { + device_printf(dev, "pin[%x] IS NOT in input mode\n", + idx); + err = 1; + break; + } + + /* Allocate interrupt resource */ + /* Available options are: + * GPIO_INTR_EDGE_BOTH + * GPIO_INTR_EDGE_FALLING + * GPIO_INTR_EDGE_RISING + * + * Set this in DTS? + */ + sc->sc_inputs[idx].sc_ires = gpio_alloc_intr_resource( + sc->sc_device, &sc->sc_inputs[idx].sc_irid, RF_ACTIVE, + sc->sc_inputs[idx].sc_pin, GPIO_INTR_EDGE_BOTH); + if (sc->sc_inputs[idx].sc_ires == NULL) { + device_printf(sc->sc_device, "Cannot allocate IRQ\n"); + err = 1; + break; + } + + /* Attach to interrupt handler function */ + err = bus_setup_intr(sc->sc_device, sc->sc_inputs[idx].sc_ires, + INTR_TYPE_BIO | INTR_MPSAFE, NULL, input_intr, + &sc->sc_inputs[idx], &sc->sc_inputs[idx].sc_ihandler); + if (err != 0) { + device_printf(sc->sc_device, "Unable to setup IRQ\n"); + break; + } + + sc->sc_inputs[idx].sc_counter = 0; + sc->sc_inputs[idx].sc_parent = sc; + gpio_pin_is_active(sc->sc_inputs[idx].sc_pin, + &sc->sc_inputs[idx].sc_state); + } + + if (err != 0) { + /* -- Free allocated resource -- */ + gpioiitk_detach(sc->sc_device); + return (ENXIO); + } + + /* -- Create device -- */ + unit = device_get_unit(sc->sc_device); + sc->sc_cdev = make_dev(&gpioiitk_cdevsw, unit, + UID_ROOT, GID_WHEEL, 0666, + "gpioiitk_%d", unit); + sc->sc_cdev->si_drv1 = sc; + + return (0); +} + +static int +gpioiitk_detach(device_t dev) +{ + struct gpio_input_softc *sc; + int idx; + + sc = device_get_softc(dev); + + if (sc->sc_cdev) + destroy_dev(sc->sc_cdev); + + /* Free input IRQ handler and pins */ + for (idx = 0; idx < MAX_INPUTS; idx++) { + if (sc->sc_inputs[idx].sc_ihandler) { + bus_teardown_intr(sc->sc_device, + sc->sc_inputs[idx].sc_ires, + sc->sc_inputs[idx].sc_ihandler); + } + if (sc->sc_inputs[idx].sc_pin) { + gpio_pin_release(sc->sc_inputs[idx].sc_pin); + } + if (sc->sc_inputs[idx].sc_ires) { + bus_release_resource(sc->sc_device, SYS_RES_IRQ, 0, + sc->sc_inputs[idx].sc_ires); + } + } + + KASSERT(mtx_initialized(&sc->sc_mtx), ("gpioiitk mtx not initialized")); + + GPIOIITK_LOCK_DESTROY(sc); + + return (0); +} + +static phandle_t +gpioiitk_get_node(device_t bus, device_t dev) +{ + struct gpio_input_softc *sc; + sc = device_get_softc(dev); + return (ofw_bus_get_node(bus)); +} + +/* + * Character device interface + */ + +static int +gpioiitk_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + return 0; +} + +static int +gpioiitk_close(struct cdev *dev, int fflags, int devtype, struct thread *td) +{ + return 0; +} + +static int +gpioiitk_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct gpio_input_softc *sc = dev->si_drv1; + uint32_t *INx; + uint16_t *counter; + uint8_t idx; + + GPIOIITK_LOCK(sc); + switch (cmd) + { + case GPIOIITK_GET_COUNTER: + counter = (uint16_t *)data; + for (idx = 0; idx < sc->sc_num_inputs; idx++) { + counter[idx] = sc->sc_inputs[idx].sc_counter; + sc->sc_inputs[idx].sc_counter=0; + } + break; + + /* Get the cached state on all input pins */ + case GPIOIITK_GET_CACHE: + INx = (uint32_t *) data; + *INx = 0; + for (idx = 0; idx < sc->sc_num_inputs; idx++) { + *INx |= (uint32_t)(sc->sc_inputs[idx].sc_state << idx); + } + break; + + /* Refetch the input state from HW */ + case GPIOIITK_GET: + INx = (uint32_t *) data; + *INx = 0; + for (idx = 0; idx < sc->sc_num_inputs; idx++) { + gpio_pin_is_active(sc->sc_inputs[idx].sc_pin, + &sc->sc_inputs[idx].sc_state); + *INx |= (uint32_t)(sc->sc_inputs[idx].sc_state << idx); + } + break; + } + GPIOIITK_UNLOCK(sc); + + return 0; +} + +/* Interrupt handler for input pin */ +static void +input_intr(void *arg) +{ + struct gpio_input_pin *input = (struct gpio_input_pin *)arg; + + GPIOIITK_LOCK(input->sc_parent); + gpio_pin_is_active(input->sc_pin, &input->sc_state); + input->sc_parent->sc_changed = true; + input->sc_counter++; + + KNOTE_LOCKED(&input->sc_parent->sc_note, 1); + GPIOIITK_UNLOCK(input->sc_parent); +} + +static int +gpioiitk_kqfilter(struct cdev *dev, struct knote *kn) +{ + struct gpio_input_softc *sc = dev->si_drv1; + + switch(kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &gpioiitk_read_filterops; + kn->kn_hook = (void *)sc; + break; + default: + return (EOPNOTSUPP); + } + + knlist_add(&sc->sc_note, kn, 0); + + return (0); +} + +static int +gpioiitk_kqread(struct knote *kn, long hint) +{ + struct gpio_input_softc *sc = kn->kn_hook; + int ret; + + kn->kn_data = + (sc->sc_inputs[0].sc_state) | + (sc->sc_inputs[1].sc_state<<1) | + (sc->sc_inputs[2].sc_state<<2) | + (sc->sc_inputs[3].sc_state<<3) | + (sc->sc_inputs[4].sc_state<<4) | + (sc->sc_inputs[5].sc_state<<5) | + (sc->sc_inputs[6].sc_state<<6) | + (sc->sc_inputs[7].sc_state<<7) | + (sc->sc_inputs[8].sc_state<<8) | + (sc->sc_inputs[9].sc_state<<9); + + ret = sc->sc_changed; + if (hint == 0) + sc->sc_changed = false; + + return (ret); +} + +static void +gpioiitk_kqdetach(struct knote *kn) +{ + struct gpio_input_softc *sc = kn->kn_hook; + + knlist_remove(&sc->sc_note, kn, 0); +} + +static device_method_t gpioiitk_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpioiitk_probe), + DEVMETHOD(device_attach, gpioiitk_attach), + DEVMETHOD(device_detach, gpioiitk_detach), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, gpioiitk_get_node), + + DEVMETHOD_END +}; + +static devclass_t gpioiitk_devclass; + +DEFINE_CLASS_0(gpioiitk, gpioiitk_driver, gpioiitk_methods, + sizeof(struct gpio_input_softc)); + +DRIVER_MODULE(gpioiitk, ofwbus, gpioiitk_driver, gpioiitk_devclass, NULL, NULL); +DRIVER_MODULE(gpioiitk, simplebus, gpioiitk_driver, gpioiitk_devclass, + NULL, NULL); +MODULE_DEPEND(gpioiitk, gpiobus, 1, 1, 1); + diff -ruN drvGPIOIITK.orig/gpioiitk_ioctl.h drvGPIOIITK/gpioiitk_ioctl.h --- drvGPIOIITK.orig/gpioiitk_ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/gpioiitk_ioctl.h 2020-11-26 04:44:40.316930000 +0100 @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Oskar Holmlund. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GPIOIITK_IOCTL__ +#define __GPIOIITK_IOCTL__ + +#include + +#define GPIOIITK_NAME "gpioiitk" + +#define GPIOIITK_GET _IOR('b', 1, uint32_t) +#define GPIOIITK_GET_CACHE _IOR('b', 2, uint32_t) +#define GPIOIITK_GET_COUNTER _IOR('b', 3, uint16_t[10]) + +#endif /* __GPIOIITK_IOCTL__ */ diff -ruN drvGPIOIITK.orig/ofw_bus_if.h drvGPIOIITK/ofw_bus_if.h --- drvGPIOIITK.orig/ofw_bus_if.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/ofw_bus_if.h 2020-11-26 04:44:40.316871000 +0100 @@ -0,0 +1,130 @@ +/* + * This file is @generated automatically. + * Do not modify anything in here by hand. + * + * Created from source file + * /usr/src/sys/dev/ofw/ofw_bus_if.m + * with + * makeobjops.awk + * + * See the source file for legal information + */ + + +#ifndef _ofw_bus_if_h_ +#define _ofw_bus_if_h_ + + +struct ofw_bus_devinfo { + phandle_t obd_node; + char *obd_compat; + char *obd_model; + char *obd_name; + char *obd_type; + char *obd_status; +}; + +/** @brief Unique descriptor for the OFW_BUS_GET_DEVINFO() method */ +extern struct kobjop_desc ofw_bus_get_devinfo_desc; +/** @brief A function implementing the OFW_BUS_GET_DEVINFO() method */ +typedef const struct ofw_bus_devinfo * ofw_bus_get_devinfo_t(device_t bus, + device_t dev); + +static __inline const struct ofw_bus_devinfo * OFW_BUS_GET_DEVINFO(device_t bus, + device_t dev) +{ + kobjop_t _m; + const struct ofw_bus_devinfo * rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_devinfo); + rc = ((ofw_bus_get_devinfo_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_GET_COMPAT() method */ +extern struct kobjop_desc ofw_bus_get_compat_desc; +/** @brief A function implementing the OFW_BUS_GET_COMPAT() method */ +typedef const char * ofw_bus_get_compat_t(device_t bus, device_t dev); + +static __inline const char * OFW_BUS_GET_COMPAT(device_t bus, device_t dev) +{ + kobjop_t _m; + const char * rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_compat); + rc = ((ofw_bus_get_compat_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_GET_MODEL() method */ +extern struct kobjop_desc ofw_bus_get_model_desc; +/** @brief A function implementing the OFW_BUS_GET_MODEL() method */ +typedef const char * ofw_bus_get_model_t(device_t bus, device_t dev); + +static __inline const char * OFW_BUS_GET_MODEL(device_t bus, device_t dev) +{ + kobjop_t _m; + const char * rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_model); + rc = ((ofw_bus_get_model_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_GET_NAME() method */ +extern struct kobjop_desc ofw_bus_get_name_desc; +/** @brief A function implementing the OFW_BUS_GET_NAME() method */ +typedef const char * ofw_bus_get_name_t(device_t bus, device_t dev); + +static __inline const char * OFW_BUS_GET_NAME(device_t bus, device_t dev) +{ + kobjop_t _m; + const char * rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_name); + rc = ((ofw_bus_get_name_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_GET_NODE() method */ +extern struct kobjop_desc ofw_bus_get_node_desc; +/** @brief A function implementing the OFW_BUS_GET_NODE() method */ +typedef phandle_t ofw_bus_get_node_t(device_t bus, device_t dev); + +static __inline phandle_t OFW_BUS_GET_NODE(device_t bus, device_t dev) +{ + kobjop_t _m; + phandle_t rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_node); + rc = ((ofw_bus_get_node_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_GET_TYPE() method */ +extern struct kobjop_desc ofw_bus_get_type_desc; +/** @brief A function implementing the OFW_BUS_GET_TYPE() method */ +typedef const char * ofw_bus_get_type_t(device_t bus, device_t dev); + +static __inline const char * OFW_BUS_GET_TYPE(device_t bus, device_t dev) +{ + kobjop_t _m; + const char * rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_get_type); + rc = ((ofw_bus_get_type_t *) _m)(bus, dev); + return (rc); +} + +/** @brief Unique descriptor for the OFW_BUS_MAP_INTR() method */ +extern struct kobjop_desc ofw_bus_map_intr_desc; +/** @brief A function implementing the OFW_BUS_MAP_INTR() method */ +typedef int ofw_bus_map_intr_t(device_t bus, device_t dev, phandle_t iparent, + int icells, pcell_t *interrupt); + +static __inline int OFW_BUS_MAP_INTR(device_t bus, device_t dev, + phandle_t iparent, int icells, + pcell_t *interrupt) +{ + kobjop_t _m; + int rc; + KOBJOPLOOKUP(((kobj_t)bus)->ops,ofw_bus_map_intr); + rc = ((ofw_bus_map_intr_t *) _m)(bus, dev, iparent, icells, interrupt); + return (rc); +} + +#endif /* _ofw_bus_if_h_ */ diff -ruN drvGPIOIITK.orig/opt_platform.h drvGPIOIITK/opt_platform.h --- drvGPIOIITK.orig/opt_platform.h 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/opt_platform.h 2020-11-26 04:44:40.316901000 +0100 @@ -0,0 +1,2 @@ +#define FDT 1 +#define EFI 1 diff -ruN drvGPIOIITK.orig/test.c drvGPIOIITK/test.c --- drvGPIOIITK.orig/test.c 1970-01-01 01:00:00.000000000 +0100 +++ drvGPIOIITK/test.c 2020-11-26 04:44:40.316960000 +0100 @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gpioiitk_ioctl.h" + +int main(int argc, char **argv) { + + struct kevent event[1]; + struct kevent tevent[1]; + int kq = -1; + int nev = -1; + struct timespec tv; + struct timespec *tv_ptr; + int res; + + tv.tv_sec = 2; + tv.tv_nsec = 0; + tv_ptr = &tv; + + uint32_t status; + uint16_t counters[10]; + int fd,ret, loop; + char device[32]; + snprintf(device, sizeof(device), "/dev/gpioiitk_%d", 0); + + fd = open(device, O_RDONLY); + if (fd < 0) { + printf("Failed to open device\n"); + return (1); + } + + ret = ioctl(fd, GPIOIITK_GET, &status); + if (ret < 0) { + close(fd); + printf("ioctl(GPIOIITK_GET)\n"); + return (1); + } + + printf("status: %x\n", status); + + ret = ioctl(fd, GPIOIITK_GET_COUNTER, counters); + if (ret < 0) { + close(fd); + printf("ioctl(GPIOIITK_GET_COUNTER)\n"); + return (1); + } + printf("counters[0]: %d\n", counters[0]); + printf("counters[1]: %d\n", counters[1]); + printf("counters[2]: %d\n", counters[2]); + + kq = kqueue(); + if (kq == -1) { + close(fd); + printf("kqueue()"); + return (1); + } + + EV_SET(&event[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + nev = kevent(kq, event, 1, NULL, 0, NULL); + if (nev == -1) { + printf("kevent()"); + close(fd); + return (1); + } + + while (1) { + nev = kevent(kq, NULL, 0, tevent, 1, tv_ptr); + if (nev == -1) { + printf("kevent()\n"); + break; + } else if (nev > 0) { + printf("keveturned %i events (flags: %d data %" PRIu64 ")\n", + nev, tevent[0].flags, tevent[0].data); + if (tevent[0].flags & EV_EOF) { + printf("Recieved EV_EOF\n"); + break; + } + } + } + + close(fd); + return (0); +}