From c4d7e5101085c19094470780ffe6cb788e53765f Mon Sep 17 00:00:00 2001 From: Robin van der Gracht Date: Mon, 7 Nov 2016 10:56:36 +0100 Subject: MAINTAINERS: auxdisplay: Added myself as maintainer for ht16k33 driver Signed-off-by: Robin van der Gracht CC: Miguel Ojeda Sandonis Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 3d838cf49f81..2e8b8710ce5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3025,6 +3025,12 @@ F: drivers/usb/host/whci/ F: drivers/usb/wusbcore/ F: include/linux/usb/wusb* +HT16K33 LED CONTROLLER DRIVER +M: Robin van der Gracht +S: Maintained +F: drivers/auxdisplay/ht16k33.c +F: Documentation/devicetree/bindings/display/ht16k33.txt + CFAG12864B LCD DRIVER M: Miguel Ojeda Sandonis W: http://miguelojeda.es/auxdisplay.htm -- cgit v1.2.3-55-g7522 From f2ed287bcc9073d8edbf6561c389b282163edc78 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 25 Oct 2016 16:28:10 +0200 Subject: char/pcmcia: add scr24x_cs chip card interface driver This implements only the very basic protocol "Mode A", just to make the device functional. Patches to implement "Mode C" that uses better bulking and is interrupt-driver may follow. The device essentially speaks the same protocol as USB CCID devices do over the bulk endpoints. The driver exchanges the command submissions and responses over a plain read()/write() interface, compatible with legacy OpenCT's pcmcia_block driver. Patches for the newer CCID driver are available: https://github.com/lkundrak/CCID/tree/lr/pcmcia_block Signed-off-by: Lubomir Rintel Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 + drivers/char/pcmcia/Kconfig | 11 ++ drivers/char/pcmcia/Makefile | 1 + drivers/char/pcmcia/scr24x_cs.c | 372 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 389 insertions(+) create mode 100644 drivers/char/pcmcia/scr24x_cs.c (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 2e8b8710ce5d..46f74871df09 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10699,6 +10699,11 @@ W: http://www.sunplus.com S: Supported F: arch/score/ +SCR24X CHIP CARD INTERFACE DRIVER +M: Lubomir Rintel +S: Supported +F: drivers/char/pcmcia/scr24x_cs.c + SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers M: Sudeep Holla L: linux-arm-kernel@lists.infradead.org diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index 8d3dfb0c8a26..1d1e7da8ad27 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -43,6 +43,17 @@ config CARDMAN_4040 (http://www.omnikey.com/), or a current development version of OpenCT (http://www.opensc-project.org/opensc). +config SCR24X + tristate "SCR24x Chip Card Interface support" + depends on PCMCIA + help + Enable support for the SCR24x PCMCIA Chip Card Interface. + + To compile this driver as a module, choose M here. + The module will be called scr24x_cs.. + + If unsure say N. + config IPWIRELESS tristate "IPWireless 3G UMTS PCMCIA card support" depends on PCMCIA && NETDEVICES && TTY diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile index 0aae20985d57..5b836bc21406 100644 --- a/drivers/char/pcmcia/Makefile +++ b/drivers/char/pcmcia/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o +obj-$(CONFIG_SCR24X) += scr24x_cs.o diff --git a/drivers/char/pcmcia/scr24x_cs.c b/drivers/char/pcmcia/scr24x_cs.c new file mode 100644 index 000000000000..4f215ce1a3be --- /dev/null +++ b/drivers/char/pcmcia/scr24x_cs.c @@ -0,0 +1,372 @@ +/* + * SCR24x PCMCIA Smart Card Reader Driver + * + * Copyright (C) 2005-2006 TL Sudheendran + * Copyright (C) 2016 Lubomir Rintel + * + * Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran. + * + * 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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CCID_HEADER_SIZE 10 +#define CCID_LENGTH_OFFSET 1 +#define CCID_MAX_LEN 271 + +#define SCR24X_DATA(n) (1 + n) +#define SCR24X_CMD_STATUS 7 +#define CMD_START 0x40 +#define CMD_WRITE_BYTE 0x41 +#define CMD_READ_BYTE 0x42 +#define STATUS_BUSY 0x80 + +struct scr24x_dev { + struct device *dev; + struct cdev c_dev; + unsigned char buf[CCID_MAX_LEN]; + int devno; + struct mutex lock; + struct kref refcnt; + u8 __iomem *regs; +}; + +#define SCR24X_DEVS 8 +static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS); + +static struct class *scr24x_class; +static dev_t scr24x_devt; + +static void scr24x_delete(struct kref *kref) +{ + struct scr24x_dev *dev = container_of(kref, struct scr24x_dev, + refcnt); + + kfree(dev); +} + +static int scr24x_wait_ready(struct scr24x_dev *dev) +{ + u_char status; + int timeout = 100; + + do { + status = ioread8(dev->regs + SCR24X_CMD_STATUS); + if (!(status & STATUS_BUSY)) + return 0; + + msleep(20); + } while (--timeout); + + return -EIO; +} + +static int scr24x_open(struct inode *inode, struct file *filp) +{ + struct scr24x_dev *dev = container_of(inode->i_cdev, + struct scr24x_dev, c_dev); + + kref_get(&dev->refcnt); + filp->private_data = dev; + + return nonseekable_open(inode, filp); +} + +static int scr24x_release(struct inode *inode, struct file *filp) +{ + struct scr24x_dev *dev = filp->private_data; + + /* We must not take the dev->lock here as scr24x_delete() + * might be called to remove the dev structure altogether. + * We don't need the lock anyway, since after the reference + * acquired in probe() is released in remove() the chrdev + * is already unregistered and noone can possibly acquire + * a reference via open() anymore. */ + kref_put(&dev->refcnt, scr24x_delete); + return 0; +} + +static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit) +{ + size_t i, y; + int ret; + + for (i = offset; i < limit; i += 5) { + iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS); + ret = scr24x_wait_ready(dev); + if (ret < 0) + return ret; + + for (y = 0; y < 5 && i + y < limit; y++) + dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y)); + } + + return 0; +} + +static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count, + loff_t *ppos) +{ + struct scr24x_dev *dev = filp->private_data; + int ret; + int len; + + if (count < CCID_HEADER_SIZE) + return -EINVAL; + + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + + if (!dev->dev) { + ret = -ENODEV; + goto out; + } + + ret = scr24x_wait_ready(dev); + if (ret < 0) + goto out; + len = CCID_HEADER_SIZE; + ret = read_chunk(dev, 0, len); + if (ret < 0) + goto out; + + len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET])); + if (len > sizeof(dev->buf)) { + ret = -EIO; + goto out; + } + read_chunk(dev, CCID_HEADER_SIZE, len); + if (ret < 0) + goto out; + + if (len < count) + count = len; + + if (copy_to_user(buf, dev->buf, count)) { + ret = -EFAULT; + goto out; + } + + ret = count; +out: + mutex_unlock(&dev->lock); + return ret; +} + +static ssize_t scr24x_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct scr24x_dev *dev = filp->private_data; + size_t i, y; + int ret; + + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + + if (!dev->dev) { + ret = -ENODEV; + goto out; + } + + if (count > sizeof(dev->buf)) { + ret = -EINVAL; + goto out; + } + + if (copy_from_user(dev->buf, buf, count)) { + ret = -EFAULT; + goto out; + } + + ret = scr24x_wait_ready(dev); + if (ret < 0) + goto out; + + iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS); + ret = scr24x_wait_ready(dev); + if (ret < 0) + goto out; + + for (i = 0; i < count; i += 5) { + for (y = 0; y < 5 && i + y < count; y++) + iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y)); + + iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS); + ret = scr24x_wait_ready(dev); + if (ret < 0) + goto out; + } + + ret = count; +out: + mutex_unlock(&dev->lock); + return ret; +} + +static const struct file_operations scr24x_fops = { + .owner = THIS_MODULE, + .read = scr24x_read, + .write = scr24x_write, + .open = scr24x_open, + .release = scr24x_release, + .llseek = no_llseek, +}; + +static int scr24x_config_check(struct pcmcia_device *link, void *priv_data) +{ + if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11) + return -ENODEV; + return pcmcia_request_io(link); +} + +static int scr24x_probe(struct pcmcia_device *link) +{ + struct scr24x_dev *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS); + if (dev->devno >= SCR24X_DEVS) { + ret = -EBUSY; + goto err; + } + + mutex_init(&dev->lock); + kref_init(&dev->refcnt); + + link->priv = dev; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + + ret = pcmcia_loop_config(link, scr24x_config_check, NULL); + if (ret < 0) + goto err; + + dev->dev = &link->dev; + dev->regs = devm_ioport_map(&link->dev, + link->resource[PCMCIA_IOPORT_0]->start, + resource_size(link->resource[PCMCIA_IOPORT_0])); + if (!dev->regs) { + ret = -EIO; + goto err; + } + + cdev_init(&dev->c_dev, &scr24x_fops); + dev->c_dev.owner = THIS_MODULE; + dev->c_dev.ops = &scr24x_fops; + ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1); + if (ret < 0) + goto err; + + ret = pcmcia_enable_device(link); + if (ret < 0) { + pcmcia_disable_device(link); + goto err; + } + + device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno), + NULL, "scr24x%d", dev->devno); + + dev_info(&link->dev, "SCR24x Chip Card Interface\n"); + return 0; + +err: + if (dev->devno < SCR24X_DEVS) + clear_bit(dev->devno, scr24x_minors); + kfree (dev); + return ret; +} + +static void scr24x_remove(struct pcmcia_device *link) +{ + struct scr24x_dev *dev = (struct scr24x_dev *)link->priv; + + device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno)); + mutex_lock(&dev->lock); + pcmcia_disable_device(link); + cdev_del(&dev->c_dev); + clear_bit(dev->devno, scr24x_minors); + dev->dev = NULL; + mutex_unlock(&dev->lock); + + kref_put(&dev->refcnt, scr24x_delete); +} + +static const struct pcmcia_device_id scr24x_ids[] = { + PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader", + 0x53cb94f9, 0xbfdf89a5), + PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3), + PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de), + PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, scr24x_ids); + +static struct pcmcia_driver scr24x_driver = { + .owner = THIS_MODULE, + .name = "scr24x_cs", + .probe = scr24x_probe, + .remove = scr24x_remove, + .id_table = scr24x_ids, +}; + +static int __init scr24x_init(void) +{ + int ret; + + scr24x_class = class_create(THIS_MODULE, "scr24x"); + if (IS_ERR(scr24x_class)) + return PTR_ERR(scr24x_class); + + ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x"); + if (ret < 0) { + class_destroy(scr24x_class); + return ret; + } + + ret = pcmcia_register_driver(&scr24x_driver); + if (ret < 0) { + unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); + class_destroy(scr24x_class); + } + + return ret; +} + +static void __exit scr24x_exit(void) +{ + pcmcia_unregister_driver(&scr24x_driver); + unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); + class_destroy(scr24x_class); +} + +module_init(scr24x_init); +module_exit(scr24x_exit); + +MODULE_AUTHOR("Lubomir Rintel"); +MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-55-g7522 From 8056756441092098bf8f2bb764f2af2ab0e1d3ff Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 10 Nov 2016 22:12:00 +0000 Subject: MAINTAINERS: update email I am no longer with Vector India. Update my email. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index c5d0c74f91d0..21b8664e94d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9098,7 +9098,7 @@ F: drivers/misc/panel.c PARALLEL PORT SUBSYSTEM M: Sudip Mukherjee -M: Sudip Mukherjee +M: Sudip Mukherjee L: linux-parport@lists.infradead.org (subscribers-only) S: Maintained F: drivers/parport/ @@ -11114,7 +11114,7 @@ F: include/media/i2c/ov2659.h SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee M: Teddy Wang -M: Sudip Mukherjee +M: Sudip Mukherjee L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/video/fbdev/sm712* @@ -11542,7 +11542,7 @@ F: drivers/staging/rtl8712/ STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER M: Sudip Mukherjee M: Teddy Wang -M: Sudip Mukherjee +M: Sudip Mukherjee L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/staging/sm750fb/ -- cgit v1.2.3-55-g7522 From 7f1a5f044e27838a94a252b0e038a0091c037535 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Mon, 21 Nov 2016 13:49:01 -0800 Subject: MAINTAINERS: Update fpga-mgr entry with new linux-fpga mailing list Update the fpga-mgr framework entry with new linux-fpga@vger.kernel.org mailing list. Signed-off-by: Moritz Fischer Cc: Alan Tull Cc: Greg Kroah-Hartman Cc: Michal Simek Cc: Sören Brinkmann Cc: David S. Miller Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: linux-fpga@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 21b8664e94d1..2f89c3be2a39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4956,6 +4956,7 @@ K: fmc_d.*register FPGA MANAGER FRAMEWORK M: Alan Tull R: Moritz Fischer +L: linux-fpga@vger.kernel.org S: Maintained F: drivers/fpga/ F: include/linux/fpga/fpga-mgr.h -- cgit v1.2.3-55-g7522 From e499807737b75387bcc9d146927dc36a0b7e4cff Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Tue, 29 Nov 2016 15:15:45 -0600 Subject: MAINTAINERS: add git url for fpga Add git url for fpga stuff. Signed-off-by: Alan Tull --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 2f89c3be2a39..b0fee8c45135 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4958,6 +4958,7 @@ M: Alan Tull R: Moritz Fischer L: linux-fpga@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git F: drivers/fpga/ F: include/linux/fpga/fpga-mgr.h W: http://www.rocketboards.org -- cgit v1.2.3-55-g7522 From 95096f2fbd10186d3e78a328b327afc71428f65f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 3 Dec 2016 12:34:40 -0800 Subject: uio-hv-generic: new userspace i/o driver for VMBus This is a new driver to enable userspace networking on VMBus. It is based largely on the similar driver that already exists for PCI, and earlier work done by Brocade to support DPDK. Signed-off-by: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/hv/connection.c | 1 + drivers/uio/Kconfig | 9 ++ drivers/uio/Makefile | 1 + drivers/uio/uio_hv_generic.c | 218 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 drivers/uio/uio_hv_generic.c (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index b0fee8c45135..d19faf724ac6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5852,6 +5852,7 @@ F: drivers/input/serio/hyperv-keyboard.c F: drivers/pci/host/pci-hyperv.c F: drivers/net/hyperv/ F: drivers/scsi/storvsc_drv.c +F: drivers/uio/uio_hv_generic.c F: drivers/video/fbdev/hyperv_fb.c F: include/linux/hyperv.h F: tools/hv/ diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 78e6368a4423..6ce8b874e833 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -39,6 +39,7 @@ struct vmbus_connection vmbus_connection = { .conn_state = DISCONNECTED, .next_gpadl_handle = ATOMIC_INIT(0xE1E10), }; +EXPORT_SYMBOL_GPL(vmbus_connection); /* * Negotiated protocol version with the host. diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 52c98ce1b6fe..7e8dc78a9796 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -155,4 +155,13 @@ config UIO_MF624 If you compile this as a module, it will be called uio_mf624. +config UIO_HV_GENERIC + tristate "Generic driver for Hyper-V VMBus" + depends on HYPERV + help + Generic driver that you can bind, dynamically, to any + Hyper-V VMBus device. It is useful to provide direct access + to network and storage devices from userspace. + + If you compile this as a module, it will be called uio_hv_generic. endif diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 8560dad52d0f..e9663bb8a4c7 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_UIO_NETX) += uio_netx.o obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o +obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c new file mode 100644 index 000000000000..ad3ab5805ad8 --- /dev/null +++ b/drivers/uio/uio_hv_generic.c @@ -0,0 +1,218 @@ +/* + * uio_hv_generic - generic UIO driver for VMBus + * + * Copyright (c) 2013-2016 Brocade Communications Systems, Inc. + * Copyright (c) 2016, Microsoft Corporation. + * + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * Since the driver does not declare any device ids, you must allocate + * id and bind the device to the driver yourself. For example: + * + * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \ + * > /sys/bus/vmbus/drivers/uio_hv_generic + * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ + * > /sys/bus/vmbus/drivers/hv_netvsc/unbind + * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ + * > /sys/bus/vmbus/drivers/uio_hv_generic/bind + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../hv/hyperv_vmbus.h" + +#define DRIVER_VERSION "0.02.0" +#define DRIVER_AUTHOR "Stephen Hemminger " +#define DRIVER_DESC "Generic UIO driver for VMBus devices" + +/* + * List of resources to be mapped to user space + * can be extended up to MAX_UIO_MAPS(5) items + */ +enum hv_uio_map { + TXRX_RING_MAP = 0, + INT_PAGE_MAP, + MON_PAGE_MAP, +}; + +#define HV_RING_SIZE 512 + +struct hv_uio_private_data { + struct uio_info info; + struct hv_device *device; +}; + +static int +hv_uio_mmap(struct uio_info *info, struct vm_area_struct *vma) +{ + int mi; + + if (vma->vm_pgoff >= MAX_UIO_MAPS) + return -EINVAL; + + if (info->mem[vma->vm_pgoff].size == 0) + return -EINVAL; + + mi = (int)vma->vm_pgoff; + + return remap_pfn_range(vma, vma->vm_start, + virt_to_phys((void *)info->mem[mi].addr) >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + +/* + * This is the irqcontrol callback to be registered to uio_info. + * It can be used to disable/enable interrupt from user space processes. + * + * @param info + * pointer to uio_info. + * @param irq_state + * state value. 1 to enable interrupt, 0 to disable interrupt. + */ +static int +hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) +{ + struct hv_uio_private_data *pdata = info->priv; + struct hv_device *dev = pdata->device; + + dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; + virt_mb(); + + return 0; +} + +/* + * Callback from vmbus_event when something is in inbound ring. + */ +static void hv_uio_channel_cb(void *context) +{ + struct hv_uio_private_data *pdata = context; + struct hv_device *dev = pdata->device; + + dev->channel->inbound.ring_buffer->interrupt_mask = 1; + virt_mb(); + + uio_event_notify(&pdata->info); +} + +static int +hv_uio_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) +{ + struct hv_uio_private_data *pdata; + int ret; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE, + HV_RING_SIZE * PAGE_SIZE, NULL, 0, + hv_uio_channel_cb, pdata); + if (ret) + goto fail; + + dev->channel->inbound.ring_buffer->interrupt_mask = 1; + dev->channel->batched_reading = false; + + /* Fill general uio info */ + pdata->info.name = "uio_hv_generic"; + pdata->info.version = DRIVER_VERSION; + pdata->info.irqcontrol = hv_uio_irqcontrol; + pdata->info.mmap = hv_uio_mmap; + pdata->info.irq = UIO_IRQ_CUSTOM; + + /* mem resources */ + pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; + pdata->info.mem[TXRX_RING_MAP].addr + = (phys_addr_t)dev->channel->ringbuffer_pages; + pdata->info.mem[TXRX_RING_MAP].size + = dev->channel->ringbuffer_pagecount * PAGE_SIZE; + pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; + + pdata->info.mem[INT_PAGE_MAP].name = "int_page"; + pdata->info.mem[INT_PAGE_MAP].addr = + (phys_addr_t)vmbus_connection.int_page; + pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; + pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + pdata->info.mem[MON_PAGE_MAP].name = "monitor_pages"; + pdata->info.mem[MON_PAGE_MAP].addr = + (phys_addr_t)vmbus_connection.monitor_pages[1]; + pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; + pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + pdata->info.priv = pdata; + pdata->device = dev; + + ret = uio_register_device(&dev->device, &pdata->info); + if (ret) { + dev_err(&dev->device, "hv_uio register failed\n"); + goto fail_close; + } + + hv_set_drvdata(dev, pdata); + + return 0; + +fail_close: + vmbus_close(dev->channel); +fail: + kfree(pdata); + + return ret; +} + +static int +hv_uio_remove(struct hv_device *dev) +{ + struct hv_uio_private_data *pdata = hv_get_drvdata(dev); + + if (!pdata) + return 0; + + uio_unregister_device(&pdata->info); + hv_set_drvdata(dev, NULL); + vmbus_close(dev->channel); + kfree(pdata); + return 0; +} + +static struct hv_driver hv_uio_drv = { + .name = "uio_hv_generic", + .id_table = NULL, /* only dynamic id's */ + .probe = hv_uio_probe, + .remove = hv_uio_remove, +}; + +static int __init +hyperv_module_init(void) +{ + return vmbus_driver_register(&hv_uio_drv); +} + +static void __exit +hyperv_module_exit(void) +{ + vmbus_driver_unregister(&hv_uio_drv); +} + +module_init(hyperv_module_init); +module_exit(hyperv_module_exit); + +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); -- cgit v1.2.3-55-g7522