diff options
Diffstat (limited to 'drivers/staging/ipack')
| -rw-r--r-- | drivers/staging/ipack/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/staging/ipack/Makefile | 6 | ||||
| -rw-r--r-- | drivers/staging/ipack/TODO | 46 | ||||
| -rw-r--r-- | drivers/staging/ipack/bridges/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/staging/ipack/bridges/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/ipack/bridges/tpci200.c | 1141 | ||||
| -rw-r--r-- | drivers/staging/ipack/bridges/tpci200.h | 162 | ||||
| -rw-r--r-- | drivers/staging/ipack/devices/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/staging/ipack/devices/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/ipack/devices/ipoctal.c | 901 | ||||
| -rw-r--r-- | drivers/staging/ipack/devices/ipoctal.h | 80 | ||||
| -rw-r--r-- | drivers/staging/ipack/devices/scc2698.h | 228 | ||||
| -rw-r--r-- | drivers/staging/ipack/ipack.c | 205 | ||||
| -rw-r--r-- | drivers/staging/ipack/ipack.h | 183 |
14 files changed, 0 insertions, 2989 deletions
diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig deleted file mode 100644 index af321789ddd..00000000000 --- a/drivers/staging/ipack/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# -# IPACK configuration. -# - -menuconfig IPACK_BUS - tristate "IndustryPack bus support" - ---help--- - If you say Y here you get support for the IndustryPack Framework - for drivers for many types of boards that support this industrial - bus. The IndustryPack Framework is a virtual bus allowing to - communicate between carrier and mezzanine cards connected through - this bus. - -if IPACK_BUS - -source "drivers/staging/ipack/bridges/Kconfig" - -source "drivers/staging/ipack/devices/Kconfig" - -endif # IPACK diff --git a/drivers/staging/ipack/Makefile b/drivers/staging/ipack/Makefile deleted file mode 100644 index 85ff223616f..00000000000 --- a/drivers/staging/ipack/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the IPACK bridge device drivers. -# -obj-$(CONFIG_IPACK_BUS) += ipack.o -obj-y += devices/ -obj-y += bridges/ diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO deleted file mode 100644 index 3a45a53afd8..00000000000 --- a/drivers/staging/ipack/TODO +++ /dev/null @@ -1,46 +0,0 @@ - TODO - ==== -Introduction -============ - -These drivers add support for IndustryPack devices: carrier and mezzanine -boards. - -The ipack driver is just an abstraction of the bus providing the common -operations between the two kind of boards. - -TODO -==== - -TPCI-200 --------- - -* It receives the name of the mezzanine plugged in each slot by SYSFS. - No autodetection supported yet, because the mezzanine driver could not be - loaded at the time that the tpci200 driver loads. - -* It has a linked list with the tpci200 devices it is managing. Get rid of it - and use driver_for_each_device() instead. - -IP-OCTAL --------- - -* It has a linked list which saves the devices it is currently - managing. It should use the driver_for_each_device() function. It is not there - due to the impossibility of using container_of macro to recover the - corresponding "struct ipoctal" because the attribute "struct ipack_device" is - a pointer. This code should be refactored. - -Ipack ------ - -* The structures and API exported can be improved a lot. For example, the - way to unregistering mezzanine devices, doing the mezzanine driver a call to - remove_device() to notify the carrier driver, or the opposite with the call to - the ipack_driver_ops' remove() function could be improved. - - -Contact -======= - -Contact: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
\ No newline at end of file diff --git a/drivers/staging/ipack/bridges/Kconfig b/drivers/staging/ipack/bridges/Kconfig deleted file mode 100644 index 97c837ea7a0..00000000000 --- a/drivers/staging/ipack/bridges/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config BOARD_TPCI200 - tristate "TEWS TPCI-200 support for IndustryPack bus" - depends on IPACK_BUS - depends on PCI - help - This driver supports the TEWS TPCI200 device for the IndustryPack bus. - default n - diff --git a/drivers/staging/ipack/bridges/Makefile b/drivers/staging/ipack/bridges/Makefile deleted file mode 100644 index d8b76459300..00000000000 --- a/drivers/staging/ipack/bridges/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_BOARD_TPCI200) += tpci200.o diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c deleted file mode 100644 index ad287075023..00000000000 --- a/drivers/staging/ipack/bridges/tpci200.c +++ /dev/null @@ -1,1141 +0,0 @@ -/** - * tpci200.c - * - * driver for the TEWS TPCI-200 device - * Copyright (c) 2009 Nicolas Serafini, EIC2 SA - * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include "tpci200.h" - -static struct ipack_bus_ops tpci200_bus_ops; - -/* TPCI200 controls registers */ -static int control_reg[] = { - TPCI200_CONTROL_A_REG, - TPCI200_CONTROL_B_REG, - TPCI200_CONTROL_C_REG, - TPCI200_CONTROL_D_REG -}; - -/* Linked list to save the registered devices */ -static LIST_HEAD(tpci200_list); - -static int tpci200_slot_unregister(struct ipack_device *dev); - -static struct tpci200_board *check_slot(struct ipack_device *dev) -{ - struct tpci200_board *tpci200; - int found = 0; - - if (dev == NULL) { - pr_info("Slot doesn't exist.\n"); - return NULL; - } - - list_for_each_entry(tpci200, &tpci200_list, list) { - if (tpci200->number == dev->bus_nr) { - found = 1; - break; - } - } - - if (!found) { - pr_err("Carrier not found\n"); - return NULL; - } - - if (dev->slot >= TPCI200_NB_SLOT) { - pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n", - dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1); - return NULL; - } - - BUG_ON(tpci200->slots == NULL); - if (tpci200->slots[dev->slot].dev == NULL) { - pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr, - dev->slot); - return NULL; - } - - return tpci200; -} - -static inline unsigned char __tpci200_read8(void __iomem *address, - unsigned long offset) -{ - return ioread8(address + (offset^1)); -} - -static inline unsigned short __tpci200_read16(void __iomem *address, - unsigned long offset) -{ - return ioread16(address + offset); -} - -static inline unsigned int __tpci200_read32(void __iomem *address, - unsigned long offset) -{ - return swahw32(ioread32(address + offset)); -} - -static inline void __tpci200_write8(unsigned char value, - void __iomem *address, unsigned long offset) -{ - iowrite8(value, address+(offset^1)); -} - -static inline void __tpci200_write16(unsigned short value, - void __iomem *address, - unsigned long offset) -{ - iowrite16(value, address+offset); -} - -static inline void __tpci200_write32(unsigned int value, - void __iomem *address, - unsigned long offset) -{ - iowrite32(swahw32(value), address+offset); -} - -static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev, - int space) -{ - struct ipack_addr_space *addr; - - switch (space) { - case IPACK_IO_SPACE: - addr = &dev->io_space; - break; - case IPACK_ID_SPACE: - addr = &dev->id_space; - break; - case IPACK_MEM_SPACE: - addr = &dev->mem_space; - break; - default: - pr_err("Slot [%d:%d] space number %d doesn't exist !\n", - dev->bus_nr, dev->slot, space); - return NULL; - break; - } - - if ((addr->size == 0) || (addr->address == NULL)) { - pr_err("Error, slot space not mapped !\n"); - return NULL; - } - - return addr; -} - -static int tpci200_read8(struct ipack_device *dev, int space, - unsigned long offset, unsigned char *value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if (offset >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - - *value = __tpci200_read8(addr->address, offset); - - return 0; -} - -static int tpci200_read16(struct ipack_device *dev, int space, - unsigned long offset, unsigned short *value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if ((offset+2) >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - *value = __tpci200_read16(addr->address, offset); - - return 0; -} - -static int tpci200_read32(struct ipack_device *dev, int space, - unsigned long offset, unsigned int *value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if ((offset+4) >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - - *value = __tpci200_read32(addr->address, offset); - - return 0; -} - -static int tpci200_write8(struct ipack_device *dev, int space, - unsigned long offset, unsigned char value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if (offset >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - - __tpci200_write8(value, addr->address, offset); - - return 0; -} - -static int tpci200_write16(struct ipack_device *dev, int space, - unsigned long offset, unsigned short value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if ((offset+2) >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - - __tpci200_write16(value, addr->address, offset); - - return 0; -} - -static int tpci200_write32(struct ipack_device *dev, int space, - unsigned long offset, unsigned int value) -{ - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if ((offset+4) >= addr->size) { - pr_err("Error, slot space offset error !\n"); - return -EFAULT; - } - - __tpci200_write32(value, addr->address, offset); - - return 0; -} - -static void tpci200_unregister(struct tpci200_board *tpci200) -{ - int i; - - free_irq(tpci200->info->pdev->irq, (void *) tpci200); - - pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); - pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space); - pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space); - - pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); - pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); - pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); - - pci_disable_device(tpci200->info->pdev); - pci_dev_put(tpci200->info->pdev); - - kfree(tpci200->info); - - for (i = 0; i < TPCI200_NB_SLOT; i++) { - tpci200->slots[i].io_phys.address = NULL; - tpci200->slots[i].io_phys.size = 0; - tpci200->slots[i].id_phys.address = NULL; - tpci200->slots[i].id_phys.size = 0; - tpci200->slots[i].mem_phys.address = NULL; - tpci200->slots[i].mem_phys.size = 0; - } -} - -static irqreturn_t tpci200_interrupt(int irq, void *dev_id) -{ - struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id; - int i; - unsigned long flags; - unsigned short status_reg, reg_value; - unsigned short unhandled_ints = 0; - irqreturn_t ret = IRQ_NONE; - - spin_lock_irqsave(&tpci200->info->access_lock, flags); - - /* Read status register */ - status_reg = readw(tpci200->info->interface_regs + - TPCI200_STATUS_REG); - - if (status_reg & TPCI200_SLOT_INT_MASK) { - unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK; - /* callback to the IRQ handler for the corresponding slot */ - for (i = 0; i < TPCI200_NB_SLOT; i++) { - if ((tpci200->slots[i].irq != NULL) && - (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) { - - ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg); - - /* Dummy reads */ - readw(tpci200->slots[i].dev->io_space.address + - 0xC0); - readw(tpci200->slots[i].dev->io_space.address + - 0xC2); - - unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i))); - } - } - } - /* Interrupt not handled are disabled */ - if (unhandled_ints) { - for (i = 0; i < TPCI200_NB_SLOT; i++) { - if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) { - pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n", - tpci200->number, i); - reg_value = readw( - tpci200->info->interface_regs + - control_reg[i]); - reg_value &= - ~(TPCI200_INT0_EN | TPCI200_INT1_EN); - writew(reg_value, - (tpci200->info->interface_regs + - control_reg[i])); - } - } - } - - spin_unlock_irqrestore(&tpci200->info->access_lock, flags); - return ret; -} - -#ifdef CONFIG_SYSFS - -static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number, - unsigned int slot_position) -{ - int found = 0; - struct ipack_device *dev; - struct tpci200_board *tpci200; - - list_for_each_entry(tpci200, &tpci200_list, list) { - if (tpci200->number == tpci200_number) { - found = 1; - break; - } - } - - if (!found) { - pr_err("carrier board not found for the device\n"); - return NULL; - } - - if (slot_position >= TPCI200_NB_SLOT) { - pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number, - slot_position); - return NULL; - } - - if (mutex_lock_interruptible(&tpci200->mutex)) - return NULL; - - if (tpci200->slots[slot_position].dev != NULL) { - pr_err("Slot [%d:%d] already installed !\n", tpci200_number, - slot_position); - goto err_unlock; - } - - /* - * Give the same IRQ number as the slot number. - * The TPCI200 has assigned his own two IRQ by PCI bus driver - */ - dev = ipack_device_register(tpci200->info->ipack_bus, - slot_position, slot_position); - if (dev == NULL) { - pr_info("Slot [%d:%d] Unable to register an ipack device\n", - tpci200_number, slot_position); - goto err_unlock; - } - - tpci200->slots[slot_position].dev = dev; - mutex_unlock(&tpci200->mutex); - return dev; - -err_unlock: - mutex_unlock(&tpci200->mutex); - return NULL; -} - -static ssize_t tpci200_store_board(struct device *pdev, const char *buf, - size_t count, int slot) -{ - struct tpci200_board *card = dev_get_drvdata(pdev); - struct ipack_device *dev = card->slots[slot].dev; - - if (dev != NULL) - return -EBUSY; - - dev = tpci200_slot_register(card->number, slot); - if (dev == NULL) - return -ENODEV; - - return count; -} - -static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot) -{ - struct tpci200_board *card = dev_get_drvdata(pdev); - struct ipack_device *dev = card->slots[slot].dev; - - if (dev != NULL) - return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev)); - else - return snprintf(buf, PAGE_SIZE, "none\n"); -} - -static ssize_t tpci200_show_description(struct device *pdev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, - "TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n"); -} - -static ssize_t tpci200_show_board_slot0(struct device *pdev, - struct device_attribute *attr, - char *buf) -{ - return tpci200_show_board(pdev, buf, 0); -} - -static ssize_t tpci200_store_board_slot0(struct device *pdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return tpci200_store_board(pdev, buf, count, 0); -} - -static ssize_t tpci200_show_board_slot1(struct device *pdev, - struct device_attribute *attr, - char *buf) -{ - return tpci200_show_board(pdev, buf, 1); -} - -static ssize_t tpci200_store_board_slot1(struct device *pdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return tpci200_store_board(pdev, buf, count, 1); -} - -static ssize_t tpci200_show_board_slot2(struct device *pdev, - struct device_attribute *attr, - char *buf) -{ - return tpci200_show_board(pdev, buf, 2); -} - -static ssize_t tpci200_store_board_slot2(struct device *pdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return tpci200_store_board(pdev, buf, count, 2); -} - - -static ssize_t tpci200_show_board_slot3(struct device *pdev, - struct device_attribute *attr, - char *buf) -{ - return tpci200_show_board(pdev, buf, 3); -} - -static ssize_t tpci200_store_board_slot3(struct device *pdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return tpci200_store_board(pdev, buf, count, 3); -} - -/* Declaration of the device attributes for the TPCI200 */ -static DEVICE_ATTR(description, S_IRUGO, - tpci200_show_description, NULL); -static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR, - tpci200_show_board_slot0, tpci200_store_board_slot0); -static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR, - tpci200_show_board_slot1, tpci200_store_board_slot1); -static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR, - tpci200_show_board_slot2, tpci200_store_board_slot2); -static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR, - tpci200_show_board_slot3, tpci200_store_board_slot3); - -static struct attribute *tpci200_attrs[] = { - &dev_attr_description.attr, - &dev_attr_board_slot0.attr, - &dev_attr_board_slot1.attr, - &dev_attr_board_slot2.attr, - &dev_attr_board_slot3.attr, - NULL, -}; - -static struct attribute_group tpci200_attr_group = { - .attrs = tpci200_attrs, -}; - -static int tpci200_create_sysfs_files(struct tpci200_board *card) -{ - return sysfs_create_group(&card->info->pdev->dev.kobj, - &tpci200_attr_group); -} - -static void tpci200_remove_sysfs_files(struct tpci200_board *card) -{ - sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group); -} - -#else - -static int tpci200_create_sysfs_files(struct tpci200_board *card) -{ - return 0; -} - -static void tpci200_remove_sysfs_files(struct tpci200_board *card) -{ -} - -#endif /* CONFIG_SYSFS */ - -static int tpci200_register(struct tpci200_board *tpci200) -{ - int i; - int res; - unsigned long ioidint_base; - unsigned long mem_base; - unsigned short slot_ctrl; - - if (pci_enable_device(tpci200->info->pdev) < 0) - return -ENODEV; - - if (tpci200_create_sysfs_files(tpci200) < 0) { - pr_err("failed creating sysfs files\n"); - res = -EFAULT; - goto out_disable_pci; - } - - /* Request IP interface register (Bar 2) */ - res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR, - "Carrier IP interface registers"); - if (res) { - pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !", - tpci200->info->pdev->bus->number, - tpci200->info->pdev->devfn); - goto out_remove_sysfs; - } - - /* Request IO ID INT space (Bar 3) */ - res = pci_request_region(tpci200->info->pdev, - TPCI200_IO_ID_INT_SPACES_BAR, - "Carrier IO ID INT space"); - if (res) { - pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !", - tpci200->info->pdev->bus->number, - tpci200->info->pdev->devfn); - goto out_release_ip_space; - } - - /* Request MEM space (Bar 4) */ - res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR, - "Carrier MEM space"); - if (res) { - pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!", - tpci200->info->pdev->bus->number, - tpci200->info->pdev->devfn); - goto out_release_ioid_int_space; - } - - /* Map internal tpci200 driver user space */ - tpci200->info->interface_regs = - ioremap(pci_resource_start(tpci200->info->pdev, - TPCI200_IP_INTERFACE_BAR), - TPCI200_IFACE_SIZE); - tpci200->info->ioidint_space = - ioremap(pci_resource_start(tpci200->info->pdev, - TPCI200_IO_ID_INT_SPACES_BAR), - TPCI200_IOIDINT_SIZE); - tpci200->info->mem8_space = - ioremap(pci_resource_start(tpci200->info->pdev, - TPCI200_MEM8_SPACE_BAR), - TPCI200_MEM8_SIZE); - - spin_lock_init(&tpci200->info->access_lock); - ioidint_base = pci_resource_start(tpci200->info->pdev, - TPCI200_IO_ID_INT_SPACES_BAR); - mem_base = pci_resource_start(tpci200->info->pdev, - TPCI200_MEM8_SPACE_BAR); - - /* Set the default parameters of the slot - * INT0 disabled, level sensitive - * INT1 disabled, level sensitive - * error interrupt disabled - * timeout interrupt disabled - * recover time disabled - * clock rate 8 MHz - */ - slot_ctrl = 0; - - /* Set all slot physical address space */ - for (i = 0; i < TPCI200_NB_SLOT; i++) { - tpci200->slots[i].io_phys.address = - (void __iomem *)ioidint_base + - TPCI200_IO_SPACE_OFF + TPCI200_IO_SPACE_GAP*i; - tpci200->slots[i].io_phys.size = TPCI200_IO_SPACE_SIZE; - - tpci200->slots[i].id_phys.address = - (void __iomem *)ioidint_base + - TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i; - tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE; - - tpci200->slots[i].mem_phys.address = - (void __iomem *)mem_base + TPCI200_MEM8_GAP*i; - tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE; - - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[i])); - } - - res = request_irq(tpci200->info->pdev->irq, - tpci200_interrupt, IRQF_SHARED, - KBUILD_MODNAME, (void *) tpci200); - if (res) { - pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !", - tpci200->info->pdev->bus->number, - tpci200->info->pdev->devfn); - tpci200_unregister(tpci200); - goto out_err; - } - - return 0; - -out_release_ioid_int_space: - pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); -out_release_ip_space: - pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); -out_remove_sysfs: - tpci200_remove_sysfs_files(tpci200); -out_disable_pci: - pci_disable_device(tpci200->info->pdev); -out_err: - return res; -} - -static int __tpci200_request_irq(struct tpci200_board *tpci200, - struct ipack_device *dev) -{ - unsigned short slot_ctrl; - - /* Set the default parameters of the slot - * INT0 enabled, level sensitive - * INT1 enabled, level sensitive - * error interrupt disabled - * timeout interrupt disabled - * recover time disabled - * clock rate 8 MHz - */ - slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN; - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[dev->slot])); - - return 0; -} - -static void __tpci200_free_irq(struct tpci200_board *tpci200, - struct ipack_device *dev) -{ - unsigned short slot_ctrl; - - /* Set the default parameters of the slot - * INT0 disabled, level sensitive - * INT1 disabled, level sensitive - * error interrupt disabled - * timeout interrupt disabled - * recover time disabled - * clock rate 8 MHz - */ - slot_ctrl = 0; - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[dev->slot])); -} - -static int tpci200_free_irq(struct ipack_device *dev) -{ - int res; - struct slot_irq *slot_irq; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) { - res = -EINVAL; - goto out; - } - - if (mutex_lock_interruptible(&tpci200->mutex)) { - res = -ERESTARTSYS; - goto out; - } - - if (tpci200->slots[dev->slot].irq == NULL) { - res = -EINVAL; - goto out_unlock; - } - - __tpci200_free_irq(tpci200, dev); - slot_irq = tpci200->slots[dev->slot].irq; - tpci200->slots[dev->slot].irq = NULL; - kfree(slot_irq); - -out_unlock: - mutex_unlock(&tpci200->mutex); -out: - return res; -} - -static int tpci200_slot_unmap_space(struct ipack_device *dev, int space) -{ - int res; - struct ipack_addr_space *virt_addr_space; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) { - res = -EINVAL; - goto out; - } - - if (mutex_lock_interruptible(&tpci200->mutex)) { - res = -ERESTARTSYS; - goto out; - } - - switch (space) { - case IPACK_IO_SPACE: - if (dev->io_space.address == NULL) { - pr_info("Slot [%d:%d] IO space not mapped !\n", - dev->bus_nr, dev->slot); - goto out_unlock; - } - virt_addr_space = &dev->io_space; - break; - case IPACK_ID_SPACE: - if (dev->id_space.address == NULL) { - pr_info("Slot [%d:%d] ID space not mapped !\n", - dev->bus_nr, dev->slot); - goto out_unlock; - } - virt_addr_space = &dev->id_space; - break; - case IPACK_MEM_SPACE: - if (dev->mem_space.address == NULL) { - pr_info("Slot [%d:%d] MEM space not mapped !\n", - dev->bus_nr, dev->slot); - goto out_unlock; - } - virt_addr_space = &dev->mem_space; - break; - default: - pr_err("Slot [%d:%d] space number %d doesn't exist !\n", - dev->bus_nr, dev->slot, space); - res = -EINVAL; - goto out_unlock; - break; - } - - iounmap(virt_addr_space->address); - - virt_addr_space->address = NULL; - virt_addr_space->size = 0; -out_unlock: - mutex_unlock(&tpci200->mutex); -out: - return res; -} - -static int tpci200_slot_unregister(struct ipack_device *dev) -{ - struct tpci200_board *tpci200; - - if (dev == NULL) - return -ENODEV; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - tpci200_free_irq(dev); - - if (mutex_lock_interruptible(&tpci200->mutex)) - return -ERESTARTSYS; - - ipack_device_unregister(dev); - tpci200->slots[dev->slot].dev = NULL; - mutex_unlock(&tpci200->mutex); - - return 0; -} - -static int tpci200_slot_map_space(struct ipack_device *dev, - unsigned int memory_size, int space) -{ - int res; - unsigned int size_to_map; - void __iomem *phys_address; - struct ipack_addr_space *virt_addr_space; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) { - res = -EINVAL; - goto out; - } - - if (mutex_lock_interruptible(&tpci200->mutex)) { - res = -ERESTARTSYS; - goto out; - } - - switch (space) { - case IPACK_IO_SPACE: - if (dev->io_space.address != NULL) { - pr_err("Slot [%d:%d] IO space already mapped !\n", - tpci200->number, dev->slot); - res = -EINVAL; - goto out_unlock; - } - virt_addr_space = &dev->io_space; - - phys_address = tpci200->slots[dev->slot].io_phys.address; - size_to_map = tpci200->slots[dev->slot].io_phys.size; - break; - case IPACK_ID_SPACE: - if (dev->id_space.address != NULL) { - pr_err("Slot [%d:%d] ID space already mapped !\n", - tpci200->number, dev->slot); - res = -EINVAL; - goto out_unlock; - } - virt_addr_space = &dev->id_space; - - phys_address = tpci200->slots[dev->slot].id_phys.address; - size_to_map = tpci200->slots[dev->slot].id_phys.size; - break; - case IPACK_MEM_SPACE: - if (dev->mem_space.address != NULL) { - pr_err("Slot [%d:%d] MEM space already mapped !\n", - tpci200->number, dev->slot); - res = -EINVAL; - goto out_unlock; - } - virt_addr_space = &dev->mem_space; - - if (memory_size > tpci200->slots[dev->slot].mem_phys.size) { - pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n", - dev->bus_nr, dev->slot, memory_size, - tpci200->slots[dev->slot].mem_phys.size); - res = -EINVAL; - goto out_unlock; - } - - phys_address = tpci200->slots[dev->slot].mem_phys.address; - size_to_map = memory_size; - break; - default: - pr_err("Slot [%d:%d] space %d doesn't exist !\n", - tpci200->number, dev->slot, space); - res = -EINVAL; - goto out_unlock; - break; - } - - virt_addr_space->size = size_to_map; - virt_addr_space->address = - ioremap((unsigned long)phys_address, size_to_map); - -out_unlock: - mutex_unlock(&tpci200->mutex); -out: - return res; -} - -static int tpci200_request_irq(struct ipack_device *dev, int vector, - int (*handler)(void *), void *arg) -{ - int res; - struct slot_irq *slot_irq; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) { - res = -EINVAL; - goto out; - } - - if (mutex_lock_interruptible(&tpci200->mutex)) { - res = -ERESTARTSYS; - goto out; - } - - if (tpci200->slots[dev->slot].irq != NULL) { - pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr, - dev->slot); - res = -EINVAL; - goto out_unlock; - } - - slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL); - if (slot_irq == NULL) { - pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n", - dev->bus_nr, dev->slot); - res = -ENOMEM; - goto out_unlock; - } - - /* - * WARNING: Setup Interrupt Vector in the IndustryPack device - * before an IRQ request. - * Read the User Manual of your IndustryPack device to know - * where to write the vector in memory. - */ - slot_irq->vector = vector; - slot_irq->handler = handler; - slot_irq->arg = arg; - slot_irq->name = dev_name(&dev->dev); - - tpci200->slots[dev->slot].irq = slot_irq; - res = __tpci200_request_irq(tpci200, dev); - -out_unlock: - mutex_unlock(&tpci200->mutex); -out: - return res; -} - -static void tpci200_slot_remove(struct tpci200_slot *slot) -{ - if ((slot->dev == NULL) || - (slot->dev->driver->ops->remove == NULL)) - return; - - slot->dev->driver->ops->remove(slot->dev); -} - -static void tpci200_uninstall(struct tpci200_board *tpci200) -{ - int i; - - for (i = 0; i < TPCI200_NB_SLOT; i++) - tpci200_slot_remove(&tpci200->slots[i]); - - tpci200_unregister(tpci200); - kfree(tpci200->slots); -} - -static struct ipack_bus_ops tpci200_bus_ops = { - .map_space = tpci200_slot_map_space, - .unmap_space = tpci200_slot_unmap_space, - .request_irq = tpci200_request_irq, - .free_irq = tpci200_free_irq, - .read8 = tpci200_read8, - .read16 = tpci200_read16, - .read32 = tpci200_read32, - .write8 = tpci200_write8, - .write16 = tpci200_write16, - .write32 = tpci200_write32, - .remove_device = tpci200_slot_unregister, -}; - -static int tpci200_install(struct tpci200_board *tpci200) -{ - int res; - - tpci200->slots = kzalloc( - TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL); - if (tpci200->slots == NULL) { - res = -ENOMEM; - goto out_err; - } - - res = tpci200_register(tpci200); - if (res) - goto out_free; - - mutex_init(&tpci200->mutex); - return 0; - -out_free: - kfree(tpci200->slots); - tpci200->slots = NULL; -out_err: - return res; -} - -static int tpci200_pciprobe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int ret; - struct tpci200_board *tpci200; - - tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL); - if (!tpci200) - return -ENOMEM; - - tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL); - if (!tpci200->info) { - kfree(tpci200); - return -ENOMEM; - } - - /* Save struct pci_dev pointer */ - tpci200->info->pdev = pdev; - tpci200->info->id_table = (struct pci_device_id *)id; - - /* register the device and initialize it */ - ret = tpci200_install(tpci200); - if (ret) { - pr_err("Error during tpci200 install !\n"); - kfree(tpci200->info); - kfree(tpci200); - return -ENODEV; - } - - /* Register the carrier in the industry pack bus driver */ - tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev, - TPCI200_NB_SLOT, - &tpci200_bus_ops); - if (!tpci200->info->ipack_bus) { - pr_err("error registering the carrier on ipack driver\n"); - tpci200_uninstall(tpci200); - kfree(tpci200->info); - kfree(tpci200); - return -EFAULT; - } - - /* save the bus number given by ipack to logging purpose */ - tpci200->number = tpci200->info->ipack_bus->bus_nr; - dev_set_drvdata(&pdev->dev, tpci200); - /* add the registered device in an internal linked list */ - list_add_tail(&tpci200->list, &tpci200_list); - return ret; -} - -static void __tpci200_pci_remove(struct tpci200_board *tpci200) -{ - tpci200_uninstall(tpci200); - tpci200_remove_sysfs_files(tpci200); - list_del(&tpci200->list); - ipack_bus_unregister(tpci200->info->ipack_bus); - kfree(tpci200->info); - kfree(tpci200); -} - -static void __devexit tpci200_pci_remove(struct pci_dev *dev) -{ - struct tpci200_board *tpci200, *next; - - /* Search the registered device to uninstall it */ - list_for_each_entry_safe(tpci200, next, &tpci200_list, list) { - if (tpci200->info->pdev == dev) { - __tpci200_pci_remove(tpci200); - break; - } - } -} - -static struct pci_device_id tpci200_idtable[2] = { - { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID, - TPCI200_SUBDEVICE_ID }, - { 0, }, -}; - -static struct pci_driver tpci200_pci_drv = { - .name = "tpci200", - .id_table = tpci200_idtable, - .probe = tpci200_pciprobe, - .remove = __devexit_p(tpci200_pci_remove), -}; - -static int __init tpci200_drvr_init_module(void) -{ - return pci_register_driver(&tpci200_pci_drv); -} - -static void __exit tpci200_drvr_exit_module(void) -{ - struct tpci200_board *tpci200, *next; - - list_for_each_entry_safe(tpci200, next, &tpci200_list, list) - __tpci200_pci_remove(tpci200); - - pci_unregister_driver(&tpci200_pci_drv); -} - -MODULE_DESCRIPTION("TEWS TPCI-200 device driver"); -MODULE_LICENSE("GPL"); -module_init(tpci200_drvr_init_module); -module_exit(tpci200_drvr_exit_module); diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h deleted file mode 100644 index 0b547eedddc..00000000000 --- a/drivers/staging/ipack/bridges/tpci200.h +++ /dev/null @@ -1,162 +0,0 @@ -/** - * tpci200.h - * - * driver for the carrier TEWS TPCI-200 - * Copyright (c) 2009 Nicolas Serafini, EIC2 SA - * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#ifndef _TPCI200_H_ -#define _TPCI200_H_ - -#include <linux/version.h> -#include <linux/limits.h> -#include <linux/pci.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/swab.h> -#include <linux/io.h> - -#include "../ipack.h" - -#define TPCI200_NB_SLOT 0x4 -#define TPCI200_NB_BAR 0x6 - -#define TPCI200_VENDOR_ID 0x1498 -#define TPCI200_DEVICE_ID 0x30C8 -#define TPCI200_SUBVENDOR_ID 0x1498 -#define TPCI200_SUBDEVICE_ID 0x300A - -#define TPCI200_IP_INTERFACE_BAR 2 -#define TPCI200_IO_ID_INT_SPACES_BAR 3 -#define TPCI200_MEM16_SPACE_BAR 4 -#define TPCI200_MEM8_SPACE_BAR 5 - -#define TPCI200_REVISION_REG 0x00 -#define TPCI200_CONTROL_A_REG 0x02 -#define TPCI200_CONTROL_B_REG 0x04 -#define TPCI200_CONTROL_C_REG 0x06 -#define TPCI200_CONTROL_D_REG 0x08 -#define TPCI200_RESET_REG 0x0A -#define TPCI200_STATUS_REG 0x0C - -#define TPCI200_IFACE_SIZE 0x100 - -#define TPCI200_IO_SPACE_OFF 0x0000 -#define TPCI200_IO_SPACE_GAP 0x0100 -#define TPCI200_IO_SPACE_SIZE 0x0080 -#define TPCI200_ID_SPACE_OFF 0x0080 -#define TPCI200_ID_SPACE_GAP 0x0100 -#define TPCI200_ID_SPACE_SIZE 0x0040 -#define TPCI200_INT_SPACE_OFF 0x00C0 -#define TPCI200_INT_SPACE_GAP 0x0100 -#define TPCI200_INT_SPACE_SIZE 0x0040 -#define TPCI200_IOIDINT_SIZE 0x0400 - -#define TPCI200_MEM8_GAP 0x00400000 -#define TPCI200_MEM8_SIZE 0x00400000 -#define TPCI200_MEM16_GAP 0x00800000 -#define TPCI200_MEM16_SIZE 0x00800000 - -#define TPCI200_INT0_EN 0x0040 -#define TPCI200_INT1_EN 0x0080 -#define TPCI200_INT0_EDGE 0x0010 -#define TPCI200_INT1_EDGE 0x0020 -#define TPCI200_ERR_INT_EN 0x0008 -#define TPCI200_TIME_INT_EN 0x0004 -#define TPCI200_RECOVER_EN 0x0002 -#define TPCI200_CLK32 0x0001 - -#define TPCI200_A_RESET 0x0001 -#define TPCI200_B_RESET 0x0002 -#define TPCI200_C_RESET 0x0004 -#define TPCI200_D_RESET 0x0008 - -#define TPCI200_A_TIMEOUT 0x1000 -#define TPCI200_B_TIMEOUT 0x2000 -#define TPCI200_C_TIMEOUT 0x4000 -#define TPCI200_D_TIMEOUT 0x8000 - -#define TPCI200_A_ERROR 0x0100 -#define TPCI200_B_ERROR 0x0200 -#define TPCI200_C_ERROR 0x0400 -#define TPCI200_D_ERROR 0x0800 - -#define TPCI200_A_INT0 0x0001 -#define TPCI200_A_INT1 0x0002 -#define TPCI200_B_INT0 0x0004 -#define TPCI200_B_INT1 0x0008 -#define TPCI200_C_INT0 0x0010 -#define TPCI200_C_INT1 0x0020 -#define TPCI200_D_INT0 0x0040 -#define TPCI200_D_INT1 0x0080 - -#define TPCI200_SLOT_INT_MASK 0x00FF - -#define VME_IOID_SPACE "IOID" -#define VME_MEM_SPACE "MEM" - -/** - * struct slot_irq - slot IRQ definition. - * @vector Vector number - * @handler Handler called when IRQ arrives - * @arg Handler argument - * @name IRQ name - * - */ -struct slot_irq { - int vector; - int (*handler)(void *); - void *arg; - const char *name; -}; - -/** - * struct tpci200_slot - data specific to the tpci200 slot. - * @slot_id Slot identification gived to external interface - * @irq Slot IRQ infos - * @io_phys IO physical base address register of the slot - * @id_phys ID physical base address register of the slot - * @mem_phys MEM physical base address register of the slot - * - */ -struct tpci200_slot { - struct ipack_device *dev; - struct slot_irq *irq; - struct ipack_addr_space io_phys; - struct ipack_addr_space id_phys; - struct ipack_addr_space mem_phys; -}; - -/** - * struct tpci200_infos - informations specific of the TPCI200 tpci200. - * @pci_dev PCI device - * @interface_regs Pointer to IP interface space (Bar 2) - * @ioidint_space Pointer to IP ID, IO and INT space (Bar 3) - * @mem8_space Pointer to MEM space (Bar 4) - * @access_lock Mutex lock for simultaneous access - * - */ -struct tpci200_infos { - struct pci_dev *pdev; - struct pci_device_id *id_table; - void __iomem *interface_regs; - void __iomem *ioidint_space; - void __iomem *mem8_space; - spinlock_t access_lock; - struct ipack_bus_device *ipack_bus; -}; -struct tpci200_board { - struct list_head list; - unsigned int number; - struct mutex mutex; - struct tpci200_slot *slots; - struct tpci200_infos *info; -}; - -#endif /* _TPCI200_H_ */ diff --git a/drivers/staging/ipack/devices/Kconfig b/drivers/staging/ipack/devices/Kconfig deleted file mode 100644 index 39f71888a58..00000000000 --- a/drivers/staging/ipack/devices/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config SERIAL_IPOCTAL - tristate "IndustryPack IP-OCTAL uart support" - depends on IPACK_BUS - help - This driver supports the IPOCTAL serial port device for the IndustryPack bus. - default n - diff --git a/drivers/staging/ipack/devices/Makefile b/drivers/staging/ipack/devices/Makefile deleted file mode 100644 index 6de18bda4a9..00000000000 --- a/drivers/staging/ipack/devices/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_SERIAL_IPOCTAL) += ipoctal.o diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c deleted file mode 100644 index 29f6fa841d2..00000000000 --- a/drivers/staging/ipack/devices/ipoctal.c +++ /dev/null @@ -1,901 +0,0 @@ -/** - * ipoctal.c - * - * driver for the GE IP-OCTAL boards - * Copyright (c) 2009 Nicolas Serafini, EIC2 SA - * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/device.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/tty.h> -#include <linux/serial.h> -#include <linux/tty_flip.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/atomic.h> -#include "../ipack.h" -#include "ipoctal.h" -#include "scc2698.h" - -#define IP_OCTAL_MANUFACTURER_ID 0xF0 -#define IP_OCTAL_232_ID 0x22 -#define IP_OCTAL_422_ID 0x2A -#define IP_OCTAL_485_ID 0x48 - -#define IP_OCTAL_ID_SPACE_VECTOR 0x41 -#define IP_OCTAL_NB_BLOCKS 4 - -static struct ipack_driver driver; -static const struct tty_operations ipoctal_fops; - -struct ipoctal { - struct list_head list; - struct ipack_device *dev; - unsigned int board_id; - struct scc2698_channel *chan_regs; - struct scc2698_block *block_regs; - struct ipoctal_stats chan_stats[NR_CHANNELS]; - char *buffer[NR_CHANNELS]; - unsigned int nb_bytes[NR_CHANNELS]; - unsigned int count_wr[NR_CHANNELS]; - struct ipoctal_config chan_config[NR_CHANNELS]; - wait_queue_head_t queue[NR_CHANNELS]; - unsigned short error_flag[NR_CHANNELS]; - spinlock_t lock[NR_CHANNELS]; - unsigned int pointer_read[NR_CHANNELS]; - unsigned int pointer_write[NR_CHANNELS]; - atomic_t open[NR_CHANNELS]; - unsigned char write; - struct tty_port tty_port[NR_CHANNELS]; - struct tty_driver *tty_drv; -}; - -/* Linked list to save the registered devices */ -static LIST_HEAD(ipoctal_list); - -static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal, - unsigned char *dest, - unsigned char value) -{ - unsigned long offset; - - offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address; - ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset, - value); -} - -static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal, - unsigned char *dest, - unsigned char value) -{ - ipoctal_write_io_reg(ipoctal, dest, value); -} - -static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal, - unsigned char *src) -{ - unsigned long offset; - unsigned char value; - - offset = ((void __iomem *) src) - ipoctal->dev->io_space.address; - ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset, - &value); - return value; -} - -static struct ipoctal *ipoctal_find_board(struct tty_struct *tty) -{ - struct ipoctal *p; - - list_for_each_entry(p, &ipoctal_list, list) { - if (tty->driver->major == p->tty_drv->major) - return p; - } - - return NULL; -} - -static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct ipoctal *ipoctal; - int channel = tty->index; - - ipoctal = ipoctal_find_board(tty); - - if (ipoctal == NULL) { - pr_err("Device not found. Major %d\n", tty->driver->major); - return -ENODEV; - } - - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); - tty->driver_data = ipoctal; - - return 0; -} - -static int ipoctal_open(struct tty_struct *tty, struct file *file) -{ - int channel = tty->index; - int res; - struct ipoctal *ipoctal; - - ipoctal = ipoctal_find_board(tty); - - if (ipoctal == NULL) { - pr_err("Device not found. Major %d\n", tty->driver->major); - return -ENODEV; - } - - if (atomic_read(&ipoctal->open[channel])) - return -EBUSY; - - res = tty_port_open(&ipoctal->tty_port[channel], tty, file); - if (res) - return res; - - atomic_inc(&ipoctal->open[channel]); - return 0; -} - -static void ipoctal_reset_stats(struct ipoctal_stats *stats) -{ - stats->tx = 0; - stats->rx = 0; - stats->rcv_break = 0; - stats->framing_err = 0; - stats->overrun_err = 0; - stats->parity_err = 0; -} - -static void ipoctal_free_channel(struct tty_struct *tty) -{ - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - if (ipoctal == NULL) - return; - - ipoctal_reset_stats(&ipoctal->chan_stats[channel]); - ipoctal->pointer_read[channel] = 0; - ipoctal->pointer_write[channel] = 0; - ipoctal->nb_bytes[channel] = 0; -} - -static void ipoctal_close(struct tty_struct *tty, struct file *filp) -{ - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - tty_port_close(&ipoctal->tty_port[channel], tty, filp); - - if (atomic_dec_and_test(&ipoctal->open[channel])) - ipoctal_free_channel(tty); -} - -static int ipoctal_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct ipoctal *ipoctal = tty->driver_data; - int channel = tty->index; - - icount->cts = 0; - icount->dsr = 0; - icount->rng = 0; - icount->dcd = 0; - icount->rx = ipoctal->chan_stats[channel].rx; - icount->tx = ipoctal->chan_stats[channel].tx; - icount->frame = ipoctal->chan_stats[channel].framing_err; - icount->parity = ipoctal->chan_stats[channel].parity_err; - icount->brk = ipoctal->chan_stats[channel].rcv_break; - return 0; -} - -static int ipoctal_irq_handler(void *arg) -{ - unsigned int channel; - unsigned int block; - unsigned char isr; - unsigned char sr; - unsigned char isr_tx_rdy, isr_rx_rdy; - unsigned char value; - unsigned char flag; - struct tty_struct *tty; - struct ipoctal *ipoctal = (struct ipoctal *) arg; - - /* Check all channels */ - for (channel = 0; channel < NR_CHANNELS; channel++) { - /* If there is no client, skip the check */ - if (!atomic_read(&ipoctal->open[channel])) - continue; - - tty = tty_port_tty_get(&ipoctal->tty_port[channel]); - if (!tty) - continue; - - /* - * The HW is organized in pair of channels. - * See which register we need to read from - */ - block = channel / 2; - isr = ipoctal_read_io_reg(ipoctal, - &ipoctal->block_regs[block].u.r.isr); - sr = ipoctal_read_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.r.sr); - - if ((channel % 2) == 1) { - isr_tx_rdy = isr & ISR_TxRDY_B; - isr_rx_rdy = isr & ISR_RxRDY_FFULL_B; - } else { - isr_tx_rdy = isr & ISR_TxRDY_A; - isr_rx_rdy = isr & ISR_RxRDY_FFULL_A; - } - - /* In case of RS-485, change from TX to RX when finishing TX. - * Half-duplex. - */ - if ((ipoctal->board_id == IP_OCTAL_485_ID) && - (sr & SR_TX_EMPTY) && - (ipoctal->nb_bytes[channel] == 0)) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_NEGATE_RTSN); - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); - ipoctal->write = 1; - wake_up_interruptible(&ipoctal->queue[channel]); - } - - /* RX data */ - if (isr_rx_rdy && (sr & SR_RX_READY)) { - value = ipoctal_read_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.r.rhr); - flag = TTY_NORMAL; - - /* Error: count statistics */ - if (sr & SR_ERROR) { - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - - if (sr & SR_OVERRUN_ERROR) { - ipoctal->error_flag[channel] |= UART_OVERRUN; - ipoctal->chan_stats[channel].overrun_err++; - /* Overrun doesn't affect the current character*/ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - if (sr & SR_PARITY_ERROR) { - ipoctal->error_flag[channel] |= UART_PARITY; - ipoctal->chan_stats[channel].parity_err++; - flag = TTY_PARITY; - } - if (sr & SR_FRAMING_ERROR) { - ipoctal->error_flag[channel] |= UART_FRAMING; - ipoctal->chan_stats[channel].framing_err++; - flag = TTY_FRAME; - } - if (sr & SR_RECEIVED_BREAK) { - ipoctal->error_flag[channel] |= UART_BREAK; - ipoctal->chan_stats[channel].rcv_break++; - flag = TTY_BREAK; - } - } - - tty_insert_flip_char(tty, value, flag); - } - - /* TX of each character */ - if (isr_tx_rdy && (sr & SR_TX_READY)) { - unsigned int *pointer_write = - &ipoctal->pointer_write[channel]; - - if (ipoctal->nb_bytes[channel] <= 0) { - ipoctal->nb_bytes[channel] = 0; - continue; - } - spin_lock(&ipoctal->lock[channel]); - value = ipoctal->buffer[channel][*pointer_write]; - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.thr, - value); - ipoctal->chan_stats[channel].tx++; - ipoctal->count_wr[channel]++; - (*pointer_write)++; - *pointer_write = *pointer_write % PAGE_SIZE; - ipoctal->nb_bytes[channel]--; - spin_unlock(&ipoctal->lock[channel]); - - if ((ipoctal->nb_bytes[channel] == 0) && - (waitqueue_active(&ipoctal->queue[channel]))) { - - if (ipoctal->board_id != IP_OCTAL_485_ID) { - ipoctal->write = 1; - wake_up_interruptible(&ipoctal->queue[channel]); - } - } - } - - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - return IRQ_HANDLED; -} - -static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id) -{ - unsigned char manufacturerID; - unsigned char board_id; - - dev->bus->ops->read8(dev, IPACK_ID_SPACE, - IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID); - if (manufacturerID != IP_OCTAL_MANUFACTURER_ID) - return -ENODEV; - - dev->bus->ops->read8(dev, IPACK_ID_SPACE, - IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id); - - switch (board_id) { - case IP_OCTAL_232_ID: - case IP_OCTAL_422_ID: - case IP_OCTAL_485_ID: - *id = board_id; - break; - default: - return -ENODEV; - } - - return 0; -} - -static const struct tty_port_operations ipoctal_tty_port_ops = { - .dtr_rts = NULL, - .activate = ipoctal_port_activate, -}; - -static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, - unsigned int slot, unsigned int vector) -{ - int res = 0; - int i; - struct tty_driver *tty; - char name[20]; - unsigned char board_id; - - res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, - IPACK_ID_SPACE); - if (res) { - pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot); - return res; - } - - res = ipoctal_check_model(ipoctal->dev, &board_id); - if (res) { - ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, - IPACK_ID_SPACE); - goto out_unregister_id_space; - } - ipoctal->board_id = board_id; - - res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, - IPACK_IO_SPACE); - if (res) { - pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot); - goto out_unregister_id_space; - } - - res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, - 0x8000, IPACK_MEM_SPACE); - if (res) { - pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot); - goto out_unregister_io_space; - } - - /* Save the virtual address to access the registers easily */ - ipoctal->chan_regs = - (struct scc2698_channel *) ipoctal->dev->io_space.address; - ipoctal->block_regs = - (struct scc2698_block *) ipoctal->dev->io_space.address; - - /* Disable RX and TX before touching anything */ - for (i = 0; i < NR_CHANNELS ; i++) { - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - } - - for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.acr, - ACR_BRG_SET2); - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.opcr, - OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | - OPCR_MPOb_RTSN); - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.imr, - IMR_TxRDY_A | IMR_RxRDY_FFULL_A | - IMR_DELTA_BREAK_A | IMR_TxRDY_B | - IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B); - } - - /* - * IP-OCTAL has different addresses to copy its IRQ vector. - * Depending of the carrier these addresses are accesible or not. - * More info in the datasheet. - */ - ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector, - ipoctal_irq_handler, ipoctal); - ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_ID_SPACE, 0, vector); - - /* Register the TTY device */ - - /* Each IP-OCTAL channel is a TTY port */ - tty = alloc_tty_driver(NR_CHANNELS); - - if (!tty) { - res = -ENOMEM; - goto out_unregister_slot_unmap; - } - - /* Fill struct tty_driver with ipoctal data */ - tty->owner = THIS_MODULE; - tty->driver_name = "ipoctal"; - sprintf(name, "ipoctal.%d.%d.", bus_nr, slot); - tty->name = name; - tty->major = 0; - - tty->minor_start = 0; - tty->type = TTY_DRIVER_TYPE_SERIAL; - tty->subtype = SERIAL_TYPE_NORMAL; - tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty->init_termios = tty_std_termios; - tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->init_termios.c_ispeed = 9600; - tty->init_termios.c_ospeed = 9600; - - tty_set_operations(tty, &ipoctal_fops); - res = tty_register_driver(tty); - if (res) { - pr_err("Can't register tty driver.\n"); - put_tty_driver(tty); - goto out_unregister_slot_unmap; - } - - /* Save struct tty_driver for use it when uninstalling the device */ - ipoctal->tty_drv = tty; - - for (i = 0; i < NR_CHANNELS; i++) { - tty_port_init(&ipoctal->tty_port[i]); - tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]); - ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops; - - ipoctal_reset_stats(&ipoctal->chan_stats[i]); - ipoctal->nb_bytes[i] = 0; - init_waitqueue_head(&ipoctal->queue[i]); - ipoctal->error_flag[i] = UART_NOERROR; - - spin_lock_init(&ipoctal->lock[i]); - ipoctal->pointer_read[i] = 0; - ipoctal->pointer_write[i] = 0; - ipoctal->nb_bytes[i] = 0; - tty_register_device(tty, i, NULL); - - /* - * Enable again the RX. TX will be enabled when - * there is something to send - */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_ENABLE_RX); - } - - return 0; - -out_unregister_slot_unmap: - ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE); -out_unregister_io_space: - ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE); -out_unregister_id_space: - ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE); - return res; -} - -static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal, - unsigned int channel, - const unsigned char *buf, - int count) -{ - unsigned long flags; - int i; - unsigned int *pointer_read = &ipoctal->pointer_read[channel]; - - /* Copy the bytes from the user buffer to the internal one */ - for (i = 0; i < count; i++) { - if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) { - spin_lock_irqsave(&ipoctal->lock[channel], flags); - ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i]; - *pointer_read = (*pointer_read + 1) % PAGE_SIZE; - ipoctal->nb_bytes[channel]++; - spin_unlock_irqrestore(&ipoctal->lock[channel], flags); - } else { - break; - } - } - return i; -} - -static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel, - const unsigned char *buf, int count) -{ - ipoctal->nb_bytes[channel] = 0; - ipoctal->count_wr[channel] = 0; - - ipoctal_copy_write_buffer(ipoctal, channel, buf, count); - - ipoctal->error_flag[channel] = UART_NOERROR; - - /* As the IP-OCTAL 485 only supports half duplex, do it manually */ - if (ipoctal->board_id == IP_OCTAL_485_ID) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX); - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_ASSERT_RTSN); - } - - /* - * Send a packet and then disable TX to avoid failure after several send - * operations - */ - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_TX); - wait_event_interruptible(ipoctal->queue[channel], ipoctal->write); - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_TX); - - ipoctal->write = 0; - return ipoctal->count_wr[channel]; -} - -static int ipoctal_write_tty(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - unsigned int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - return ipoctal_write(ipoctal, channel, buf, count); -} - -static int ipoctal_write_room(struct tty_struct *tty) -{ - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - return PAGE_SIZE - ipoctal->nb_bytes[channel]; -} - -static int ipoctal_chars_in_buffer(struct tty_struct *tty) -{ - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - return ipoctal->nb_bytes[channel]; -} - -static void ipoctal_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - unsigned int cflag; - unsigned char mr1 = 0; - unsigned char mr2 = 0; - unsigned char csr = 0; - unsigned int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - speed_t baud; - - cflag = tty->termios->c_cflag; - - /* Disable and reset everything before change the setup */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_RX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_MR); - - /* Set Bits per chars */ - switch (cflag & CSIZE) { - case CS6: - mr1 |= MR1_CHRL_6_BITS; - break; - case CS7: - mr1 |= MR1_CHRL_7_BITS; - break; - case CS8: - default: - mr1 |= MR1_CHRL_8_BITS; - /* By default, select CS8 */ - tty->termios->c_cflag = (cflag & ~CSIZE) | CS8; - break; - } - - /* Set Parity */ - if (cflag & PARENB) - if (cflag & PARODD) - mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD; - else - mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN; - else - mr1 |= MR1_PARITY_OFF; - - /* Mark or space parity is not supported */ - tty->termios->c_cflag &= ~CMSPAR; - - /* Set stop bits */ - if (cflag & CSTOPB) - mr2 |= MR2_STOP_BITS_LENGTH_2; - else - mr2 |= MR2_STOP_BITS_LENGTH_1; - - /* Set the flow control */ - switch (ipoctal->board_id) { - case IP_OCTAL_232_ID: - if (cflag & CRTSCTS) { - mr1 |= MR1_RxRTS_CONTROL_ON; - mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON; - ipoctal->chan_config[channel].flow_control = 1; - } else { - mr1 |= MR1_RxRTS_CONTROL_OFF; - mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; - ipoctal->chan_config[channel].flow_control = 0; - } - break; - case IP_OCTAL_422_ID: - mr1 |= MR1_RxRTS_CONTROL_OFF; - mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; - ipoctal->chan_config[channel].flow_control = 0; - break; - case IP_OCTAL_485_ID: - mr1 |= MR1_RxRTS_CONTROL_OFF; - mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF; - ipoctal->chan_config[channel].flow_control = 0; - break; - default: - return; - break; - } - - baud = tty_get_baud_rate(tty); - tty_termios_encode_baud_rate(tty->termios, baud, baud); - - /* Set baud rate */ - switch (tty->termios->c_ospeed) { - case 75: - csr |= TX_CLK_75 | RX_CLK_75; - break; - case 110: - csr |= TX_CLK_110 | RX_CLK_110; - break; - case 150: - csr |= TX_CLK_150 | RX_CLK_150; - break; - case 300: - csr |= TX_CLK_300 | RX_CLK_300; - break; - case 600: - csr |= TX_CLK_600 | RX_CLK_600; - break; - case 1200: - csr |= TX_CLK_1200 | RX_CLK_1200; - break; - case 1800: - csr |= TX_CLK_1800 | RX_CLK_1800; - break; - case 2000: - csr |= TX_CLK_2000 | RX_CLK_2000; - break; - case 2400: - csr |= TX_CLK_2400 | RX_CLK_2400; - break; - case 4800: - csr |= TX_CLK_4800 | RX_CLK_4800; - break; - case 9600: - csr |= TX_CLK_9600 | RX_CLK_9600; - break; - case 19200: - csr |= TX_CLK_19200 | RX_CLK_19200; - break; - case 38400: - default: - csr |= TX_CLK_38400 | RX_CLK_38400; - /* In case of default, we establish 38400 bps */ - tty_termios_encode_baud_rate(tty->termios, 38400, 38400); - break; - } - - mr1 |= MR1_ERROR_CHAR; - mr1 |= MR1_RxINT_RxRDY; - - /* Write the control registers */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1); - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2); - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr); - - /* save the setup in the structure */ - ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty); - ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE; - ipoctal->chan_config[channel].parity = cflag & PARENB; - ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB; - - /* Enable again the RX */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); -} - -static void ipoctal_hangup(struct tty_struct *tty) -{ - unsigned long flags; - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - if (ipoctal == NULL) - return; - - spin_lock_irqsave(&ipoctal->lock[channel], flags); - ipoctal->nb_bytes[channel] = 0; - ipoctal->pointer_read[channel] = 0; - ipoctal->pointer_write[channel] = 0; - spin_unlock_irqrestore(&ipoctal->lock[channel], flags); - - tty_port_hangup(&ipoctal->tty_port[channel]); - - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_RX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_MR); - - clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags); - wake_up_interruptible(&ipoctal->tty_port[channel].open_wait); -} - -static const struct tty_operations ipoctal_fops = { - .ioctl = NULL, - .open = ipoctal_open, - .close = ipoctal_close, - .write = ipoctal_write_tty, - .set_termios = ipoctal_set_termios, - .write_room = ipoctal_write_room, - .chars_in_buffer = ipoctal_chars_in_buffer, - .get_icount = ipoctal_get_icount, - .hangup = ipoctal_hangup, -}; - -static int ipoctal_match(struct ipack_device *dev) -{ - int res; - unsigned char board_id; - - if ((!dev->bus->ops) || (!dev->bus->ops->map_space) || - (!dev->bus->ops->unmap_space)) - return 0; - - res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE); - if (res) - return 0; - - res = ipoctal_check_model(dev, &board_id); - dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE); - if (!res) - return 1; - - return 0; -} - -static int ipoctal_probe(struct ipack_device *dev) -{ - int res; - struct ipoctal *ipoctal; - - ipoctal = kzalloc(sizeof(struct ipoctal), GFP_KERNEL); - if (ipoctal == NULL) - return -ENOMEM; - - ipoctal->dev = dev; - res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq); - if (res) - goto out_uninst; - - list_add_tail(&ipoctal->list, &ipoctal_list); - return 0; - -out_uninst: - kfree(ipoctal); - return res; -} - -static void __ipoctal_remove(struct ipoctal *ipoctal) -{ - int i; - - for (i = 0; i < NR_CHANNELS; i++) { - tty_unregister_device(ipoctal->tty_drv, i); - tty_port_free_xmit_buf(&ipoctal->tty_port[i]); - } - - tty_unregister_driver(ipoctal->tty_drv); - put_tty_driver(ipoctal->tty_drv); - - /* Tell the carrier board to free all the resources for this device */ - if (ipoctal->dev->bus->ops->remove_device != NULL) - ipoctal->dev->bus->ops->remove_device(ipoctal->dev); - - list_del(&ipoctal->list); - kfree(ipoctal); -} - -static void ipoctal_remove(struct ipack_device *device) -{ - struct ipoctal *ipoctal, *next; - - list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) { - if (ipoctal->dev == device) - __ipoctal_remove(ipoctal); - } -} - -static struct ipack_driver_ops ipoctal_drv_ops = { - .match = ipoctal_match, - .probe = ipoctal_probe, - .remove = ipoctal_remove, -}; - -static int __init ipoctal_init(void) -{ - driver.ops = &ipoctal_drv_ops; - return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME); -} - -static void __exit ipoctal_exit(void) -{ - struct ipoctal *p, *next; - - list_for_each_entry_safe(p, next, &ipoctal_list, list) - __ipoctal_remove(p); - - ipack_driver_unregister(&driver); -} - -MODULE_DESCRIPTION("IP-Octal 232, 422 and 485 device driver"); -MODULE_LICENSE("GPL"); - -module_init(ipoctal_init); -module_exit(ipoctal_exit); diff --git a/drivers/staging/ipack/devices/ipoctal.h b/drivers/staging/ipack/devices/ipoctal.h deleted file mode 100644 index 266f3617069..00000000000 --- a/drivers/staging/ipack/devices/ipoctal.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * ipoctal.h - * - * driver for the IPOCTAL boards - * Copyright (c) 2009 Nicolas Serafini, EIC2 SA - * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#ifndef _IPOCTAL_H -#define _IPOCTAL_H_ - -#define NR_CHANNELS 8 -#define IPOCTAL_MAX_BOARDS 16 -#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS) -#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -/** - * enum uart_parity_e - UART supported parity. - */ -enum uart_parity_e { - UART_NONE = 0, - UART_ODD = 1, - UART_EVEN = 2, -}; - -/** - * enum uart_error - UART error type - * - */ -enum uart_error { - UART_NOERROR = 0, /* No error during transmission */ - UART_TIMEOUT = 1 << 0, /* Timeout error */ - UART_OVERRUN = 1 << 1, /* Overrun error */ - UART_PARITY = 1 << 2, /* Parity error */ - UART_FRAMING = 1 << 3, /* Framing error */ - UART_BREAK = 1 << 4, /* Received break */ -}; - -/** - * struct ipoctal_config - Serial configuration - * - * @baud: Baud rate - * @stop_bits: Stop bits (1 or 2) - * @bits_per_char: data size in bits - * @parity - * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled) - */ -struct ipoctal_config { - unsigned int baud; - unsigned int stop_bits; - unsigned int bits_per_char; - unsigned short parity; - unsigned int flow_control; -}; - -/** - * struct ipoctal_stats -- Stats since last reset - * - * @tx: Number of transmitted bytes - * @rx: Number of received bytes - * @overrun: Number of overrun errors - * @parity_err: Number of parity errors - * @framing_err: Number of framing errors - * @rcv_break: Number of break received - */ -struct ipoctal_stats { - unsigned long tx; - unsigned long rx; - unsigned long overrun_err; - unsigned long parity_err; - unsigned long framing_err; - unsigned long rcv_break; -}; - -#endif /* _IPOCTAL_H_ */ diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h deleted file mode 100644 index 47f6269985f..00000000000 --- a/drivers/staging/ipack/devices/scc2698.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * scc2698.h - * - * driver for the IPOCTAL boards - * Copyright (c) 2009 Nicolas Serafini, EIC2 SA - * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#ifndef SCC2698_H_ -#define SCC2698_H_ - -/* - * struct scc2698_channel - Channel access to scc2698 IO - * - * dn value are only spacer. - * - */ -struct scc2698_channel { - union { - struct { - unsigned char d0, mr; /* Mode register 1/2*/ - unsigned char d1, sr; /* Status register */ - unsigned char d2, r1; /* reserved */ - unsigned char d3, rhr; /* Receive holding register (R) */ - unsigned char junk[8]; /* other crap for block control */ - } r; /* Read access */ - struct { - unsigned char d0, mr; /* Mode register 1/2 */ - unsigned char d1, csr; /* Clock select register */ - unsigned char d2, cr; /* Command register */ - unsigned char d3, thr; /* Transmit holding register */ - unsigned char junk[8]; /* other crap for block control */ - } w; /* Write access */ - } u; -}; - -/* - * struct scc2698_block - Block access to scc2698 IO - * - * The scc2698 contain 4 block. - * Each block containt two channel a and b. - * dn value are only spacer. - * - */ -struct scc2698_block { - union { - struct { - unsigned char d0, mra; /* Mode register 1/2 (a) */ - unsigned char d1, sra; /* Status register (a) */ - unsigned char d2, r1; /* reserved */ - unsigned char d3, rhra; /* Receive holding register (a) */ - unsigned char d4, ipcr; /* Input port change register of block */ - unsigned char d5, isr; /* Interrupt status register of block */ - unsigned char d6, ctur; /* Counter timer upper register of block */ - unsigned char d7, ctlr; /* Counter timer lower register of block */ - unsigned char d8, mrb; /* Mode register 1/2 (b) */ - unsigned char d9, srb; /* Status register (b) */ - unsigned char da, r2; /* reserved */ - unsigned char db, rhrb; /* Receive holding register (b) */ - unsigned char dc, r3; /* reserved */ - unsigned char dd, ip; /* Input port register of block */ - unsigned char de, ctg; /* Start counter timer of block */ - unsigned char df, cts; /* Stop counter timer of block */ - } r; /* Read access */ - struct { - unsigned char d0, mra; /* Mode register 1/2 (a) */ - unsigned char d1, csra; /* Clock select register (a) */ - unsigned char d2, cra; /* Command register (a) */ - unsigned char d3, thra; /* Transmit holding register (a) */ - unsigned char d4, acr; /* Auxiliary control register of block */ - unsigned char d5, imr; /* Interrupt mask register of block */ - unsigned char d6, ctu; /* Counter timer upper register of block */ - unsigned char d7, ctl; /* Counter timer lower register of block */ - unsigned char d8, mrb; /* Mode register 1/2 (b) */ - unsigned char d9, csrb; /* Clock select register (a) */ - unsigned char da, crb; /* Command register (b) */ - unsigned char db, thrb; /* Transmit holding register (b) */ - unsigned char dc, r1; /* reserved */ - unsigned char dd, opcr; /* Output port configuration register of block */ - unsigned char de, r2; /* reserved */ - unsigned char df, r3; /* reserved */ - } w; /* Write access */ - } u; -} ; - -#define MR1_CHRL_5_BITS (0x0 << 0) -#define MR1_CHRL_6_BITS (0x1 << 0) -#define MR1_CHRL_7_BITS (0x2 << 0) -#define MR1_CHRL_8_BITS (0x3 << 0) -#define MR1_PARITY_EVEN (0x1 << 2) -#define MR1_PARITY_ODD (0x0 << 2) -#define MR1_PARITY_ON (0x0 << 3) -#define MR1_PARITY_FORCE (0x1 << 3) -#define MR1_PARITY_OFF (0x2 << 3) -#define MR1_PARITY_SPECIAL (0x3 << 3) -#define MR1_ERROR_CHAR (0x0 << 5) -#define MR1_ERROR_BLOCK (0x1 << 5) -#define MR1_RxINT_RxRDY (0x0 << 6) -#define MR1_RxINT_FFULL (0x1 << 6) -#define MR1_RxRTS_CONTROL_ON (0x1 << 7) -#define MR1_RxRTS_CONTROL_OFF (0x0 << 7) - -#define MR2_STOP_BITS_LENGTH_1 (0x7 << 0) -#define MR2_STOP_BITS_LENGTH_2 (0xF << 0) -#define MR2_CTS_ENABLE_TX_ON (0x1 << 4) -#define MR2_CTS_ENABLE_TX_OFF (0x0 << 4) -#define MR2_TxRTS_CONTROL_ON (0x1 << 5) -#define MR2_TxRTS_CONTROL_OFF (0x0 << 5) -#define MR2_CH_MODE_NORMAL (0x0 << 6) -#define MR2_CH_MODE_ECHO (0x1 << 6) -#define MR2_CH_MODE_LOCAL (0x2 << 6) -#define MR2_CH_MODE_REMOTE (0x3 << 6) - -#define CR_ENABLE_RX (0x1 << 0) -#define CR_DISABLE_RX (0x1 << 1) -#define CR_ENABLE_TX (0x1 << 2) -#define CR_DISABLE_TX (0x1 << 3) -#define CR_CMD_RESET_MR (0x1 << 4) -#define CR_CMD_RESET_RX (0x2 << 4) -#define CR_CMD_RESET_TX (0x3 << 4) -#define CR_CMD_RESET_ERR_STATUS (0x4 << 4) -#define CR_CMD_RESET_BREAK_CHANGE (0x5 << 4) -#define CR_CMD_START_BREAK (0x6 << 4) -#define CR_CMD_STOP_BREAK (0x7 << 4) -#define CR_CMD_ASSERT_RTSN (0x8 << 4) -#define CR_CMD_NEGATE_RTSN (0x9 << 4) -#define CR_CMD_SET_TIMEOUT_MODE (0xA << 4) -#define CR_CMD_DISABLE_TIMEOUT_MODE (0xC << 4) - -#define SR_RX_READY (0x1 << 0) -#define SR_FIFO_FULL (0x1 << 1) -#define SR_TX_READY (0x1 << 2) -#define SR_TX_EMPTY (0x1 << 3) -#define SR_OVERRUN_ERROR (0x1 << 4) -#define SR_PARITY_ERROR (0x1 << 5) -#define SR_FRAMING_ERROR (0x1 << 6) -#define SR_RECEIVED_BREAK (0x1 << 7) - -#define SR_ERROR (0xF0) - -#define ACR_DELTA_IP0_IRQ_EN (0x1 << 0) -#define ACR_DELTA_IP1_IRQ_EN (0x1 << 1) -#define ACR_DELTA_IP2_IRQ_EN (0x1 << 2) -#define ACR_DELTA_IP3_IRQ_EN (0x1 << 3) -#define ACR_CT_Mask (0x7 << 4) -#define ACR_CExt (0x0 << 4) -#define ACR_CTxCA (0x1 << 4) -#define ACR_CTxCB (0x2 << 4) -#define ACR_CClk16 (0x3 << 4) -#define ACR_TExt (0x4 << 4) -#define ACR_TExt16 (0x5 << 4) -#define ACR_TClk (0x6 << 4) -#define ACR_TClk16 (0x7 << 4) -#define ACR_BRG_SET1 (0x0 << 7) -#define ACR_BRG_SET2 (0x1 << 7) - -#define TX_CLK_75 (0x0 << 0) -#define TX_CLK_110 (0x1 << 0) -#define TX_CLK_38400 (0x2 << 0) -#define TX_CLK_150 (0x3 << 0) -#define TX_CLK_300 (0x4 << 0) -#define TX_CLK_600 (0x5 << 0) -#define TX_CLK_1200 (0x6 << 0) -#define TX_CLK_2000 (0x7 << 0) -#define TX_CLK_2400 (0x8 << 0) -#define TX_CLK_4800 (0x9 << 0) -#define TX_CLK_1800 (0xA << 0) -#define TX_CLK_9600 (0xB << 0) -#define TX_CLK_19200 (0xC << 0) -#define RX_CLK_75 (0x0 << 4) -#define RX_CLK_110 (0x1 << 4) -#define RX_CLK_38400 (0x2 << 4) -#define RX_CLK_150 (0x3 << 4) -#define RX_CLK_300 (0x4 << 4) -#define RX_CLK_600 (0x5 << 4) -#define RX_CLK_1200 (0x6 << 4) -#define RX_CLK_2000 (0x7 << 4) -#define RX_CLK_2400 (0x8 << 4) -#define RX_CLK_4800 (0x9 << 4) -#define RX_CLK_1800 (0xA << 4) -#define RX_CLK_9600 (0xB << 4) -#define RX_CLK_19200 (0xC << 4) - -#define OPCR_MPOa_RTSN (0x0 << 0) -#define OPCR_MPOa_C_TO (0x1 << 0) -#define OPCR_MPOa_TxC1X (0x2 << 0) -#define OPCR_MPOa_TxC16X (0x3 << 0) -#define OPCR_MPOa_RxC1X (0x4 << 0) -#define OPCR_MPOa_RxC16X (0x5 << 0) -#define OPCR_MPOa_TxRDY (0x6 << 0) -#define OPCR_MPOa_RxRDY_FF (0x7 << 0) - -#define OPCR_MPOb_RTSN (0x0 << 4) -#define OPCR_MPOb_C_TO (0x1 << 4) -#define OPCR_MPOb_TxC1X (0x2 << 4) -#define OPCR_MPOb_TxC16X (0x3 << 4) -#define OPCR_MPOb_RxC1X (0x4 << 4) -#define OPCR_MPOb_RxC16X (0x5 << 4) -#define OPCR_MPOb_TxRDY (0x6 << 4) -#define OPCR_MPOb_RxRDY_FF (0x7 << 4) - -#define OPCR_MPP_INPUT (0x0 << 7) -#define OPCR_MPP_OUTPUT (0x1 << 7) - -#define IMR_TxRDY_A (0x1 << 0) -#define IMR_RxRDY_FFULL_A (0x1 << 1) -#define IMR_DELTA_BREAK_A (0x1 << 2) -#define IMR_COUNTER_READY (0x1 << 3) -#define IMR_TxRDY_B (0x1 << 4) -#define IMR_RxRDY_FFULL_B (0x1 << 5) -#define IMR_DELTA_BREAK_B (0x1 << 6) -#define IMR_INPUT_PORT_CHANGE (0x1 << 7) - -#define ISR_TxRDY_A (0x1 << 0) -#define ISR_RxRDY_FFULL_A (0x1 << 1) -#define ISR_DELTA_BREAK_A (0x1 << 2) -#define ISR_COUNTER_READY (0x1 << 3) -#define ISR_TxRDY_B (0x1 << 4) -#define ISR_RxRDY_FFULL_B (0x1 << 5) -#define ISR_DELTA_BREAK_B (0x1 << 6) -#define ISR_INPUT_PORT_CHANGE (0x1 << 7) - -#endif /* SCC2698_H_ */ diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c deleted file mode 100644 index 2b4fa51bf16..00000000000 --- a/drivers/staging/ipack/ipack.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Industry-pack bus support functions. - * - * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include "ipack.h" - -#define to_ipack_dev(device) container_of(device, struct ipack_device, dev) -#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver) - -/* used when allocating bus numbers */ -#define IPACK_MAXBUS 64 - -static DEFINE_MUTEX(ipack_mutex); - -struct ipack_busmap { - unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))]; -}; -static struct ipack_busmap busmap; - -static void ipack_device_release(struct device *dev) -{ - struct ipack_device *device = to_ipack_dev(dev); - kfree(device); -} - -static int ipack_bus_match(struct device *device, struct device_driver *driver) -{ - int ret; - struct ipack_device *dev = to_ipack_dev(device); - struct ipack_driver *drv = to_ipack_driver(driver); - - if ((!drv->ops) || (!drv->ops->match)) - return -EINVAL; - - ret = drv->ops->match(dev); - if (ret) - dev->driver = drv; - - return 0; -} - -static int ipack_bus_probe(struct device *device) -{ - struct ipack_device *dev = to_ipack_dev(device); - - if (!dev->driver->ops->probe) - return -EINVAL; - - return dev->driver->ops->probe(dev); -} - -static int ipack_bus_remove(struct device *device) -{ - struct ipack_device *dev = to_ipack_dev(device); - - if (!dev->driver->ops->remove) - return -EINVAL; - - dev->driver->ops->remove(dev); - return 0; -} - -static struct bus_type ipack_bus_type = { - .name = "ipack", - .probe = ipack_bus_probe, - .match = ipack_bus_match, - .remove = ipack_bus_remove, -}; - -static int ipack_assign_bus_number(void) -{ - int busnum; - - mutex_lock(&ipack_mutex); - busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1); - - if (busnum >= IPACK_MAXBUS) { - pr_err("too many buses\n"); - busnum = -1; - goto error_find_busnum; - } - - set_bit(busnum, busmap.busmap); - -error_find_busnum: - mutex_unlock(&ipack_mutex); - return busnum; -} - -struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, - struct ipack_bus_ops *ops) -{ - int bus_nr; - struct ipack_bus_device *bus; - - bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL); - if (!bus) - return NULL; - - bus_nr = ipack_assign_bus_number(); - if (bus_nr < 0) { - kfree(bus); - return NULL; - } - - bus->bus_nr = bus_nr; - bus->parent = parent; - bus->slots = slots; - bus->ops = ops; - return bus; -} -EXPORT_SYMBOL_GPL(ipack_bus_register); - -int ipack_bus_unregister(struct ipack_bus_device *bus) -{ - mutex_lock(&ipack_mutex); - clear_bit(bus->bus_nr, busmap.busmap); - mutex_unlock(&ipack_mutex); - kfree(bus); - return 0; -} -EXPORT_SYMBOL_GPL(ipack_bus_unregister); - -int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, - char *name) -{ - edrv->driver.owner = owner; - edrv->driver.name = name; - edrv->driver.bus = &ipack_bus_type; - return driver_register(&edrv->driver); -} -EXPORT_SYMBOL_GPL(ipack_driver_register); - -void ipack_driver_unregister(struct ipack_driver *edrv) -{ - driver_unregister(&edrv->driver); -} -EXPORT_SYMBOL_GPL(ipack_driver_unregister); - -struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, - int slot, int irqv) -{ - int ret; - struct ipack_device *dev; - - dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL); - if (!dev) - return NULL; - - dev->dev.bus = &ipack_bus_type; - dev->dev.release = ipack_device_release; - dev->dev.parent = bus->parent; - dev->slot = slot; - dev->bus_nr = bus->bus_nr; - dev->irq = irqv; - dev->bus = bus; - dev_set_name(&dev->dev, - "ipack-dev.%u.%u", dev->bus_nr, dev->slot); - - ret = device_register(&dev->dev); - if (ret < 0) { - pr_err("error registering the device.\n"); - dev->driver->ops->remove(dev); - kfree(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL_GPL(ipack_device_register); - -void ipack_device_unregister(struct ipack_device *dev) -{ - device_unregister(&dev->dev); -} -EXPORT_SYMBOL_GPL(ipack_device_unregister); - -static int __init ipack_init(void) -{ - return bus_register(&ipack_bus_type); -} - -static void __exit ipack_exit(void) -{ - bus_unregister(&ipack_bus_type); -} - -module_init(ipack_init); -module_exit(ipack_exit); - -MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Industry-pack bus core"); diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h deleted file mode 100644 index 8bc001e3ca4..00000000000 --- a/drivers/staging/ipack/ipack.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Industry-pack bus. - * - * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN - * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia - * - * 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; version 2 of the License. - */ - -#include <linux/device.h> - -#define IPACK_IDPROM_OFFSET_I 0x01 -#define IPACK_IDPROM_OFFSET_P 0x03 -#define IPACK_IDPROM_OFFSET_A 0x05 -#define IPACK_IDPROM_OFFSET_C 0x07 -#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID 0x09 -#define IPACK_IDPROM_OFFSET_MODEL 0x0B -#define IPACK_IDPROM_OFFSET_REVISION 0x0D -#define IPACK_IDPROM_OFFSET_RESERVED 0x0F -#define IPACK_IDPROM_OFFSET_DRIVER_ID_L 0x11 -#define IPACK_IDPROM_OFFSET_DRIVER_ID_H 0x13 -#define IPACK_IDPROM_OFFSET_NUM_BYTES 0x15 -#define IPACK_IDPROM_OFFSET_CRC 0x17 - -struct ipack_bus_ops; -struct ipack_driver; - -enum ipack_space { - IPACK_IO_SPACE = 0, - IPACK_ID_SPACE = 1, - IPACK_MEM_SPACE = 2, -}; - -/** - * struct ipack_addr_space - Virtual address space mapped for a specified type. - * - * @address: virtual address - * @size: size of the mapped space - */ -struct ipack_addr_space { - void __iomem *address; - unsigned int size; -}; - -/** - * struct ipack_device - * - * @bus_nr: IP bus number where the device is plugged - * @slot: Slot where the device is plugged in the carrier board - * @irq: IRQ vector - * @driver: Pointer to the ipack_driver that manages the device - * @bus: ipack_bus_device where the device is plugged to. - * @id_space: Virtual address to ID space. - * @io_space: Virtual address to IO space. - * @mem_space: Virtual address to MEM space. - * @dev: device in kernel representation. - * - * Warning: Direct access to mapped memory is possible but the endianness - * is not the same with PCI carrier or VME carrier. The endianness is managed - * by the carrier board throught bus->ops. - */ -struct ipack_device { - unsigned int bus_nr; - unsigned int slot; - unsigned int irq; - struct ipack_driver *driver; - struct ipack_bus_device *bus; - struct ipack_addr_space id_space; - struct ipack_addr_space io_space; - struct ipack_addr_space mem_space; - struct device dev; -}; - -/** - * struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device - * - * @match: Match function - * @probe: Probe function - * @remove: tell the driver that the carrier board wants to remove one device - */ - -struct ipack_driver_ops { - int (*match) (struct ipack_device *dev); - int (*probe) (struct ipack_device *dev); - void (*remove) (struct ipack_device *dev); -}; - -/** - * struct ipack_driver -- Specific data to each ipack board driver - * - * @driver: Device driver kernel representation - * @ops: Mezzanine driver operations specific for the ipack bus. - */ -struct ipack_driver { - struct device_driver driver; - struct ipack_driver_ops *ops; -}; - -/** - * struct ipack_bus_ops - available operations on a bridge module - * - * @map_space: map IP address space - * @unmap_space: unmap IP address space - * @request_irq: request IRQ - * @free_irq: free IRQ - * @read8: read unsigned char - * @read16: read unsigned short - * @read32: read unsigned int - * @write8: read unsigned char - * @write16: read unsigned short - * @write32: read unsigned int - * @remove_device: tell the bridge module that the device has been removed - */ -struct ipack_bus_ops { - int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space); - int (*unmap_space) (struct ipack_device *dev, int space); - int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg); - int (*free_irq) (struct ipack_device *dev); - int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value); - int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value); - int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value); - int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value); - int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value); - int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value); - int (*remove_device) (struct ipack_device *dev); -}; - -/** - * struct ipack_bus_device - * - * @dev: pointer to carrier device - * @slots: number of slots available - * @bus_nr: ipack bus number - * @ops: bus operations for the mezzanine drivers - */ -struct ipack_bus_device { - struct device *parent; - int slots; - int bus_nr; - struct ipack_bus_ops *ops; -}; - -/** - * ipack_bus_register -- register a new ipack bus - * - * @parent: pointer to the parent device, if any. - * @slots: number of slots available in the bus device. - * @ops: bus operations for the mezzanine drivers. - * - * The carrier board device should call this function to register itself as - * available bus device in ipack. - */ -struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, - struct ipack_bus_ops *ops); - -/** - * ipack_bus_unregister -- unregister an ipack bus - */ -int ipack_bus_unregister(struct ipack_bus_device *bus); - -/** - * ipack_driver_register -- Register a new driver - * - * Called by a ipack driver to register itself as a driver - * that can manage ipack devices. - */ -int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name); -void ipack_driver_unregister(struct ipack_driver *edrv); - -/** - * ipack_device_register -- register a new mezzanine device - * - * @bus: ipack bus device it is plugged to. - * @slot: slot position in the bus device. - * @irqv: IRQ vector for the mezzanine. - * - * Register a new ipack device (mezzanine device). The call is done by - * the carrier device driver. - */ -struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv); -void ipack_device_unregister(struct ipack_device *dev); |
