diff --git a/device-db.h b/device-db.h new file mode 100644 index 0000000..5a18550 --- /dev/null +++ b/device-db.h @@ -0,0 +1,24 @@ +/* +Vendor Reset - Vendor Specific Reset +Copyright (C) 2020 Geoffrey McRae + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but 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. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +static struct vendor_reset_device vendor_reset_devices[] = +{ + { + .type = VENDOR_RESET_TYPE_INVALID + } +}; diff --git a/include/vendor-reset.h b/include/vendor-reset.h new file mode 100644 index 0000000..7937cda --- /dev/null +++ b/include/vendor-reset.h @@ -0,0 +1,40 @@ +/* +Vendor Reset - Vendor Specific Reset +Copyright (C) 2020 Geoffrey McRae + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but 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. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_VENDOR_RESET_IOCTL +#define _H_VENDOR_RESET_IOCTL + +#include +#include + +#define VENDOR_RESET_MAGIC 'r' + +#define VENDOR_RESET_TYPE_PCI 0x1 +#define VENDOR_RESET_TYPE_USB 0x2 + +struct vendor_reset_ioctl +{ + int type; + int domain; + int bus; + int devfn; +}; + +#define VENDOR_RESET_RESET _IOW(VENDOR_RESET_MAGIC, 1, struct vendor_reset_ioctl) + +#endif diff --git a/vendor-reset.c b/vendor-reset.c index ff1081e..47ab4ec 100644 --- a/vendor-reset.c +++ b/vendor-reset.c @@ -15,3 +15,106 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include +#include + +#include "vendor-reset.h" +#include "include/vendor-reset.h" + +#include "device-db.h" + +#define VENDOR_RESET_DEVNAME "vendor_reset" + +static long vendor_reset_ioctl_reset(struct file * filp, unsigned long arg) +{ + struct vendor_reset_ioctl dev; + struct vendor_reset_device *entry = vendor_reset_devices; + struct pci_dev * pcidev; + int ret; + + if (copy_from_user(&dev, (void __user *)arg, sizeof(dev))) + return -EFAULT; + + pcidev = pci_get_domain_bus_and_slot(dev.domain, dev.bus, dev.devfn); + if (!pcidev) + return -ENODEV; + + while(entry->type != VENDOR_RESET_TYPE_INVALID) + { + if (entry->type != VENDOR_RESET_TYPE_PCI || entry->vendor != pcidev->vendor) + continue; + + if (entry->device == VENDOR_RESET_DEVICE_ALL || + entry->device == pcidev->device) + break; + + ++entry; + } + + if (entry->type == VENDOR_RESET_TYPE_INVALID) + { + ret = -ENODEV; + goto err; + } + + ret = entry->ops.reset(pcidev); + +err: + pci_dev_put(pcidev); + return ret; +} + +static long vendor_reset_ioctl(struct file * filp, unsigned int ioctl, + unsigned long arg) +{ + long ret; + + switch(ioctl) + { + case VENDOR_RESET_RESET: + ret = vendor_reset_ioctl_reset(filp, arg); + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static const struct file_operations vendor_reset_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = vendor_reset_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vendor_reset_ioctl, +#endif +}; + +static struct miscdevice vendor_reset_misc = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = VENDOR_RESET_DEVNAME, + .fops = &vendor_reset_fops +}; + +static int __init vendor_reset_init(void) +{ + return misc_register(&vendor_reset_misc); +} + +static void __exit vendor_reset_exit(void) +{ + misc_deregister(&vendor_reset_misc); +} + +module_init(vendor_reset_init); +module_exit(vendor_reset_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Geoffrey McRae "); diff --git a/vendor-reset.h b/vendor-reset.h new file mode 100644 index 0000000..0cbee6f --- /dev/null +++ b/vendor-reset.h @@ -0,0 +1,51 @@ +/* +Vendor Reset - Vendor Specific Reset +Copyright (C) 2020 Geoffrey McRae + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but 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. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_VENDOR_RESET +#define _H_VENDOR_RESET + +#define VENDOR_RESET_TYPE_INVALID 0x0 +#define VENDOR_RESET_TYPE_PCI 0x1 + +#define VENDOR_RESET_DEVICE_ALL ((unsigned int)-1) + +#include + +struct vendor_reset_ops +{ + /* the reset method for the device at the specified address */ + int (*reset)(struct pci_dev *dev); +}; + +struct vendor_reset_device +{ + /* one of VENDOR_RESET_TYPE_* */ + unsigned int type; + + /* the vendor ID */ + unsigned int vendor; + + /* the device ID or VENDOR_RESET_DEVICE_ALL to match all devices for the + * vendor */ + unsigned int device; + + /* the reset operations */ + struct vendor_reset_ops ops; +}; + +#endif