diff options
Diffstat (limited to 'drivers')
44 files changed, 1537 insertions, 1057 deletions
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 7c88c060a9e6..46685a540772 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | config AGP | 1 | config AGP |
| 2 | tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU | 2 | tristate "/dev/agpgart (AGP Support)" |
| 3 | depends on ALPHA || IA64 || PPC || X86 | 3 | depends on ALPHA || IA64 || PPC || X86 |
| 4 | default y if GART_IOMMU | ||
| 5 | ---help--- | 4 | ---help--- |
| 6 | AGP (Accelerated Graphics Port) is a bus system mainly used to | 5 | AGP (Accelerated Graphics Port) is a bus system mainly used to |
| 7 | connect graphics cards to the rest of the system. | 6 | connect graphics cards to the rest of the system. |
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e1feb58bd661..1a2b9785e998 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
| @@ -2120,7 +2120,7 @@ abort_linearize: | |||
| 2120 | goto drop; | 2120 | goto drop; |
| 2121 | } | 2121 | } |
| 2122 | 2122 | ||
| 2123 | if (skb_linearize(skb, GFP_ATOMIC)) | 2123 | if (skb_linearize(skb)) |
| 2124 | goto drop; | 2124 | goto drop; |
| 2125 | 2125 | ||
| 2126 | mgp->tx_linearized++; | 2126 | mgp->tx_linearized++; |
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
| @@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o | |||
| 26 | obj-$(CONFIG_PPC64) += setup-bus.o | 26 | obj-$(CONFIG_PPC64) += setup-bus.o |
| 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o | 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o |
| 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o | 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o |
| 29 | obj-$(CONFIG_PCI_MSI) += msi.o | 29 | |
| 30 | msiobj-y := msi.o msi-apic.o | ||
| 31 | msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o | ||
| 32 | msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o | ||
| 33 | obj-$(CONFIG_PCI_MSI) += $(msiobj-y) | ||
| 30 | 34 | ||
| 31 | # | 35 | # |
| 32 | # ACPI Related PCI FW Functions | 36 | # ACPI Related PCI FW Functions |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index eed67d9e73bc..723092682023 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
| @@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) | |||
| 81 | { | 81 | { |
| 82 | device_add(&dev->dev); | 82 | device_add(&dev->dev); |
| 83 | 83 | ||
| 84 | spin_lock(&pci_bus_lock); | 84 | down_write(&pci_bus_sem); |
| 85 | list_add_tail(&dev->global_list, &pci_devices); | 85 | list_add_tail(&dev->global_list, &pci_devices); |
| 86 | spin_unlock(&pci_bus_lock); | 86 | up_write(&pci_bus_sem); |
| 87 | 87 | ||
| 88 | pci_proc_attach_device(dev); | 88 | pci_proc_attach_device(dev); |
| 89 | pci_create_sysfs_dev_files(dev); | 89 | pci_create_sysfs_dev_files(dev); |
| @@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) | |||
| 125 | */ | 125 | */ |
| 126 | if (dev->subordinate) { | 126 | if (dev->subordinate) { |
| 127 | if (list_empty(&dev->subordinate->node)) { | 127 | if (list_empty(&dev->subordinate->node)) { |
| 128 | spin_lock(&pci_bus_lock); | 128 | down_write(&pci_bus_sem); |
| 129 | list_add_tail(&dev->subordinate->node, | 129 | list_add_tail(&dev->subordinate->node, |
| 130 | &dev->bus->children); | 130 | &dev->bus->children); |
| 131 | spin_unlock(&pci_bus_lock); | 131 | up_write(&pci_bus_sem); |
| 132 | } | 132 | } |
| 133 | pci_bus_add_devices(dev->subordinate); | 133 | pci_bus_add_devices(dev->subordinate); |
| 134 | 134 | ||
| @@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
| 168 | struct list_head *next; | 168 | struct list_head *next; |
| 169 | 169 | ||
| 170 | bus = top; | 170 | bus = top; |
| 171 | spin_lock(&pci_bus_lock); | 171 | down_read(&pci_bus_sem); |
| 172 | next = top->devices.next; | 172 | next = top->devices.next; |
| 173 | for (;;) { | 173 | for (;;) { |
| 174 | if (next == &bus->devices) { | 174 | if (next == &bus->devices) { |
| @@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
| 180 | continue; | 180 | continue; |
| 181 | } | 181 | } |
| 182 | dev = list_entry(next, struct pci_dev, bus_list); | 182 | dev = list_entry(next, struct pci_dev, bus_list); |
| 183 | pci_dev_get(dev); | ||
| 184 | if (dev->subordinate) { | 183 | if (dev->subordinate) { |
| 185 | /* this is a pci-pci bridge, do its devices next */ | 184 | /* this is a pci-pci bridge, do its devices next */ |
| 186 | next = dev->subordinate->devices.next; | 185 | next = dev->subordinate->devices.next; |
| 187 | bus = dev->subordinate; | 186 | bus = dev->subordinate; |
| 188 | } else | 187 | } else |
| 189 | next = dev->bus_list.next; | 188 | next = dev->bus_list.next; |
| 190 | spin_unlock(&pci_bus_lock); | ||
| 191 | 189 | ||
| 192 | /* Run device routines with the bus unlocked */ | 190 | /* Run device routines with the device locked */ |
| 191 | down(&dev->dev.sem); | ||
| 193 | cb(dev, userdata); | 192 | cb(dev, userdata); |
| 194 | 193 | up(&dev->dev.sem); | |
| 195 | spin_lock(&pci_bus_lock); | ||
| 196 | pci_dev_put(dev); | ||
| 197 | } | 194 | } |
| 198 | spin_unlock(&pci_bus_lock); | 195 | up_read(&pci_bus_sem); |
| 199 | } | 196 | } |
| 200 | EXPORT_SYMBOL_GPL(pci_walk_bus); | 197 | EXPORT_SYMBOL_GPL(pci_walk_bus); |
| 201 | 198 | ||
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..bed4183a5e39 --- /dev/null +++ b/drivers/pci/msi-altix.c | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/pci.h> | ||
| 11 | #include <linux/cpumask.h> | ||
| 12 | |||
| 13 | #include <asm/sn/addrs.h> | ||
| 14 | #include <asm/sn/intr.h> | ||
| 15 | #include <asm/sn/pcibus_provider_defs.h> | ||
| 16 | #include <asm/sn/pcidev.h> | ||
| 17 | #include <asm/sn/nodepda.h> | ||
| 18 | |||
| 19 | #include "msi.h" | ||
| 20 | |||
| 21 | struct sn_msi_info { | ||
| 22 | u64 pci_addr; | ||
| 23 | struct sn_irq_info *sn_irq_info; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct sn_msi_info *sn_msi_info; | ||
| 27 | |||
| 28 | static void | ||
| 29 | sn_msi_teardown(unsigned int vector) | ||
| 30 | { | ||
| 31 | nasid_t nasid; | ||
| 32 | int widget; | ||
| 33 | struct pci_dev *pdev; | ||
| 34 | struct pcidev_info *sn_pdev; | ||
| 35 | struct sn_irq_info *sn_irq_info; | ||
| 36 | struct pcibus_bussoft *bussoft; | ||
| 37 | struct sn_pcibus_provider *provider; | ||
| 38 | |||
| 39 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
| 40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
| 41 | return; | ||
| 42 | |||
| 43 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
| 44 | pdev = sn_pdev->pdi_linux_pcidev; | ||
| 45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 46 | |||
| 47 | (*provider->dma_unmap)(pdev, | ||
| 48 | sn_msi_info[vector].pci_addr, | ||
| 49 | PCI_DMA_FROMDEVICE); | ||
| 50 | sn_msi_info[vector].pci_addr = 0; | ||
| 51 | |||
| 52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
| 53 | nasid = NASID_GET(bussoft->bs_base); | ||
| 54 | widget = (nasid & 1) ? | ||
| 55 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
| 56 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
| 57 | |||
| 58 | sn_intr_free(nasid, widget, sn_irq_info); | ||
| 59 | sn_msi_info[vector].sn_irq_info = NULL; | ||
| 60 | |||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | int | ||
| 65 | sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | ||
| 66 | u32 *addr_hi, u32 *addr_lo, u32 *data) | ||
| 67 | { | ||
| 68 | int widget; | ||
| 69 | int status; | ||
| 70 | nasid_t nasid; | ||
| 71 | u64 bus_addr; | ||
| 72 | struct sn_irq_info *sn_irq_info; | ||
| 73 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
| 74 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 75 | |||
| 76 | if (bussoft == NULL) | ||
| 77 | return -EINVAL; | ||
| 78 | |||
| 79 | if (provider == NULL || provider->dma_map_consistent == NULL) | ||
| 80 | return -EINVAL; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Set up the vector plumbing. Let the prom (via sn_intr_alloc) | ||
| 84 | * decide which cpu to direct this msi at by default. | ||
| 85 | */ | ||
| 86 | |||
| 87 | nasid = NASID_GET(bussoft->bs_base); | ||
| 88 | widget = (nasid & 1) ? | ||
| 89 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
| 90 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
| 91 | |||
| 92 | sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | ||
| 93 | if (! sn_irq_info) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 96 | status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); | ||
| 97 | if (status) { | ||
| 98 | kfree(sn_irq_info); | ||
| 99 | return -ENOMEM; | ||
| 100 | } | ||
| 101 | |||
| 102 | sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ | ||
| 103 | sn_irq_fixup(pdev, sn_irq_info); | ||
| 104 | |||
| 105 | /* Prom probably should fill these in, but doesn't ... */ | ||
| 106 | sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; | ||
| 107 | sn_irq_info->irq_bridge = (void *)bussoft->bs_base; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Map the xio address into bus space | ||
| 111 | */ | ||
| 112 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
| 113 | sn_irq_info->irq_xtalkaddr, | ||
| 114 | sizeof(sn_irq_info->irq_xtalkaddr), | ||
| 115 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
| 116 | if (! bus_addr) { | ||
| 117 | sn_intr_free(nasid, widget, sn_irq_info); | ||
| 118 | kfree(sn_irq_info); | ||
| 119 | return -ENOMEM; | ||
| 120 | } | ||
| 121 | |||
| 122 | sn_msi_info[vector].sn_irq_info = sn_irq_info; | ||
| 123 | sn_msi_info[vector].pci_addr = bus_addr; | ||
| 124 | |||
| 125 | *addr_hi = (u32)(bus_addr >> 32); | ||
| 126 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
| 127 | |||
| 128 | /* | ||
| 129 | * In the SN platform, bit 16 is a "send vector" bit which | ||
| 130 | * must be present in order to move the vector through the system. | ||
| 131 | */ | ||
| 132 | *data = 0x100 + (unsigned int)vector; | ||
| 133 | |||
| 134 | #ifdef CONFIG_SMP | ||
| 135 | set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); | ||
| 136 | #endif | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static void | ||
| 142 | sn_msi_target(unsigned int vector, unsigned int cpu, | ||
| 143 | u32 *addr_hi, u32 *addr_lo) | ||
| 144 | { | ||
| 145 | int slice; | ||
| 146 | nasid_t nasid; | ||
| 147 | u64 bus_addr; | ||
| 148 | struct pci_dev *pdev; | ||
| 149 | struct pcidev_info *sn_pdev; | ||
| 150 | struct sn_irq_info *sn_irq_info; | ||
| 151 | struct sn_irq_info *new_irq_info; | ||
| 152 | struct sn_pcibus_provider *provider; | ||
| 153 | |||
| 154 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
| 155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
| 156 | return; | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Release XIO resources for the old MSI PCI address | ||
| 160 | */ | ||
| 161 | |||
| 162 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
| 163 | pdev = sn_pdev->pdi_linux_pcidev; | ||
| 164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 165 | |||
| 166 | bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); | ||
| 167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | ||
| 168 | sn_msi_info[vector].pci_addr = 0; | ||
| 169 | |||
| 170 | nasid = cpuid_to_nasid(cpu); | ||
| 171 | slice = cpuid_to_slice(cpu); | ||
| 172 | |||
| 173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | ||
| 174 | sn_msi_info[vector].sn_irq_info = new_irq_info; | ||
| 175 | if (new_irq_info == NULL) | ||
| 176 | return; | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Map the xio address into bus space | ||
| 180 | */ | ||
| 181 | |||
| 182 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
| 183 | new_irq_info->irq_xtalkaddr, | ||
| 184 | sizeof(new_irq_info->irq_xtalkaddr), | ||
| 185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
| 186 | |||
| 187 | sn_msi_info[vector].pci_addr = bus_addr; | ||
| 188 | *addr_hi = (u32)(bus_addr >> 32); | ||
| 189 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
| 190 | } | ||
| 191 | |||
| 192 | struct msi_ops sn_msi_ops = { | ||
| 193 | .setup = sn_msi_setup, | ||
| 194 | .teardown = sn_msi_teardown, | ||
| 195 | #ifdef CONFIG_SMP | ||
| 196 | .target = sn_msi_target, | ||
| 197 | #endif | ||
| 198 | }; | ||
| 199 | |||
| 200 | int | ||
| 201 | sn_msi_init(void) | ||
| 202 | { | ||
| 203 | sn_msi_info = | ||
| 204 | kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); | ||
| 205 | if (! sn_msi_info) | ||
| 206 | return -ENOMEM; | ||
| 207 | |||
| 208 | msi_register(&sn_msi_ops); | ||
| 209 | return 0; | ||
| 210 | } | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * MSI hooks for standard x86 apic | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/pci.h> | ||
| 6 | #include <linux/irq.h> | ||
| 7 | |||
| 8 | #include "msi.h" | ||
| 9 | |||
| 10 | /* | ||
| 11 | * Shifts for APIC-based data | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define MSI_DATA_VECTOR_SHIFT 0 | ||
| 15 | #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) | ||
| 16 | |||
| 17 | #define MSI_DATA_DELIVERY_SHIFT 8 | ||
| 18 | #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) | ||
| 19 | #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) | ||
| 20 | |||
| 21 | #define MSI_DATA_LEVEL_SHIFT 14 | ||
| 22 | #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | ||
| 23 | #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | ||
| 24 | |||
| 25 | #define MSI_DATA_TRIGGER_SHIFT 15 | ||
| 26 | #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | ||
| 27 | #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Shift/mask fields for APIC-based bus address | ||
| 31 | */ | ||
| 32 | |||
| 33 | #define MSI_ADDR_HEADER 0xfee00000 | ||
| 34 | |||
| 35 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | ||
| 36 | #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) | ||
| 37 | |||
| 38 | #define MSI_ADDR_DESTMODE_SHIFT 2 | ||
| 39 | #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) | ||
| 40 | #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) | ||
| 41 | |||
| 42 | #define MSI_ADDR_REDIRECTION_SHIFT 3 | ||
| 43 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | ||
| 44 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | ||
| 45 | |||
| 46 | |||
| 47 | static void | ||
| 48 | msi_target_apic(unsigned int vector, | ||
| 49 | unsigned int dest_cpu, | ||
| 50 | u32 *address_hi, /* in/out */ | ||
| 51 | u32 *address_lo) /* in/out */ | ||
| 52 | { | ||
| 53 | u32 addr = *address_lo; | ||
| 54 | |||
| 55 | addr &= MSI_ADDR_DESTID_MASK; | ||
| 56 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); | ||
| 57 | |||
| 58 | *address_lo = addr; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int | ||
| 62 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | ||
| 63 | unsigned int vector, | ||
| 64 | u32 *address_hi, | ||
| 65 | u32 *address_lo, | ||
| 66 | u32 *data) | ||
| 67 | { | ||
| 68 | unsigned long dest_phys_id; | ||
| 69 | |||
| 70 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | ||
| 71 | |||
| 72 | *address_hi = 0; | ||
| 73 | *address_lo = MSI_ADDR_HEADER | | ||
| 74 | MSI_ADDR_DESTMODE_PHYS | | ||
| 75 | MSI_ADDR_REDIRECTION_CPU | | ||
| 76 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
| 77 | |||
| 78 | *data = MSI_DATA_TRIGGER_EDGE | | ||
| 79 | MSI_DATA_LEVEL_ASSERT | | ||
| 80 | MSI_DATA_DELIVERY_FIXED | | ||
| 81 | MSI_DATA_VECTOR(vector); | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void | ||
| 87 | msi_teardown_apic(unsigned int vector) | ||
| 88 | { | ||
| 89 | return; /* no-op */ | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Generic ops used on most IA archs/platforms. Set with msi_register() | ||
| 94 | */ | ||
| 95 | |||
| 96 | struct msi_ops msi_apic_ops = { | ||
| 97 | .setup = msi_setup_apic, | ||
| 98 | .teardown = msi_teardown_apic, | ||
| 99 | .target = msi_target_apic, | ||
| 100 | }; | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | #include "pci.h" | 23 | #include "pci.h" |
| 24 | #include "msi.h" | 24 | #include "msi.h" |
| 25 | 25 | ||
| 26 | #define MSI_TARGET_CPU first_cpu(cpu_online_map) | ||
| 27 | |||
| 28 | static DEFINE_SPINLOCK(msi_lock); | 26 | static DEFINE_SPINLOCK(msi_lock); |
| 29 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | 27 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; |
| 30 | static kmem_cache_t* msi_cachep; | 28 | static kmem_cache_t* msi_cachep; |
| @@ -37,9 +35,17 @@ static int nr_msix_devices; | |||
| 37 | 35 | ||
| 38 | #ifndef CONFIG_X86_IO_APIC | 36 | #ifndef CONFIG_X86_IO_APIC |
| 39 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 37 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; |
| 40 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | ||
| 41 | #endif | 38 | #endif |
| 42 | 39 | ||
| 40 | static struct msi_ops *msi_ops; | ||
| 41 | |||
| 42 | int | ||
| 43 | msi_register(struct msi_ops *ops) | ||
| 44 | { | ||
| 45 | msi_ops = ops; | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 43 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) | 49 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) |
| 44 | { | 50 | { |
| 45 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); | 51 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); |
| @@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
| 92 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 98 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) |
| 93 | { | 99 | { |
| 94 | struct msi_desc *entry; | 100 | struct msi_desc *entry; |
| 95 | struct msg_address address; | 101 | u32 address_hi, address_lo; |
| 96 | unsigned int irq = vector; | 102 | unsigned int irq = vector; |
| 97 | unsigned int dest_cpu = first_cpu(cpu_mask); | 103 | unsigned int dest_cpu = first_cpu(cpu_mask); |
| 98 | 104 | ||
| @@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | |||
| 108 | if (!pos) | 114 | if (!pos) |
| 109 | return; | 115 | return; |
| 110 | 116 | ||
| 117 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | ||
| 118 | &address_hi); | ||
| 111 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 119 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 112 | &address.lo_address.value); | 120 | &address_lo); |
| 113 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 121 | |
| 114 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 122 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); |
| 115 | MSI_TARGET_CPU_SHIFT); | 123 | |
| 116 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 124 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), |
| 125 | address_hi); | ||
| 117 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | 126 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 118 | address.lo_address.value); | 127 | address_lo); |
| 119 | set_native_irq_info(irq, cpu_mask); | 128 | set_native_irq_info(irq, cpu_mask); |
| 120 | break; | 129 | break; |
| 121 | } | 130 | } |
| 122 | case PCI_CAP_ID_MSIX: | 131 | case PCI_CAP_ID_MSIX: |
| 123 | { | 132 | { |
| 124 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 133 | int offset_hi = |
| 125 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 134 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 126 | 135 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | |
| 127 | address.lo_address.value = readl(entry->mask_base + offset); | 136 | int offset_lo = |
| 128 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 137 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 129 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 138 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; |
| 130 | MSI_TARGET_CPU_SHIFT); | 139 | |
| 131 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 140 | address_hi = readl(entry->mask_base + offset_hi); |
| 132 | writel(address.lo_address.value, entry->mask_base + offset); | 141 | address_lo = readl(entry->mask_base + offset_lo); |
| 142 | |||
| 143 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
| 144 | |||
| 145 | writel(address_hi, entry->mask_base + offset_hi); | ||
| 146 | writel(address_lo, entry->mask_base + offset_lo); | ||
| 133 | set_native_irq_info(irq, cpu_mask); | 147 | set_native_irq_info(irq, cpu_mask); |
| 134 | break; | 148 | break; |
| 135 | } | 149 | } |
| @@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { | |||
| 251 | .set_affinity = set_msi_affinity | 265 | .set_affinity = set_msi_affinity |
| 252 | }; | 266 | }; |
| 253 | 267 | ||
| 254 | static void msi_data_init(struct msg_data *msi_data, | ||
| 255 | unsigned int vector) | ||
| 256 | { | ||
| 257 | memset(msi_data, 0, sizeof(struct msg_data)); | ||
| 258 | msi_data->vector = (u8)vector; | ||
| 259 | msi_data->delivery_mode = MSI_DELIVERY_MODE; | ||
| 260 | msi_data->level = MSI_LEVEL_MODE; | ||
| 261 | msi_data->trigger = MSI_TRIGGER_MODE; | ||
| 262 | } | ||
| 263 | |||
| 264 | static void msi_address_init(struct msg_address *msi_address) | ||
| 265 | { | ||
| 266 | unsigned int dest_id; | ||
| 267 | unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); | ||
| 268 | |||
| 269 | memset(msi_address, 0, sizeof(struct msg_address)); | ||
| 270 | msi_address->hi_address = (u32)0; | ||
| 271 | dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); | ||
| 272 | msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; | ||
| 273 | msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; | ||
| 274 | msi_address->lo_address.u.dest_id = dest_id; | ||
| 275 | msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); | 268 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); |
| 279 | static int assign_msi_vector(void) | 269 | static int assign_msi_vector(void) |
| 280 | { | 270 | { |
| @@ -369,13 +359,29 @@ static int msi_init(void) | |||
| 369 | return status; | 359 | return status; |
| 370 | } | 360 | } |
| 371 | 361 | ||
| 362 | status = msi_arch_init(); | ||
| 363 | if (status < 0) { | ||
| 364 | pci_msi_enable = 0; | ||
| 365 | printk(KERN_WARNING | ||
| 366 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
| 367 | return status; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (! msi_ops) { | ||
| 371 | printk(KERN_WARNING | ||
| 372 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
| 373 | status = -EINVAL; | ||
| 374 | return status; | ||
| 375 | } | ||
| 376 | |||
| 377 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | ||
| 372 | status = msi_cache_init(); | 378 | status = msi_cache_init(); |
| 373 | if (status < 0) { | 379 | if (status < 0) { |
| 374 | pci_msi_enable = 0; | 380 | pci_msi_enable = 0; |
| 375 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | 381 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); |
| 376 | return status; | 382 | return status; |
| 377 | } | 383 | } |
| 378 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | 384 | |
| 379 | if (last_alloc_vector < 0) { | 385 | if (last_alloc_vector < 0) { |
| 380 | pci_msi_enable = 0; | 386 | pci_msi_enable = 0; |
| 381 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); | 387 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); |
| @@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 442 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 448 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 443 | msi_enable(control, 1); | 449 | msi_enable(control, 1); |
| 444 | pci_write_config_word(dev, msi_control_reg(pos), control); | 450 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 451 | dev->msi_enabled = 1; | ||
| 445 | } else { | 452 | } else { |
| 446 | msix_enable(control); | 453 | msix_enable(control); |
| 447 | pci_write_config_word(dev, msi_control_reg(pos), control); | 454 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 455 | dev->msix_enabled = 1; | ||
| 448 | } | 456 | } |
| 449 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 457 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 450 | /* PCI Express Endpoint device detected */ | 458 | /* PCI Express Endpoint device detected */ |
| @@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 461 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 469 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 462 | msi_disable(control); | 470 | msi_disable(control); |
| 463 | pci_write_config_word(dev, msi_control_reg(pos), control); | 471 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 472 | dev->msi_enabled = 0; | ||
| 464 | } else { | 473 | } else { |
| 465 | msix_disable(control); | 474 | msix_disable(control); |
| 466 | pci_write_config_word(dev, msi_control_reg(pos), control); | 475 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 476 | dev->msix_enabled = 0; | ||
| 467 | } | 477 | } |
| 468 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 478 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 469 | /* PCI Express Endpoint device detected */ | 479 | /* PCI Express Endpoint device detected */ |
| @@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
| 538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | 548 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); |
| 539 | if (control & PCI_MSI_FLAGS_MASKBIT) | 549 | if (control & PCI_MSI_FLAGS_MASKBIT) |
| 540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | 550 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); |
| 541 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
| 542 | save_state->cap_nr = PCI_CAP_ID_MSI; | 551 | save_state->cap_nr = PCI_CAP_ID_MSI; |
| 543 | pci_add_saved_cap(dev, save_state); | 552 | pci_add_saved_cap(dev, save_state); |
| 544 | return 0; | 553 | return 0; |
| @@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
| 575 | int pci_save_msix_state(struct pci_dev *dev) | 584 | int pci_save_msix_state(struct pci_dev *dev) |
| 576 | { | 585 | { |
| 577 | int pos; | 586 | int pos; |
| 587 | int temp; | ||
| 588 | int vector, head, tail = 0; | ||
| 578 | u16 control; | 589 | u16 control; |
| 579 | struct pci_cap_saved_state *save_state; | 590 | struct pci_cap_saved_state *save_state; |
| 580 | 591 | ||
| @@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 582 | if (pos <= 0 || dev->no_msi) | 593 | if (pos <= 0 || dev->no_msi) |
| 583 | return 0; | 594 | return 0; |
| 584 | 595 | ||
| 596 | /* save the capability */ | ||
| 585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 597 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 598 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
| 587 | return 0; | 599 | return 0; |
| @@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 593 | } | 605 | } |
| 594 | *((u16 *)&save_state->data[0]) = control; | 606 | *((u16 *)&save_state->data[0]) = control; |
| 595 | 607 | ||
| 596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 608 | /* save the table */ |
| 609 | temp = dev->irq; | ||
| 610 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | ||
| 611 | kfree(save_state); | ||
| 612 | return -EINVAL; | ||
| 613 | } | ||
| 614 | |||
| 615 | vector = head = dev->irq; | ||
| 616 | while (head != tail) { | ||
| 617 | int j; | ||
| 618 | void __iomem *base; | ||
| 619 | struct msi_desc *entry; | ||
| 620 | |||
| 621 | entry = msi_desc[vector]; | ||
| 622 | base = entry->mask_base; | ||
| 623 | j = entry->msi_attrib.entry_nr; | ||
| 624 | |||
| 625 | entry->address_lo_save = | ||
| 626 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 627 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
| 628 | entry->address_hi_save = | ||
| 629 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 630 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
| 631 | entry->data_save = | ||
| 632 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 633 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
| 634 | |||
| 635 | tail = msi_desc[vector]->link.tail; | ||
| 636 | vector = tail; | ||
| 637 | } | ||
| 638 | dev->irq = temp; | ||
| 639 | |||
| 597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 640 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
| 598 | pci_add_saved_cap(dev, save_state); | 641 | pci_add_saved_cap(dev, save_state); |
| 599 | return 0; | 642 | return 0; |
| @@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 606 | int vector, head, tail = 0; | 649 | int vector, head, tail = 0; |
| 607 | void __iomem *base; | 650 | void __iomem *base; |
| 608 | int j; | 651 | int j; |
| 609 | struct msg_address address; | ||
| 610 | struct msg_data data; | ||
| 611 | struct msi_desc *entry; | 652 | struct msi_desc *entry; |
| 612 | int temp; | 653 | int temp; |
| 613 | struct pci_cap_saved_state *save_state; | 654 | struct pci_cap_saved_state *save_state; |
| @@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 633 | base = entry->mask_base; | 674 | base = entry->mask_base; |
| 634 | j = entry->msi_attrib.entry_nr; | 675 | j = entry->msi_attrib.entry_nr; |
| 635 | 676 | ||
| 636 | msi_address_init(&address); | 677 | writel(entry->address_lo_save, |
| 637 | msi_data_init(&data, vector); | ||
| 638 | |||
| 639 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | ||
| 640 | address.lo_address.value |= entry->msi_attrib.current_cpu << | ||
| 641 | MSI_TARGET_CPU_SHIFT; | ||
| 642 | |||
| 643 | writel(address.lo_address.value, | ||
| 644 | base + j * PCI_MSIX_ENTRY_SIZE + | 678 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 679 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 646 | writel(address.hi_address, | 680 | writel(entry->address_hi_save, |
| 647 | base + j * PCI_MSIX_ENTRY_SIZE + | 681 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 682 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 649 | writel(*(u32*)&data, | 683 | writel(entry->data_save, |
| 650 | base + j * PCI_MSIX_ENTRY_SIZE + | 684 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 651 | PCI_MSIX_ENTRY_DATA_OFFSET); | 685 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 652 | 686 | ||
| @@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 660 | } | 694 | } |
| 661 | #endif | 695 | #endif |
| 662 | 696 | ||
| 663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 697 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
| 664 | { | 698 | { |
| 665 | struct msg_address address; | 699 | int status; |
| 666 | struct msg_data data; | 700 | u32 address_hi; |
| 701 | u32 address_lo; | ||
| 702 | u32 data; | ||
| 667 | int pos, vector = dev->irq; | 703 | int pos, vector = dev->irq; |
| 668 | u16 control; | 704 | u16 control; |
| 669 | 705 | ||
| 670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 706 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
| 671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 707 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 708 | |||
| 672 | /* Configure MSI capability structure */ | 709 | /* Configure MSI capability structure */ |
| 673 | msi_address_init(&address); | 710 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); |
| 674 | msi_data_init(&data, vector); | 711 | if (status < 0) |
| 675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | 712 | return status; |
| 676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 713 | |
| 677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 714 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); |
| 678 | address.lo_address.value); | ||
| 679 | if (is_64bit_address(control)) { | 715 | if (is_64bit_address(control)) { |
| 680 | pci_write_config_dword(dev, | 716 | pci_write_config_dword(dev, |
| 681 | msi_upper_address_reg(pos), address.hi_address); | 717 | msi_upper_address_reg(pos), address_hi); |
| 682 | pci_write_config_word(dev, | 718 | pci_write_config_word(dev, |
| 683 | msi_data_reg(pos, 1), *((u32*)&data)); | 719 | msi_data_reg(pos, 1), data); |
| 684 | } else | 720 | } else |
| 685 | pci_write_config_word(dev, | 721 | pci_write_config_word(dev, |
| 686 | msi_data_reg(pos, 0), *((u32*)&data)); | 722 | msi_data_reg(pos, 0), data); |
| 687 | if (entry->msi_attrib.maskbit) { | 723 | if (entry->msi_attrib.maskbit) { |
| 688 | unsigned int maskbits, temp; | 724 | unsigned int maskbits, temp; |
| 689 | /* All MSIs are unmasked by default, Mask them all */ | 725 | /* All MSIs are unmasked by default, Mask them all */ |
| @@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 733 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
| 698 | maskbits); | 734 | maskbits); |
| 699 | } | 735 | } |
| 736 | |||
| 737 | return 0; | ||
| 700 | } | 738 | } |
| 701 | 739 | ||
| 702 | /** | 740 | /** |
| @@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 710 | **/ | 748 | **/ |
| 711 | static int msi_capability_init(struct pci_dev *dev) | 749 | static int msi_capability_init(struct pci_dev *dev) |
| 712 | { | 750 | { |
| 751 | int status; | ||
| 713 | struct msi_desc *entry; | 752 | struct msi_desc *entry; |
| 714 | int pos, vector; | 753 | int pos, vector; |
| 715 | u16 control; | 754 | u16 control; |
| @@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev) | |||
| 742 | /* Replace with MSI handler */ | 781 | /* Replace with MSI handler */ |
| 743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 782 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
| 744 | /* Configure MSI capability structure */ | 783 | /* Configure MSI capability structure */ |
| 745 | msi_register_init(dev, entry); | 784 | status = msi_register_init(dev, entry); |
| 785 | if (status != 0) { | ||
| 786 | dev->irq = entry->msi_attrib.default_vector; | ||
| 787 | kmem_cache_free(msi_cachep, entry); | ||
| 788 | return status; | ||
| 789 | } | ||
| 746 | 790 | ||
| 747 | attach_msi_entry(entry, vector); | 791 | attach_msi_entry(entry, vector); |
| 748 | /* Set MSI enabled bits */ | 792 | /* Set MSI enabled bits */ |
| @@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 765 | struct msix_entry *entries, int nvec) | 809 | struct msix_entry *entries, int nvec) |
| 766 | { | 810 | { |
| 767 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 811 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
| 768 | struct msg_address address; | 812 | u32 address_hi; |
| 769 | struct msg_data data; | 813 | u32 address_lo; |
| 814 | u32 data; | ||
| 815 | int status; | ||
| 770 | int vector, pos, i, j, nr_entries, temp = 0; | 816 | int vector, pos, i, j, nr_entries, temp = 0; |
| 771 | unsigned long phys_addr; | 817 | unsigned long phys_addr; |
| 772 | u32 table_offset; | 818 | u32 table_offset; |
| @@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 822 | /* Replace with MSI-X handler */ | 868 | /* Replace with MSI-X handler */ |
| 823 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 869 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
| 824 | /* Configure MSI-X capability structure */ | 870 | /* Configure MSI-X capability structure */ |
| 825 | msi_address_init(&address); | 871 | status = msi_ops->setup(dev, vector, |
| 826 | msi_data_init(&data, vector); | 872 | &address_hi, |
| 827 | entry->msi_attrib.current_cpu = | 873 | &address_lo, |
| 828 | ((address.lo_address.u.dest_id >> | 874 | &data); |
| 829 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 875 | if (status < 0) |
| 830 | writel(address.lo_address.value, | 876 | break; |
| 877 | |||
| 878 | writel(address_lo, | ||
| 831 | base + j * PCI_MSIX_ENTRY_SIZE + | 879 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 832 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 880 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 833 | writel(address.hi_address, | 881 | writel(address_hi, |
| 834 | base + j * PCI_MSIX_ENTRY_SIZE + | 882 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 835 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 883 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 836 | writel(*(u32*)&data, | 884 | writel(data, |
| 837 | base + j * PCI_MSIX_ENTRY_SIZE + | 885 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 838 | PCI_MSIX_ENTRY_DATA_OFFSET); | 886 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 839 | attach_msi_entry(entry, vector); | 887 | attach_msi_entry(entry, vector); |
| @@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 865 | **/ | 913 | **/ |
| 866 | int pci_enable_msi(struct pci_dev* dev) | 914 | int pci_enable_msi(struct pci_dev* dev) |
| 867 | { | 915 | { |
| 916 | struct pci_bus *bus; | ||
| 868 | int pos, temp, status = -EINVAL; | 917 | int pos, temp, status = -EINVAL; |
| 869 | u16 control; | 918 | u16 control; |
| 870 | 919 | ||
| @@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 874 | if (dev->no_msi) | 923 | if (dev->no_msi) |
| 875 | return status; | 924 | return status; |
| 876 | 925 | ||
| 877 | if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 926 | for (bus = dev->bus; bus; bus = bus->parent) |
| 878 | return -EINVAL; | 927 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
| 928 | return -EINVAL; | ||
| 879 | 929 | ||
| 880 | temp = dev->irq; | 930 | temp = dev->irq; |
| 881 | 931 | ||
| @@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 887 | if (!pos) | 937 | if (!pos) |
| 888 | return -EINVAL; | 938 | return -EINVAL; |
| 889 | 939 | ||
| 890 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 891 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 892 | return 0; /* Already in MSI mode */ | ||
| 893 | |||
| 894 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 940 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
| 895 | /* Lookup Sucess */ | 941 | /* Lookup Sucess */ |
| 896 | unsigned long flags; | 942 | unsigned long flags; |
| 897 | 943 | ||
| 944 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 945 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 946 | return 0; /* Already in MSI mode */ | ||
| 898 | spin_lock_irqsave(&msi_lock, flags); | 947 | spin_lock_irqsave(&msi_lock, flags); |
| 899 | if (!vector_irq[dev->irq]) { | 948 | if (!vector_irq[dev->irq]) { |
| 900 | msi_desc[dev->irq]->msi_attrib.state = 0; | 949 | msi_desc[dev->irq]->msi_attrib.state = 0; |
| 901 | vector_irq[dev->irq] = -1; | 950 | vector_irq[dev->irq] = -1; |
| 902 | nr_released_vectors--; | 951 | nr_released_vectors--; |
| 903 | spin_unlock_irqrestore(&msi_lock, flags); | 952 | spin_unlock_irqrestore(&msi_lock, flags); |
| 904 | msi_register_init(dev, msi_desc[dev->irq]); | 953 | status = msi_register_init(dev, msi_desc[dev->irq]); |
| 905 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 954 | if (status == 0) |
| 906 | return 0; | 955 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
| 956 | return status; | ||
| 907 | } | 957 | } |
| 908 | spin_unlock_irqrestore(&msi_lock, flags); | 958 | spin_unlock_irqrestore(&msi_lock, flags); |
| 909 | dev->irq = temp; | 959 | dev->irq = temp; |
| @@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 980 | void __iomem *base; | 1030 | void __iomem *base; |
| 981 | unsigned long flags; | 1031 | unsigned long flags; |
| 982 | 1032 | ||
| 1033 | msi_ops->teardown(vector); | ||
| 1034 | |||
| 983 | spin_lock_irqsave(&msi_lock, flags); | 1035 | spin_lock_irqsave(&msi_lock, flags); |
| 984 | entry = msi_desc[vector]; | 1036 | entry = msi_desc[vector]; |
| 985 | if (!entry || entry->dev != dev) { | 1037 | if (!entry || entry->dev != dev) { |
| @@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 1008 | entry_nr * PCI_MSIX_ENTRY_SIZE + | 1060 | entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 1009 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 1061 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
| 1010 | 1062 | ||
| 1011 | if (head == vector) { | 1063 | if (head == vector) |
| 1012 | /* | ||
| 1013 | * Detect last MSI-X vector to be released. | ||
| 1014 | * Release the MSI-X memory-mapped table. | ||
| 1015 | */ | ||
| 1016 | #if 0 | ||
| 1017 | int pos, nr_entries; | ||
| 1018 | unsigned long phys_addr; | ||
| 1019 | u32 table_offset; | ||
| 1020 | u16 control; | ||
| 1021 | u8 bir; | ||
| 1022 | |||
| 1023 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 1024 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1025 | &control); | ||
| 1026 | nr_entries = multi_msix_capable(control); | ||
| 1027 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1028 | &table_offset); | ||
| 1029 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1030 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1031 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1032 | /* | ||
| 1033 | * FIXME! and what did you want to do with phys_addr? | ||
| 1034 | */ | ||
| 1035 | #endif | ||
| 1036 | iounmap(base); | 1064 | iounmap(base); |
| 1037 | } | ||
| 1038 | } | 1065 | } |
| 1039 | 1066 | ||
| 1040 | return 0; | 1067 | return 0; |
| @@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
| 1108 | **/ | 1135 | **/ |
| 1109 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1136 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
| 1110 | { | 1137 | { |
| 1138 | struct pci_bus *bus; | ||
| 1111 | int status, pos, nr_entries, free_vectors; | 1139 | int status, pos, nr_entries, free_vectors; |
| 1112 | int i, j, temp; | 1140 | int i, j, temp; |
| 1113 | u16 control; | 1141 | u16 control; |
| @@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
| 1116 | if (!pci_msi_enable || !dev || !entries) | 1144 | if (!pci_msi_enable || !dev || !entries) |
| 1117 | return -EINVAL; | 1145 | return -EINVAL; |
| 1118 | 1146 | ||
| 1147 | if (dev->no_msi) | ||
| 1148 | return -EINVAL; | ||
| 1149 | |||
| 1150 | for (bus = dev->bus; bus; bus = bus->parent) | ||
| 1151 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
| 1152 | return -EINVAL; | ||
| 1153 | |||
| 1119 | status = msi_init(); | 1154 | status = msi_init(); |
| 1120 | if (status < 0) | 1155 | if (status < 0) |
| 1121 | return status; | 1156 | return status; |
| @@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
| 1300 | } | 1335 | } |
| 1301 | msi_free_vector(dev, vector, 0); | 1336 | msi_free_vector(dev, vector, 0); |
| 1302 | if (warning) { | 1337 | if (warning) { |
| 1303 | /* Force to release the MSI-X memory-mapped table */ | ||
| 1304 | #if 0 | ||
| 1305 | unsigned long phys_addr; | ||
| 1306 | u32 table_offset; | ||
| 1307 | u16 control; | ||
| 1308 | u8 bir; | ||
| 1309 | |||
| 1310 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1311 | &control); | ||
| 1312 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1313 | &table_offset); | ||
| 1314 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1315 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1316 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1317 | /* | ||
| 1318 | * FIXME! and what did you want to do with phys_addr? | ||
| 1319 | */ | ||
| 1320 | #endif | ||
| 1321 | iounmap(base); | 1338 | iounmap(base); |
| 1322 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 1339 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
| 1323 | "called without free_irq() on all MSI-X vectors\n", | 1340 | "called without free_irq() on all MSI-X vectors\n", |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
| @@ -6,6 +6,68 @@ | |||
| 6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
| 7 | #define MSI_H | 7 | #define MSI_H |
| 8 | 8 | ||
| 9 | /* | ||
| 10 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
| 11 | * to abstract platform-specific tasks relating to MSI address generation | ||
| 12 | * and resource management. | ||
| 13 | */ | ||
| 14 | struct msi_ops { | ||
| 15 | /** | ||
| 16 | * setup - generate an MSI bus address and data for a given vector | ||
| 17 | * @pdev: PCI device context (in) | ||
| 18 | * @vector: vector allocated by the msi core (in) | ||
| 19 | * @addr_hi: upper 32 bits of PCI bus MSI address (out) | ||
| 20 | * @addr_lo: lower 32 bits of PCI bus MSI address (out) | ||
| 21 | * @data: MSI data payload (out) | ||
| 22 | * | ||
| 23 | * Description: The setup op is used to generate a PCI bus addres and | ||
| 24 | * data which the msi core will program into the card MSI capability | ||
| 25 | * registers. The setup routine is responsible for picking an initial | ||
| 26 | * cpu to target the MSI at. The setup routine is responsible for | ||
| 27 | * examining pdev to determine the MSI capabilities of the card and | ||
| 28 | * generating a suitable address/data. The setup routine is | ||
| 29 | * responsible for allocating and tracking any system resources it | ||
| 30 | * needs to route the MSI to the cpu it picks, and for associating | ||
| 31 | * those resources with the passed in vector. | ||
| 32 | * | ||
| 33 | * Returns 0 if the MSI address/data was successfully setup. | ||
| 34 | **/ | ||
| 35 | |||
| 36 | int (*setup) (struct pci_dev *pdev, unsigned int vector, | ||
| 37 | u32 *addr_hi, u32 *addr_lo, u32 *data); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * teardown - release resources allocated by setup | ||
| 41 | * @vector: vector context for resources (in) | ||
| 42 | * | ||
| 43 | * Description: The teardown op is used to release any resources | ||
| 44 | * that were allocated in the setup routine associated with the passed | ||
| 45 | * in vector. | ||
| 46 | **/ | ||
| 47 | |||
| 48 | void (*teardown) (unsigned int vector); | ||
| 49 | |||
| 50 | /** | ||
| 51 | * target - retarget an MSI at a different cpu | ||
| 52 | * @vector: vector context for resources (in) | ||
| 53 | * @cpu: new cpu to direct vector at (in) | ||
| 54 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
| 55 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
| 56 | * | ||
| 57 | * Description: The target op is used to redirect an MSI vector | ||
| 58 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
| 59 | * values that the MSI core has programmed into the card. The | ||
| 60 | * target code is responsible for freeing any resources (if any) | ||
| 61 | * associated with the old address, and generating a new PCI bus | ||
| 62 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
| 63 | **/ | ||
| 64 | |||
| 65 | void (*target) (unsigned int vector, unsigned int cpu, | ||
| 66 | u32 *addr_hi, u32 *addr_lo); | ||
| 67 | }; | ||
| 68 | |||
| 69 | extern int msi_register(struct msi_ops *ops); | ||
| 70 | |||
| 9 | #include <asm/msi.h> | 71 | #include <asm/msi.h> |
| 10 | 72 | ||
| 11 | /* | 73 | /* |
| @@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); | |||
| 63 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) | 125 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) |
| 64 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) | 126 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) |
| 65 | 127 | ||
| 66 | /* | ||
| 67 | * MSI Defined Data Structures | ||
| 68 | */ | ||
| 69 | #define MSI_ADDRESS_HEADER 0xfee | ||
| 70 | #define MSI_ADDRESS_HEADER_SHIFT 12 | ||
| 71 | #define MSI_ADDRESS_HEADER_MASK 0xfff000 | ||
| 72 | #define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f | ||
| 73 | #define MSI_TARGET_CPU_MASK 0xff | ||
| 74 | #define MSI_DELIVERY_MODE 0 | ||
| 75 | #define MSI_LEVEL_MODE 1 /* Edge always assert */ | ||
| 76 | #define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ | ||
| 77 | #define MSI_PHYSICAL_MODE 0 | ||
| 78 | #define MSI_LOGICAL_MODE 1 | ||
| 79 | #define MSI_REDIRECTION_HINT_MODE 0 | ||
| 80 | |||
| 81 | struct msg_data { | ||
| 82 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
| 83 | __u32 vector : 8; | ||
| 84 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
| 85 | __u32 reserved_1 : 3; | ||
| 86 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
| 87 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
| 88 | __u32 reserved_2 : 16; | ||
| 89 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
| 90 | __u32 reserved_2 : 16; | ||
| 91 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
| 92 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
| 93 | __u32 reserved_1 : 3; | ||
| 94 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
| 95 | __u32 vector : 8; | ||
| 96 | #else | ||
| 97 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
| 98 | #endif | ||
| 99 | } __attribute__ ((packed)); | ||
| 100 | |||
| 101 | struct msg_address { | ||
| 102 | union { | ||
| 103 | struct { | ||
| 104 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
| 105 | __u32 reserved_1 : 2; | ||
| 106 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
| 107 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
| 108 | 1: lowest priority */ | ||
| 109 | __u32 reserved_2 : 4; | ||
| 110 | __u32 dest_id : 24; /* Destination ID */ | ||
| 111 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
| 112 | __u32 dest_id : 24; /* Destination ID */ | ||
| 113 | __u32 reserved_2 : 4; | ||
| 114 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
| 115 | 1: lowest priority */ | ||
| 116 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
| 117 | __u32 reserved_1 : 2; | ||
| 118 | #else | ||
| 119 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
| 120 | #endif | ||
| 121 | }u; | ||
| 122 | __u32 value; | ||
| 123 | }lo_address; | ||
| 124 | __u32 hi_address; | ||
| 125 | } __attribute__ ((packed)); | ||
| 126 | |||
| 127 | struct msi_desc { | 128 | struct msi_desc { |
| 128 | struct { | 129 | struct { |
| 129 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
| @@ -132,7 +133,7 @@ struct msi_desc { | |||
| 132 | __u8 reserved: 1; /* reserved */ | 133 | __u8 reserved: 1; /* reserved */ |
| 133 | __u8 entry_nr; /* specific enabled entry */ | 134 | __u8 entry_nr; /* specific enabled entry */ |
| 134 | __u8 default_vector; /* default pre-assigned vector */ | 135 | __u8 default_vector; /* default pre-assigned vector */ |
| 135 | __u8 current_cpu; /* current destination cpu */ | 136 | __u8 unused; /* formerly unused destination cpu*/ |
| 136 | }msi_attrib; | 137 | }msi_attrib; |
| 137 | 138 | ||
| 138 | struct { | 139 | struct { |
| @@ -142,6 +143,14 @@ struct msi_desc { | |||
| 142 | 143 | ||
| 143 | void __iomem *mask_base; | 144 | void __iomem *mask_base; |
| 144 | struct pci_dev *dev; | 145 | struct pci_dev *dev; |
| 146 | |||
| 147 | #ifdef CONFIG_PM | ||
| 148 | /* PM save area for MSIX address/data */ | ||
| 149 | |||
| 150 | u32 address_hi_save; | ||
| 151 | u32 address_lo_save; | ||
| 152 | u32 data_save; | ||
| 153 | #endif | ||
| 145 | }; | 154 | }; |
| 146 | 155 | ||
| 147 | #endif /* MSI_H */ | 156 | #endif /* MSI_H */ |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ecae5ff0c1..bb7456c1dbac 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
| @@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
| 267 | 267 | ||
| 268 | 268 | ||
| 269 | /* ACPI bus type */ | 269 | /* ACPI bus type */ |
| 270 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | 270 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
| 271 | { | 271 | { |
| 272 | struct pci_dev * pci_dev; | 272 | struct pci_dev * pci_dev; |
| 273 | acpi_integer addr; | 273 | acpi_integer addr; |
| @@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | |||
| 281 | return 0; | 281 | return 0; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | 284 | static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) |
| 285 | { | 285 | { |
| 286 | int num; | 286 | int num; |
| 287 | unsigned int seg, bus; | 287 | unsigned int seg, bus; |
| @@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | |||
| 299 | return 0; | 299 | return 0; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | static struct acpi_bus_type pci_acpi_bus = { | 302 | static struct acpi_bus_type acpi_pci_bus = { |
| 303 | .bus = &pci_bus_type, | 303 | .bus = &pci_bus_type, |
| 304 | .find_device = pci_acpi_find_device, | 304 | .find_device = acpi_pci_find_device, |
| 305 | .find_bridge = pci_acpi_find_root_bridge, | 305 | .find_bridge = acpi_pci_find_root_bridge, |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | static int __init pci_acpi_init(void) | 308 | static int __init acpi_pci_init(void) |
| 309 | { | 309 | { |
| 310 | int ret; | 310 | int ret; |
| 311 | 311 | ||
| 312 | ret = register_acpi_bus_type(&pci_acpi_bus); | 312 | ret = register_acpi_bus_type(&acpi_pci_bus); |
| 313 | if (ret) | 313 | if (ret) |
| 314 | return 0; | 314 | return 0; |
| 315 | platform_pci_choose_state = acpi_pci_choose_state; | 315 | platform_pci_choose_state = acpi_pci_choose_state; |
| 316 | platform_pci_set_power_state = acpi_pci_set_power_state; | 316 | platform_pci_set_power_state = acpi_pci_set_power_state; |
| 317 | return 0; | 317 | return 0; |
| 318 | } | 318 | } |
| 319 | arch_initcall(pci_acpi_init); | 319 | arch_initcall(acpi_pci_init); |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56ac2bc003c7..bc405c035ce3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -43,6 +43,29 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); | |||
| 43 | pci_config_attr(subsystem_device, "0x%04x\n"); | 43 | pci_config_attr(subsystem_device, "0x%04x\n"); |
| 44 | pci_config_attr(class, "0x%06x\n"); | 44 | pci_config_attr(class, "0x%06x\n"); |
| 45 | pci_config_attr(irq, "%u\n"); | 45 | pci_config_attr(irq, "%u\n"); |
| 46 | pci_config_attr(is_enabled, "%u\n"); | ||
| 47 | |||
| 48 | static ssize_t broken_parity_status_show(struct device *dev, | ||
| 49 | struct device_attribute *attr, | ||
| 50 | char *buf) | ||
| 51 | { | ||
| 52 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 53 | return sprintf (buf, "%u\n", pdev->broken_parity_status); | ||
| 54 | } | ||
| 55 | |||
| 56 | static ssize_t broken_parity_status_store(struct device *dev, | ||
| 57 | struct device_attribute *attr, | ||
| 58 | const char *buf, size_t count) | ||
| 59 | { | ||
| 60 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 61 | ssize_t consumed = -EINVAL; | ||
| 62 | |||
| 63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | ||
| 64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | ||
| 65 | consumed = count; | ||
| 66 | } | ||
| 67 | return consumed; | ||
| 68 | } | ||
| 46 | 69 | ||
| 47 | static ssize_t local_cpus_show(struct device *dev, | 70 | static ssize_t local_cpus_show(struct device *dev, |
| 48 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
| @@ -90,6 +113,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 90 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), | 113 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), |
| 91 | (u8)(pci_dev->class)); | 114 | (u8)(pci_dev->class)); |
| 92 | } | 115 | } |
| 116 | static ssize_t | ||
| 117 | is_enabled_store(struct device *dev, struct device_attribute *attr, | ||
| 118 | const char *buf, size_t count) | ||
| 119 | { | ||
| 120 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 121 | |||
| 122 | /* this can crash the machine when done on the "wrong" device */ | ||
| 123 | if (!capable(CAP_SYS_ADMIN)) | ||
| 124 | return count; | ||
| 125 | |||
| 126 | if (*buf == '0') | ||
| 127 | pci_disable_device(pdev); | ||
| 128 | |||
| 129 | if (*buf == '1') | ||
| 130 | pci_enable_device(pdev); | ||
| 131 | |||
| 132 | return count; | ||
| 133 | } | ||
| 134 | |||
| 93 | 135 | ||
| 94 | struct device_attribute pci_dev_attrs[] = { | 136 | struct device_attribute pci_dev_attrs[] = { |
| 95 | __ATTR_RO(resource), | 137 | __ATTR_RO(resource), |
| @@ -101,6 +143,9 @@ struct device_attribute pci_dev_attrs[] = { | |||
| 101 | __ATTR_RO(irq), | 143 | __ATTR_RO(irq), |
| 102 | __ATTR_RO(local_cpus), | 144 | __ATTR_RO(local_cpus), |
| 103 | __ATTR_RO(modalias), | 145 | __ATTR_RO(modalias), |
| 146 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), | ||
| 147 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | ||
| 148 | broken_parity_status_show,broken_parity_status_store), | ||
| 104 | __ATTR_NULL, | 149 | __ATTR_NULL, |
| 105 | }; | 150 | }; |
| 106 | 151 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fde41cc14734..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) | |||
| 517 | int | 517 | int |
| 518 | pci_enable_device(struct pci_dev *dev) | 518 | pci_enable_device(struct pci_dev *dev) |
| 519 | { | 519 | { |
| 520 | int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 520 | int err; |
| 521 | |||
| 522 | if (dev->is_enabled) | ||
| 523 | return 0; | ||
| 524 | |||
| 525 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | ||
| 521 | if (err) | 526 | if (err) |
| 522 | return err; | 527 | return err; |
| 523 | pci_fixup_device(pci_fixup_enable, dev); | 528 | pci_fixup_device(pci_fixup_enable, dev); |
| @@ -546,7 +551,14 @@ void | |||
| 546 | pci_disable_device(struct pci_dev *dev) | 551 | pci_disable_device(struct pci_dev *dev) |
| 547 | { | 552 | { |
| 548 | u16 pci_command; | 553 | u16 pci_command; |
| 549 | 554 | ||
| 555 | if (dev->msi_enabled) | ||
| 556 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
| 557 | PCI_CAP_ID_MSI); | ||
| 558 | if (dev->msix_enabled) | ||
| 559 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
| 560 | PCI_CAP_ID_MSIX); | ||
| 561 | |||
| 550 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); | 562 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); |
| 551 | if (pci_command & PCI_COMMAND_MASTER) { | 563 | if (pci_command & PCI_COMMAND_MASTER) { |
| 552 | pci_command &= ~PCI_COMMAND_MASTER; | 564 | pci_command &= ~PCI_COMMAND_MASTER; |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 30630cbe2fe3..29bdeca031a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int | |||
| 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); | 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); |
| 41 | 41 | ||
| 42 | /* Lock for read/write access to pci device and bus lists */ | 42 | /* Lock for read/write access to pci device and bus lists */ |
| 43 | extern spinlock_t pci_bus_lock; | 43 | extern struct rw_semaphore pci_bus_sem; |
| 44 | 44 | ||
| 45 | #ifdef CONFIG_X86_IO_APIC | 45 | #ifdef CONFIG_X86_IO_APIC |
| 46 | extern int pci_msi_quirk; | 46 | extern int pci_msi_quirk; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
| @@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
| 180 | res->flags |= pci_calc_resource_flags(l); | 180 | res->flags |= pci_calc_resource_flags(l); |
| 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) | 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) |
| 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { | 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { |
| 183 | pci_read_config_dword(dev, reg+4, &l); | 183 | u32 szhi, lhi; |
| 184 | pci_read_config_dword(dev, reg+4, &lhi); | ||
| 185 | pci_write_config_dword(dev, reg+4, ~0); | ||
| 186 | pci_read_config_dword(dev, reg+4, &szhi); | ||
| 187 | pci_write_config_dword(dev, reg+4, lhi); | ||
| 188 | szhi = pci_size(lhi, szhi, 0xffffffff); | ||
| 184 | next++; | 189 | next++; |
| 185 | #if BITS_PER_LONG == 64 | 190 | #if BITS_PER_LONG == 64 |
| 186 | res->start |= ((unsigned long) l) << 32; | 191 | res->start |= ((unsigned long) lhi) << 32; |
| 187 | res->end = res->start + sz; | 192 | res->end = res->start + sz; |
| 188 | pci_write_config_dword(dev, reg+4, ~0); | 193 | if (szhi) { |
| 189 | pci_read_config_dword(dev, reg+4, &sz); | ||
| 190 | pci_write_config_dword(dev, reg+4, l); | ||
| 191 | sz = pci_size(l, sz, 0xffffffff); | ||
| 192 | if (sz) { | ||
| 193 | /* This BAR needs > 4GB? Wow. */ | 194 | /* This BAR needs > 4GB? Wow. */ |
| 194 | res->end |= (unsigned long)sz<<32; | 195 | res->end |= (unsigned long)szhi<<32; |
| 195 | } | 196 | } |
| 196 | #else | 197 | #else |
| 197 | if (l) { | 198 | if (szhi) { |
| 198 | printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); | 199 | printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); |
| 199 | res->start = 0; | 200 | res->start = 0; |
| 200 | res->flags = 0; | 201 | res->flags = 0; |
| 201 | continue; | 202 | } else if (lhi) { |
| 203 | /* 64-bit wide address, treat as disabled */ | ||
| 204 | pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | ||
| 205 | pci_write_config_dword(dev, reg+4, 0); | ||
| 206 | res->start = 0; | ||
| 207 | res->end = sz; | ||
| 202 | } | 208 | } |
| 203 | #endif | 209 | #endif |
| 204 | } | 210 | } |
| @@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
| 377 | 383 | ||
| 378 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
| 379 | if (child) { | 385 | if (child) { |
| 380 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
| 381 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
| 382 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
| 383 | } | 389 | } |
| 384 | return child; | 390 | return child; |
| 385 | } | 391 | } |
| @@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
| 838 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
| 839 | */ | 845 | */ |
| 840 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
| 841 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
| 842 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
| 843 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
| 844 | } | 850 | } |
| 845 | 851 | ||
| 846 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
| @@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
| 975 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
| 976 | goto err_out; | 982 | goto err_out; |
| 977 | } | 983 | } |
| 978 | spin_lock(&pci_bus_lock); | 984 | |
| 985 | down_write(&pci_bus_sem); | ||
| 979 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
| 980 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
| 981 | 988 | ||
| 982 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
| 983 | dev->parent = parent; | 990 | dev->parent = parent; |
| @@ -1017,9 +1024,9 @@ class_dev_create_file_err: | |||
| 1017 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
| 1018 | device_unregister(dev); | 1025 | device_unregister(dev); |
| 1019 | dev_reg_err: | 1026 | dev_reg_err: |
| 1020 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
| 1021 | list_del(&b->node); | 1028 | list_del(&b->node); |
| 1022 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
| 1023 | err_out: | 1030 | err_out: |
| 1024 | kfree(dev); | 1031 | kfree(dev); |
| 1025 | kfree(b); | 1032 | kfree(b); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -24,6 +24,17 @@ | |||
| 24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
| 25 | #include "pci.h" | 25 | #include "pci.h" |
| 26 | 26 | ||
| 27 | /* The Mellanox Tavor device gives false positive parity errors | ||
| 28 | * Mark this device with a broken_parity_status, to allow | ||
| 29 | * PCI scanning code to "skip" this now blacklisted device. | ||
| 30 | */ | ||
| 31 | static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) | ||
| 32 | { | ||
| 33 | dev->broken_parity_status = 1; /* This device gives false positives */ | ||
| 34 | } | ||
| 35 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); | ||
| 36 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); | ||
| 37 | |||
| 27 | /* Deal with broken BIOS'es that neglect to enable passive release, | 38 | /* Deal with broken BIOS'es that neglect to enable passive release, |
| 28 | which can cause problems in combination with the 82441FX/PPro MTRRs */ | 39 | which can cause problems in combination with the 82441FX/PPro MTRRs */ |
| 29 | static void __devinit quirk_passive_release(struct pci_dev *dev) | 40 | static void __devinit quirk_passive_release(struct pci_dev *dev) |
| @@ -878,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e | |||
| 878 | * when a PCI-Soundcard is added. The BIOS only gives Options | 889 | * when a PCI-Soundcard is added. The BIOS only gives Options |
| 879 | * "Disabled" and "AUTO". This Quirk Sets the corresponding | 890 | * "Disabled" and "AUTO". This Quirk Sets the corresponding |
| 880 | * Register-Value to enable the Soundcard. | 891 | * Register-Value to enable the Soundcard. |
| 892 | * | ||
| 893 | * FIXME: Presently this quirk will run on anything that has an 8237 | ||
| 894 | * which isn't correct, we need to check DMI tables or something in | ||
| 895 | * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it | ||
| 896 | * runs everywhere at present we suppress the printk output in most | ||
| 897 | * irrelevant cases. | ||
| 881 | */ | 898 | */ |
| 882 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) | 899 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) |
| 883 | { | 900 | { |
| 884 | unsigned char val; | 901 | unsigned char val; |
| 885 | 902 | ||
| 886 | printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n"); | ||
| 887 | pci_read_config_byte(dev, 0x50, &val); | 903 | pci_read_config_byte(dev, 0x50, &val); |
| 888 | if (val == 0x88 || val == 0xc8) { | 904 | if (val == 0x88 || val == 0xc8) { |
| 905 | /* Assume it's probably a MSI-K8T-Neo2Fir */ | ||
| 906 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); | ||
| 889 | pci_write_config_byte(dev, 0x50, val & (~0x40)); | 907 | pci_write_config_byte(dev, 0x50, val & (~0x40)); |
| 890 | 908 | ||
| 891 | /* Verify the Change for Status output */ | 909 | /* Verify the Change for Status output */ |
| 892 | pci_read_config_byte(dev, 0x50, &val); | 910 | pci_read_config_byte(dev, 0x50, &val); |
| 893 | if (val & 0x40) | 911 | if (val & 0x40) |
| 894 | printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n"); | 912 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); |
| 895 | else | 913 | else |
| 896 | printk(KERN_INFO "PCI: MSI-K8T soundcard on\n"); | 914 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); |
| 897 | } else { | ||
| 898 | printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: " | ||
| 899 | "no Change!\n"); | ||
| 900 | } | 915 | } |
| 901 | |||
| 902 | } | 916 | } |
| 903 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); | 917 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); |
| 904 | 918 | ||
| @@ -1485,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) | |||
| 1485 | } | 1499 | } |
| 1486 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); | 1500 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); |
| 1487 | 1501 | ||
| 1502 | /* Under some circumstances, AER is not linked with extended capabilities. | ||
| 1503 | * Force it to be linked by setting the corresponding control bit in the | ||
| 1504 | * config space. | ||
| 1505 | */ | ||
| 1506 | static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) | ||
| 1507 | { | ||
| 1508 | uint8_t b; | ||
| 1509 | if (pci_read_config_byte(dev, 0xf41, &b) == 0) { | ||
| 1510 | if (!(b & 0x20)) { | ||
| 1511 | pci_write_config_byte(dev, 0xf41, b | 0x20); | ||
| 1512 | printk(KERN_INFO | ||
| 1513 | "PCI: Linking AER extended capability on %s\n", | ||
| 1514 | pci_name(dev)); | ||
| 1515 | } | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, | ||
| 1519 | quirk_nvidia_ck804_pcie_aer_ext_cap); | ||
| 1520 | |||
| 1488 | EXPORT_SYMBOL(pcie_mch_quirk); | 1521 | EXPORT_SYMBOL(pcie_mch_quirk); |
| 1489 | #ifdef CONFIG_HOTPLUG | 1522 | #ifdef CONFIG_HOTPLUG |
| 1490 | EXPORT_SYMBOL(pci_fixup_device); | 1523 | EXPORT_SYMBOL(pci_fixup_device); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1a6bf9de166f..99ffbd478b29 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
| @@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev) | |||
| 22 | pci_proc_detach_device(dev); | 22 | pci_proc_detach_device(dev); |
| 23 | pci_remove_sysfs_dev_files(dev); | 23 | pci_remove_sysfs_dev_files(dev); |
| 24 | device_unregister(&dev->dev); | 24 | device_unregister(&dev->dev); |
| 25 | spin_lock(&pci_bus_lock); | 25 | down_write(&pci_bus_sem); |
| 26 | list_del(&dev->global_list); | 26 | list_del(&dev->global_list); |
| 27 | dev->global_list.next = dev->global_list.prev = NULL; | 27 | dev->global_list.next = dev->global_list.prev = NULL; |
| 28 | spin_unlock(&pci_bus_lock); | 28 | up_write(&pci_bus_sem); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | /* Remove the device from the device lists, and prevent any further | 31 | /* Remove the device from the device lists, and prevent any further |
| 32 | * list accesses from this device */ | 32 | * list accesses from this device */ |
| 33 | spin_lock(&pci_bus_lock); | 33 | down_write(&pci_bus_sem); |
| 34 | list_del(&dev->bus_list); | 34 | list_del(&dev->bus_list); |
| 35 | dev->bus_list.next = dev->bus_list.prev = NULL; | 35 | dev->bus_list.next = dev->bus_list.prev = NULL; |
| 36 | spin_unlock(&pci_bus_lock); | 36 | up_write(&pci_bus_sem); |
| 37 | 37 | ||
| 38 | pci_free_resources(dev); | 38 | pci_free_resources(dev); |
| 39 | pci_dev_put(dev); | 39 | pci_dev_put(dev); |
| @@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) | |||
| 62 | { | 62 | { |
| 63 | pci_proc_detach_bus(pci_bus); | 63 | pci_proc_detach_bus(pci_bus); |
| 64 | 64 | ||
| 65 | spin_lock(&pci_bus_lock); | 65 | down_write(&pci_bus_sem); |
| 66 | list_del(&pci_bus->node); | 66 | list_del(&pci_bus->node); |
| 67 | spin_unlock(&pci_bus_lock); | 67 | up_write(&pci_bus_sem); |
| 68 | pci_remove_legacy_files(pci_bus); | 68 | pci_remove_legacy_files(pci_bus); |
| 69 | class_device_remove_file(&pci_bus->class_dev, | 69 | class_device_remove_file(&pci_bus->class_dev, |
| 70 | &class_device_attr_cpuaffinity); | 70 | &class_device_attr_cpuaffinity); |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ce7dd6e7be60..622b3f8ba820 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include "pci.h" | 14 | #include "pci.h" |
| 15 | 15 | ||
| 16 | DEFINE_SPINLOCK(pci_bus_lock); | 16 | DECLARE_RWSEM(pci_bus_sem); |
| 17 | 17 | ||
| 18 | static struct pci_bus * __devinit | 18 | static struct pci_bus * __devinit |
| 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) |
| @@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from) | |||
| 72 | struct pci_bus *b = NULL; | 72 | struct pci_bus *b = NULL; |
| 73 | 73 | ||
| 74 | WARN_ON(in_interrupt()); | 74 | WARN_ON(in_interrupt()); |
| 75 | spin_lock(&pci_bus_lock); | 75 | down_read(&pci_bus_sem); |
| 76 | n = from ? from->node.next : pci_root_buses.next; | 76 | n = from ? from->node.next : pci_root_buses.next; |
| 77 | if (n != &pci_root_buses) | 77 | if (n != &pci_root_buses) |
| 78 | b = pci_bus_b(n); | 78 | b = pci_bus_b(n); |
| 79 | spin_unlock(&pci_bus_lock); | 79 | up_read(&pci_bus_sem); |
| 80 | return b; | 80 | return b; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| @@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
| 124 | struct pci_dev *dev; | 124 | struct pci_dev *dev; |
| 125 | 125 | ||
| 126 | WARN_ON(in_interrupt()); | 126 | WARN_ON(in_interrupt()); |
| 127 | spin_lock(&pci_bus_lock); | 127 | down_read(&pci_bus_sem); |
| 128 | 128 | ||
| 129 | list_for_each(tmp, &bus->devices) { | 129 | list_for_each(tmp, &bus->devices) { |
| 130 | dev = pci_dev_b(tmp); | 130 | dev = pci_dev_b(tmp); |
| @@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
| 135 | dev = NULL; | 135 | dev = NULL; |
| 136 | out: | 136 | out: |
| 137 | pci_dev_get(dev); | 137 | pci_dev_get(dev); |
| 138 | spin_unlock(&pci_bus_lock); | 138 | up_read(&pci_bus_sem); |
| 139 | return dev; | 139 | return dev; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| @@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
| 167 | struct pci_dev *dev; | 167 | struct pci_dev *dev; |
| 168 | 168 | ||
| 169 | WARN_ON(in_interrupt()); | 169 | WARN_ON(in_interrupt()); |
| 170 | spin_lock(&pci_bus_lock); | 170 | down_read(&pci_bus_sem); |
| 171 | n = from ? from->global_list.next : pci_devices.next; | 171 | n = from ? from->global_list.next : pci_devices.next; |
| 172 | 172 | ||
| 173 | while (n && (n != &pci_devices)) { | 173 | while (n && (n != &pci_devices)) { |
| @@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
| 181 | } | 181 | } |
| 182 | dev = NULL; | 182 | dev = NULL; |
| 183 | exit: | 183 | exit: |
| 184 | spin_unlock(&pci_bus_lock); | 184 | up_read(&pci_bus_sem); |
| 185 | return dev; | 185 | return dev; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| @@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
| 232 | struct pci_dev *dev; | 232 | struct pci_dev *dev; |
| 233 | 233 | ||
| 234 | WARN_ON(in_interrupt()); | 234 | WARN_ON(in_interrupt()); |
| 235 | spin_lock(&pci_bus_lock); | 235 | down_read(&pci_bus_sem); |
| 236 | n = from ? from->global_list.next : pci_devices.next; | 236 | n = from ? from->global_list.next : pci_devices.next; |
| 237 | 237 | ||
| 238 | while (n && (n != &pci_devices)) { | 238 | while (n && (n != &pci_devices)) { |
| @@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
| 247 | dev = NULL; | 247 | dev = NULL; |
| 248 | exit: | 248 | exit: |
| 249 | dev = pci_dev_get(dev); | 249 | dev = pci_dev_get(dev); |
| 250 | spin_unlock(&pci_bus_lock); | 250 | up_read(&pci_bus_sem); |
| 251 | pci_dev_put(from); | 251 | pci_dev_put(from); |
| 252 | return dev; | 252 | return dev; |
| 253 | } | 253 | } |
| @@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
| 292 | struct pci_dev *dev; | 292 | struct pci_dev *dev; |
| 293 | 293 | ||
| 294 | WARN_ON(in_interrupt()); | 294 | WARN_ON(in_interrupt()); |
| 295 | spin_lock(&pci_bus_lock); | 295 | down_read(&pci_bus_sem); |
| 296 | n = from ? from->global_list.prev : pci_devices.prev; | 296 | n = from ? from->global_list.prev : pci_devices.prev; |
| 297 | 297 | ||
| 298 | while (n && (n != &pci_devices)) { | 298 | while (n && (n != &pci_devices)) { |
| @@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
| 304 | } | 304 | } |
| 305 | dev = NULL; | 305 | dev = NULL; |
| 306 | exit: | 306 | exit: |
| 307 | spin_unlock(&pci_bus_lock); | 307 | up_read(&pci_bus_sem); |
| 308 | return dev; | 308 | return dev; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| @@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
| 328 | struct pci_dev *dev; | 328 | struct pci_dev *dev; |
| 329 | 329 | ||
| 330 | WARN_ON(in_interrupt()); | 330 | WARN_ON(in_interrupt()); |
| 331 | spin_lock(&pci_bus_lock); | 331 | down_read(&pci_bus_sem); |
| 332 | n = from ? from->global_list.next : pci_devices.next; | 332 | n = from ? from->global_list.next : pci_devices.next; |
| 333 | 333 | ||
| 334 | while (n && (n != &pci_devices)) { | 334 | while (n && (n != &pci_devices)) { |
| @@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
| 340 | dev = NULL; | 340 | dev = NULL; |
| 341 | exit: | 341 | exit: |
| 342 | dev = pci_dev_get(dev); | 342 | dev = pci_dev_get(dev); |
| 343 | spin_unlock(&pci_bus_lock); | 343 | up_read(&pci_bus_sem); |
| 344 | pci_dev_put(from); | 344 | pci_dev_put(from); |
| 345 | return dev; | 345 | return dev; |
| 346 | } | 346 | } |
| @@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
| 362 | int found = 0; | 362 | int found = 0; |
| 363 | 363 | ||
| 364 | WARN_ON(in_interrupt()); | 364 | WARN_ON(in_interrupt()); |
| 365 | spin_lock(&pci_bus_lock); | 365 | down_read(&pci_bus_sem); |
| 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { | 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
| 367 | list_for_each_entry(dev, &pci_devices, global_list) { | 367 | list_for_each_entry(dev, &pci_devices, global_list) { |
| 368 | if (pci_match_one_device(ids, dev)) { | 368 | if (pci_match_one_device(ids, dev)) { |
| @@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
| 372 | } | 372 | } |
| 373 | ids++; | 373 | ids++; |
| 374 | } | 374 | } |
| 375 | exit: | 375 | exit: |
| 376 | spin_unlock(&pci_bus_lock); | 376 | up_read(&pci_bus_sem); |
| 377 | return found; | 377 | return found; |
| 378 | } | 378 | } |
| 379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28ce3a7ee434..35086e80faa9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
| @@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) | |||
| 55 | list_for_each_entry(dev, &bus->devices, bus_list) { | 55 | list_for_each_entry(dev, &bus->devices, bus_list) { |
| 56 | u16 class = dev->class >> 8; | 56 | u16 class = dev->class >> 8; |
| 57 | 57 | ||
| 58 | /* Don't touch classless devices and host bridges. */ | 58 | /* Don't touch classless devices or host bridges or ioapics. */ |
| 59 | if (class == PCI_CLASS_NOT_DEFINED || | 59 | if (class == PCI_CLASS_NOT_DEFINED || |
| 60 | class == PCI_CLASS_BRIDGE_HOST) | 60 | class == PCI_CLASS_BRIDGE_HOST || |
| 61 | class == PCI_CLASS_SYSTEM_PIC) | ||
| 61 | continue; | 62 | continue; |
| 62 | 63 | ||
| 63 | pdev_sort_resources(dev, &head); | 64 | pdev_sort_resources(dev, &head); |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
| @@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
| 155 | return ret; | 155 | return ret; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | #ifdef CONFIG_EMBEDDED | ||
| 159 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) | ||
| 160 | { | ||
| 161 | struct pci_bus *bus = dev->bus; | ||
| 162 | struct resource *res = dev->resource + resno; | ||
| 163 | unsigned int type_mask; | ||
| 164 | int i, ret = -EBUSY; | ||
| 165 | |||
| 166 | type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
| 167 | |||
| 168 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | ||
| 169 | struct resource *r = bus->resource[i]; | ||
| 170 | if (!r) | ||
| 171 | continue; | ||
| 172 | |||
| 173 | /* type_mask must match */ | ||
| 174 | if ((res->flags ^ r->flags) & type_mask) | ||
| 175 | continue; | ||
| 176 | |||
| 177 | ret = request_resource(r, res); | ||
| 178 | |||
| 179 | if (ret == 0) | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (ret) { | ||
| 184 | printk(KERN_ERR "PCI: Failed to allocate %s resource " | ||
| 185 | "#%d:%llx@%llx for %s\n", | ||
| 186 | res->flags & IORESOURCE_IO ? "I/O" : "mem", | ||
| 187 | resno, (unsigned long long)(res->end - res->start + 1), | ||
| 188 | (unsigned long long)res->start, pci_name(dev)); | ||
| 189 | } else if (resno < PCI_BRIDGE_RESOURCES) { | ||
| 190 | pci_update_resource(dev, res, resno); | ||
| 191 | } | ||
| 192 | |||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); | ||
| 196 | #endif | ||
| 197 | |||
| 158 | /* Sort resources by alignment */ | 198 | /* Sort resources by alignment */ |
| 159 | void __devinit | 199 | void __devinit |
| 160 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | 200 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 77bb2351500c..680f6063954b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c | |||
| @@ -397,30 +397,6 @@ | |||
| 397 | #include "ql1280_fw.h" | 397 | #include "ql1280_fw.h" |
| 398 | #include "ql1040_fw.h" | 398 | #include "ql1040_fw.h" |
| 399 | 399 | ||
| 400 | |||
| 401 | /* | ||
| 402 | * Missing PCI ID's | ||
| 403 | */ | ||
| 404 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1080 | ||
| 405 | #define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 | ||
| 406 | #endif | ||
| 407 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1240 | ||
| 408 | #define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 | ||
| 409 | #endif | ||
| 410 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1280 | ||
| 411 | #define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 | ||
| 412 | #endif | ||
| 413 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP10160 | ||
| 414 | #define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 | ||
| 415 | #endif | ||
| 416 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP12160 | ||
| 417 | #define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 | ||
| 418 | #endif | ||
| 419 | |||
| 420 | #ifndef PCI_VENDOR_ID_AMI | ||
| 421 | #define PCI_VENDOR_ID_AMI 0x101e | ||
| 422 | #endif | ||
| 423 | |||
| 424 | #ifndef BITS_PER_LONG | 400 | #ifndef BITS_PER_LONG |
| 425 | #error "BITS_PER_LONG not defined!" | 401 | #error "BITS_PER_LONG not defined!" |
| 426 | #endif | 402 | #endif |
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 8a29ce340b47..27d658704cf9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c | |||
| @@ -433,13 +433,14 @@ err_out: | |||
| 433 | 433 | ||
| 434 | 434 | ||
| 435 | /* | 435 | /* |
| 436 | * 0x1725/0x7174 is the Vitesse VSC-7174 | 436 | * Intel 31244 is supposed to be identical. |
| 437 | * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical | 437 | * Compatibility is untested as of yet. |
| 438 | * compatibility is untested as of yet | ||
| 439 | */ | 438 | */ |
| 440 | static const struct pci_device_id vsc_sata_pci_tbl[] = { | 439 | static const struct pci_device_id vsc_sata_pci_tbl[] = { |
| 441 | { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 440 | { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174, |
| 442 | { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 441 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, |
| 442 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244, | ||
| 443 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | ||
| 443 | { } | 444 | { } |
| 444 | }; | 445 | }; |
| 445 | 446 | ||
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 989e4d49e5bb..7f939d066a5a 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c | |||
| @@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void) | |||
| 313 | mda_num_columns = 80; | 313 | mda_num_columns = 80; |
| 314 | mda_num_lines = 25; | 314 | mda_num_lines = 25; |
| 315 | 315 | ||
| 316 | mda_vram_base = VGA_MAP_MEM(0xb0000); | ||
| 317 | mda_vram_len = 0x01000; | 316 | mda_vram_len = 0x01000; |
| 317 | mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len); | ||
| 318 | 318 | ||
| 319 | mda_index_port = 0x3b4; | 319 | mda_index_port = 0x3b4; |
| 320 | mda_value_port = 0x3b5; | 320 | mda_value_port = 0x3b5; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d5a04b68c4d4..e64d42e2449e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
| @@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void) | |||
| 391 | static struct resource ega_console_resource = | 391 | static struct resource ega_console_resource = |
| 392 | { "ega", 0x3B0, 0x3BF }; | 392 | { "ega", 0x3B0, 0x3BF }; |
| 393 | vga_video_type = VIDEO_TYPE_EGAM; | 393 | vga_video_type = VIDEO_TYPE_EGAM; |
| 394 | vga_vram_end = 0xb8000; | 394 | vga_vram_size = 0x8000; |
| 395 | display_desc = "EGA+"; | 395 | display_desc = "EGA+"; |
| 396 | request_resource(&ioport_resource, | 396 | request_resource(&ioport_resource, |
| 397 | &ega_console_resource); | 397 | &ega_console_resource); |
| @@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void) | |||
| 401 | static struct resource mda2_console_resource = | 401 | static struct resource mda2_console_resource = |
| 402 | { "mda", 0x3BF, 0x3BF }; | 402 | { "mda", 0x3BF, 0x3BF }; |
| 403 | vga_video_type = VIDEO_TYPE_MDA; | 403 | vga_video_type = VIDEO_TYPE_MDA; |
| 404 | vga_vram_end = 0xb2000; | 404 | vga_vram_size = 0x2000; |
| 405 | display_desc = "*MDA"; | 405 | display_desc = "*MDA"; |
| 406 | request_resource(&ioport_resource, | 406 | request_resource(&ioport_resource, |
| 407 | &mda1_console_resource); | 407 | &mda1_console_resource); |
| @@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void) | |||
| 418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { | 418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { |
| 419 | int i; | 419 | int i; |
| 420 | 420 | ||
| 421 | vga_vram_end = 0xc0000; | 421 | vga_vram_size = 0x8000; |
| 422 | 422 | ||
| 423 | if (!ORIG_VIDEO_ISVGA) { | 423 | if (!ORIG_VIDEO_ISVGA) { |
| 424 | static struct resource ega_console_resource | 424 | static struct resource ega_console_resource |
| @@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void) | |||
| 443 | * and COE=1 isn't necessarily a good idea) | 443 | * and COE=1 isn't necessarily a good idea) |
| 444 | */ | 444 | */ |
| 445 | vga_vram_base = 0xa0000; | 445 | vga_vram_base = 0xa0000; |
| 446 | vga_vram_end = 0xb0000; | 446 | vga_vram_size = 0x10000; |
| 447 | outb_p(6, VGA_GFX_I); | 447 | outb_p(6, VGA_GFX_I); |
| 448 | outb_p(6, VGA_GFX_D); | 448 | outb_p(6, VGA_GFX_D); |
| 449 | #endif | 449 | #endif |
| @@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void) | |||
| 475 | static struct resource cga_console_resource = | 475 | static struct resource cga_console_resource = |
| 476 | { "cga", 0x3D4, 0x3D5 }; | 476 | { "cga", 0x3D4, 0x3D5 }; |
| 477 | vga_video_type = VIDEO_TYPE_CGA; | 477 | vga_video_type = VIDEO_TYPE_CGA; |
| 478 | vga_vram_end = 0xba000; | 478 | vga_vram_size = 0x2000; |
| 479 | display_desc = "*CGA"; | 479 | display_desc = "*CGA"; |
| 480 | request_resource(&ioport_resource, | 480 | request_resource(&ioport_resource, |
| 481 | &cga_console_resource); | 481 | &cga_console_resource); |
| @@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void) | |||
| 483 | } | 483 | } |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base); | 486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); |
| 487 | vga_vram_end = VGA_MAP_MEM(vga_vram_end); | 487 | vga_vram_end = vga_vram_base + vga_vram_size; |
| 488 | vga_vram_size = vga_vram_end - vga_vram_base; | ||
| 489 | 488 | ||
| 490 | /* | 489 | /* |
| 491 | * Find out if there is a graphics card present. | 490 | * Find out if there is a graphics card present. |
| @@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) | |||
| 1020 | char *charmap; | 1019 | char *charmap; |
| 1021 | 1020 | ||
| 1022 | if (vga_video_type != VIDEO_TYPE_EGAM) { | 1021 | if (vga_video_type != VIDEO_TYPE_EGAM) { |
| 1023 | charmap = (char *) VGA_MAP_MEM(colourmap); | 1022 | charmap = (char *) VGA_MAP_MEM(colourmap, 0); |
| 1024 | beg = 0x0e; | 1023 | beg = 0x0e; |
| 1025 | #ifdef VGA_CAN_DO_64KB | 1024 | #ifdef VGA_CAN_DO_64KB |
| 1026 | if (vga_video_type == VIDEO_TYPE_VGAC) | 1025 | if (vga_video_type == VIDEO_TYPE_VGAC) |
| 1027 | beg = 0x06; | 1026 | beg = 0x06; |
| 1028 | #endif | 1027 | #endif |
| 1029 | } else { | 1028 | } else { |
| 1030 | charmap = (char *) VGA_MAP_MEM(blackwmap); | 1029 | charmap = (char *) VGA_MAP_MEM(blackwmap, 0); |
| 1031 | beg = 0x0a; | 1030 | beg = 0x0a; |
| 1032 | } | 1031 | } |
| 1033 | 1032 | ||
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index f3f16fd9f231..4fd2a272e03d 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
| @@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device) | |||
| 1351 | } | 1351 | } |
| 1352 | 1352 | ||
| 1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ | 1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ |
| 1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); | 1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); |
| 1355 | 1355 | ||
| 1356 | if (!info->screen_base) { | 1356 | if (!info->screen_base) { |
| 1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); | 1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); |
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 5e61ed59a41e..f2d9a08e89ae 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig | |||
| @@ -3,7 +3,7 @@ menu "Dallas's 1-wire bus" | |||
| 3 | config W1 | 3 | config W1 |
| 4 | tristate "Dallas's 1-wire support" | 4 | tristate "Dallas's 1-wire support" |
| 5 | ---help--- | 5 | ---help--- |
| 6 | Dallas's 1-wire bus is useful to connect slow 1-pin devices | 6 | Dallas' 1-wire bus is useful to connect slow 1-pin devices |
| 7 | such as iButtons and thermal sensors. | 7 | such as iButtons and thermal sensors. |
| 8 | 8 | ||
| 9 | If you want W1 support, you should say Y here. | 9 | If you want W1 support, you should say Y here. |
| @@ -11,6 +11,18 @@ config W1 | |||
| 11 | This W1 support can also be built as a module. If so, the module | 11 | This W1 support can also be built as a module. If so, the module |
| 12 | will be called wire.ko. | 12 | will be called wire.ko. |
| 13 | 13 | ||
| 14 | config W1_CON | ||
| 15 | depends on CONNECTOR && W1 | ||
| 16 | bool "Userspace communication over connector" | ||
| 17 | default y | ||
| 18 | --- help --- | ||
| 19 | This allows to communicate with userspace using connector [Documentation/connector]. | ||
| 20 | There are three types of messages between w1 core and userspace: | ||
| 21 | 1. Events. They are generated each time new master or slave device found | ||
| 22 | either due to automatic or requested search. | ||
| 23 | 2. Userspace commands. Includes read/write and search/alarm search comamnds. | ||
| 24 | 3. Replies to userspace commands. | ||
| 25 | |||
| 14 | source drivers/w1/masters/Kconfig | 26 | source drivers/w1/masters/Kconfig |
| 15 | source drivers/w1/slaves/Kconfig | 27 | source drivers/w1/slaves/Kconfig |
| 16 | 28 | ||
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index 0c2aa22d8c04..93845a2c7c21 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile | |||
| @@ -2,10 +2,6 @@ | |||
| 2 | # Makefile for the Dallas's 1-wire bus. | 2 | # Makefile for the Dallas's 1-wire bus. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | ifneq ($(CONFIG_NET), y) | ||
| 6 | EXTRA_CFLAGS += -DNETLINK_DISABLED | ||
| 7 | endif | ||
| 8 | |||
| 9 | ifeq ($(CONFIG_W1_DS2433_CRC), y) | 5 | ifeq ($(CONFIG_W1_DS2433_CRC), y) |
| 10 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC | 6 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC |
| 11 | endif | 7 | endif |
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index c6bad4dbdc64..2fb425536eae 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig | |||
| @@ -15,24 +15,15 @@ config W1_MASTER_MATROX | |||
| 15 | This support is also available as a module. If so, the module | 15 | This support is also available as a module. If so, the module |
| 16 | will be called matrox_w1.ko. | 16 | will be called matrox_w1.ko. |
| 17 | 17 | ||
| 18 | config W1_MASTER_DS9490 | 18 | config W1_MASTER_DS2490 |
| 19 | tristate "DS9490R transport layer driver" | 19 | tristate "DS2490 USB <-> W1 transport layer for 1-wire" |
| 20 | depends on W1 && USB | 20 | depends on W1 && USB |
| 21 | help | 21 | help |
| 22 | Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. | 22 | Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, |
| 23 | 23 | for example DS9490*. | |
| 24 | This support is also available as a module. If so, the module | 24 | |
| 25 | will be called ds9490r.ko. | 25 | This support is also available as a module. If so, the module |
| 26 | 26 | will be called ds2490.ko. | |
| 27 | config W1_MASTER_DS9490_BRIDGE | ||
| 28 | tristate "DS9490R USB <-> W1 transport layer for 1-wire" | ||
| 29 | depends on W1_MASTER_DS9490 | ||
| 30 | help | ||
| 31 | Say Y here if you want to communicate with your 1-wire devices | ||
| 32 | using DS9490R USB bridge. | ||
| 33 | |||
| 34 | This support is also available as a module. If so, the module | ||
| 35 | will be called ds_w1_bridge.ko. | ||
| 36 | 27 | ||
| 37 | config W1_MASTER_DS2482 | 28 | config W1_MASTER_DS2482 |
| 38 | tristate "Maxim DS2482 I2C to 1-Wire bridge" | 29 | tristate "Maxim DS2482 I2C to 1-Wire bridge" |
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index 1f3c8b983dc1..4cee256a8134 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile | |||
| @@ -3,11 +3,6 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o | 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o |
| 6 | 6 | obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o | |
| 7 | obj-$(CONFIG_W1_MASTER_DS9490) += ds9490r.o | ||
| 8 | ds9490r-objs := dscore.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE) += ds_w1_bridge.o | ||
| 11 | |||
| 12 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o | 7 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o |
| 13 | 8 | ||
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index d1cacd23576b..af492cc48db2 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c | |||
| @@ -125,7 +125,7 @@ struct ds2482_w1_chan { | |||
| 125 | 125 | ||
| 126 | struct ds2482_data { | 126 | struct ds2482_data { |
| 127 | struct i2c_client client; | 127 | struct i2c_client client; |
| 128 | struct semaphore access_lock; | 128 | struct mutex access_lock; |
| 129 | 129 | ||
| 130 | /* 1-wire interface(s) */ | 130 | /* 1-wire interface(s) */ |
| 131 | int w1_count; /* 1 or 8 */ | 131 | int w1_count; /* 1 or 8 */ |
| @@ -265,7 +265,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
| 265 | struct ds2482_data *pdev = pchan->pdev; | 265 | struct ds2482_data *pdev = pchan->pdev; |
| 266 | int status = -1; | 266 | int status = -1; |
| 267 | 267 | ||
| 268 | down(&pdev->access_lock); | 268 | mutex_lock(&pdev->access_lock); |
| 269 | 269 | ||
| 270 | /* Select the channel */ | 270 | /* Select the channel */ |
| 271 | ds2482_wait_1wire_idle(pdev); | 271 | ds2482_wait_1wire_idle(pdev); |
| @@ -277,7 +277,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
| 277 | bit ? 0xFF : 0)) | 277 | bit ? 0xFF : 0)) |
| 278 | status = ds2482_wait_1wire_idle(pdev); | 278 | status = ds2482_wait_1wire_idle(pdev); |
| 279 | 279 | ||
| 280 | up(&pdev->access_lock); | 280 | mutex_unlock(&pdev->access_lock); |
| 281 | 281 | ||
| 282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; | 282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; |
| 283 | } | 283 | } |
| @@ -297,7 +297,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
| 297 | struct ds2482_data *pdev = pchan->pdev; | 297 | struct ds2482_data *pdev = pchan->pdev; |
| 298 | int status = (3 << 5); | 298 | int status = (3 << 5); |
| 299 | 299 | ||
| 300 | down(&pdev->access_lock); | 300 | mutex_lock(&pdev->access_lock); |
| 301 | 301 | ||
| 302 | /* Select the channel */ | 302 | /* Select the channel */ |
| 303 | ds2482_wait_1wire_idle(pdev); | 303 | ds2482_wait_1wire_idle(pdev); |
| @@ -309,7 +309,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
| 309 | dbit ? 0xFF : 0)) | 309 | dbit ? 0xFF : 0)) |
| 310 | status = ds2482_wait_1wire_idle(pdev); | 310 | status = ds2482_wait_1wire_idle(pdev); |
| 311 | 311 | ||
| 312 | up(&pdev->access_lock); | 312 | mutex_unlock(&pdev->access_lock); |
| 313 | 313 | ||
| 314 | /* Decode the status */ | 314 | /* Decode the status */ |
| 315 | return (status >> 5); | 315 | return (status >> 5); |
| @@ -326,7 +326,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
| 326 | struct ds2482_w1_chan *pchan = data; | 326 | struct ds2482_w1_chan *pchan = data; |
| 327 | struct ds2482_data *pdev = pchan->pdev; | 327 | struct ds2482_data *pdev = pchan->pdev; |
| 328 | 328 | ||
| 329 | down(&pdev->access_lock); | 329 | mutex_lock(&pdev->access_lock); |
| 330 | 330 | ||
| 331 | /* Select the channel */ | 331 | /* Select the channel */ |
| 332 | ds2482_wait_1wire_idle(pdev); | 332 | ds2482_wait_1wire_idle(pdev); |
| @@ -336,7 +336,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
| 336 | /* Send the write byte command */ | 336 | /* Send the write byte command */ |
| 337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); | 337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); |
| 338 | 338 | ||
| 339 | up(&pdev->access_lock); | 339 | mutex_unlock(&pdev->access_lock); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | /** | 342 | /** |
| @@ -351,7 +351,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
| 351 | struct ds2482_data *pdev = pchan->pdev; | 351 | struct ds2482_data *pdev = pchan->pdev; |
| 352 | int result; | 352 | int result; |
| 353 | 353 | ||
| 354 | down(&pdev->access_lock); | 354 | mutex_lock(&pdev->access_lock); |
| 355 | 355 | ||
| 356 | /* Select the channel */ | 356 | /* Select the channel */ |
| 357 | ds2482_wait_1wire_idle(pdev); | 357 | ds2482_wait_1wire_idle(pdev); |
| @@ -370,7 +370,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
| 370 | /* Read the data byte */ | 370 | /* Read the data byte */ |
| 371 | result = i2c_smbus_read_byte(&pdev->client); | 371 | result = i2c_smbus_read_byte(&pdev->client); |
| 372 | 372 | ||
| 373 | up(&pdev->access_lock); | 373 | mutex_unlock(&pdev->access_lock); |
| 374 | 374 | ||
| 375 | return result; | 375 | return result; |
| 376 | } | 376 | } |
| @@ -389,7 +389,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
| 389 | int err; | 389 | int err; |
| 390 | u8 retval = 1; | 390 | u8 retval = 1; |
| 391 | 391 | ||
| 392 | down(&pdev->access_lock); | 392 | mutex_lock(&pdev->access_lock); |
| 393 | 393 | ||
| 394 | /* Select the channel */ | 394 | /* Select the channel */ |
| 395 | ds2482_wait_1wire_idle(pdev); | 395 | ds2482_wait_1wire_idle(pdev); |
| @@ -409,7 +409,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
| 409 | 0xF0); | 409 | 0xF0); |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | up(&pdev->access_lock); | 412 | mutex_unlock(&pdev->access_lock); |
| 413 | 413 | ||
| 414 | return retval; | 414 | return retval; |
| 415 | } | 415 | } |
| @@ -482,7 +482,7 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", | 482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", |
| 483 | data->w1_count); | 483 | data->w1_count); |
| 484 | 484 | ||
| 485 | init_MUTEX(&data->access_lock); | 485 | mutex_init(&data->access_lock); |
| 486 | 486 | ||
| 487 | /* Tell the I2C layer a new client has arrived */ | 487 | /* Tell the I2C layer a new client has arrived */ |
| 488 | if ((err = i2c_attach_client(new_client))) | 488 | if ((err = i2c_attach_client(new_client))) |
diff --git a/drivers/w1/masters/dscore.c b/drivers/w1/masters/ds2490.c index 2cf7776a7080..299e274d241a 100644 --- a/drivers/w1/masters/dscore.c +++ b/drivers/w1/masters/ds2490.c | |||
| @@ -24,7 +24,136 @@ | |||
| 24 | #include <linux/mod_devicetable.h> | 24 | #include <linux/mod_devicetable.h> |
| 25 | #include <linux/usb.h> | 25 | #include <linux/usb.h> |
| 26 | 26 | ||
| 27 | #include "dscore.h" | 27 | #include "../w1_int.h" |
| 28 | #include "../w1.h" | ||
| 29 | |||
| 30 | /* COMMAND TYPE CODES */ | ||
| 31 | #define CONTROL_CMD 0x00 | ||
| 32 | #define COMM_CMD 0x01 | ||
| 33 | #define MODE_CMD 0x02 | ||
| 34 | |||
| 35 | /* CONTROL COMMAND CODES */ | ||
| 36 | #define CTL_RESET_DEVICE 0x0000 | ||
| 37 | #define CTL_START_EXE 0x0001 | ||
| 38 | #define CTL_RESUME_EXE 0x0002 | ||
| 39 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
| 40 | #define CTL_HALT_EXE_DONE 0x0004 | ||
| 41 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
| 42 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
| 43 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
| 44 | #define CTL_GET_COMM_CMDS 0x000A | ||
| 45 | |||
| 46 | /* MODE COMMAND CODES */ | ||
| 47 | #define MOD_PULSE_EN 0x0000 | ||
| 48 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
| 49 | #define MOD_1WIRE_SPEED 0x0002 | ||
| 50 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
| 51 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
| 52 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
| 53 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
| 54 | #define MOD_DSOW0_TREC 0x0007 | ||
| 55 | |||
| 56 | /* COMMUNICATION COMMAND CODES */ | ||
| 57 | #define COMM_ERROR_ESCAPE 0x0601 | ||
| 58 | #define COMM_SET_DURATION 0x0012 | ||
| 59 | #define COMM_BIT_IO 0x0020 | ||
| 60 | #define COMM_PULSE 0x0030 | ||
| 61 | #define COMM_1_WIRE_RESET 0x0042 | ||
| 62 | #define COMM_BYTE_IO 0x0052 | ||
| 63 | #define COMM_MATCH_ACCESS 0x0064 | ||
| 64 | #define COMM_BLOCK_IO 0x0074 | ||
| 65 | #define COMM_READ_STRAIGHT 0x0080 | ||
| 66 | #define COMM_DO_RELEASE 0x6092 | ||
| 67 | #define COMM_SET_PATH 0x00A2 | ||
| 68 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
| 69 | #define COMM_WRITE_EPROM 0x00C4 | ||
| 70 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
| 71 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
| 72 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
| 73 | |||
| 74 | /* Communication command bits */ | ||
| 75 | #define COMM_TYPE 0x0008 | ||
| 76 | #define COMM_SE 0x0008 | ||
| 77 | #define COMM_D 0x0008 | ||
| 78 | #define COMM_Z 0x0008 | ||
| 79 | #define COMM_CH 0x0008 | ||
| 80 | #define COMM_SM 0x0008 | ||
| 81 | #define COMM_R 0x0008 | ||
| 82 | #define COMM_IM 0x0001 | ||
| 83 | |||
| 84 | #define COMM_PS 0x4000 | ||
| 85 | #define COMM_PST 0x4000 | ||
| 86 | #define COMM_CIB 0x4000 | ||
| 87 | #define COMM_RTS 0x4000 | ||
| 88 | #define COMM_DT 0x2000 | ||
| 89 | #define COMM_SPU 0x1000 | ||
| 90 | #define COMM_F 0x0800 | ||
| 91 | #define COMM_NTP 0x0400 | ||
| 92 | #define COMM_ICP 0x0200 | ||
| 93 | #define COMM_RST 0x0100 | ||
| 94 | |||
| 95 | #define PULSE_PROG 0x01 | ||
| 96 | #define PULSE_SPUE 0x02 | ||
| 97 | |||
| 98 | #define BRANCH_MAIN 0xCC | ||
| 99 | #define BRANCH_AUX 0x33 | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Duration of the strong pull-up pulse in milliseconds. | ||
| 103 | */ | ||
| 104 | #define PULLUP_PULSE_DURATION 750 | ||
| 105 | |||
| 106 | /* Status flags */ | ||
| 107 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
| 108 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
| 109 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
| 110 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
| 111 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
| 112 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
| 113 | #define ST_EPOF 0x80 | ||
| 114 | |||
| 115 | #define SPEED_NORMAL 0x00 | ||
| 116 | #define SPEED_FLEXIBLE 0x01 | ||
| 117 | #define SPEED_OVERDRIVE 0x02 | ||
| 118 | |||
| 119 | #define NUM_EP 4 | ||
| 120 | #define EP_CONTROL 0 | ||
| 121 | #define EP_STATUS 1 | ||
| 122 | #define EP_DATA_OUT 2 | ||
| 123 | #define EP_DATA_IN 3 | ||
| 124 | |||
| 125 | struct ds_device | ||
| 126 | { | ||
| 127 | struct list_head ds_entry; | ||
| 128 | |||
| 129 | struct usb_device *udev; | ||
| 130 | struct usb_interface *intf; | ||
| 131 | |||
| 132 | int ep[NUM_EP]; | ||
| 133 | |||
| 134 | struct w1_bus_master master; | ||
| 135 | }; | ||
| 136 | |||
| 137 | struct ds_status | ||
| 138 | { | ||
| 139 | u8 enable; | ||
| 140 | u8 speed; | ||
| 141 | u8 pullup_dur; | ||
| 142 | u8 ppuls_dur; | ||
| 143 | u8 pulldown_slew; | ||
| 144 | u8 write1_time; | ||
| 145 | u8 write0_time; | ||
| 146 | u8 reserved0; | ||
| 147 | u8 status; | ||
| 148 | u8 command0; | ||
| 149 | u8 command1; | ||
| 150 | u8 command_buffer_status; | ||
| 151 | u8 data_out_buffer_status; | ||
| 152 | u8 data_in_buffer_status; | ||
| 153 | u8 reserved1; | ||
| 154 | u8 reserved2; | ||
| 155 | |||
| 156 | }; | ||
| 28 | 157 | ||
| 29 | static struct usb_device_id ds_id_table [] = { | 158 | static struct usb_device_id ds_id_table [] = { |
| 30 | { USB_DEVICE(0x04fa, 0x2490) }, | 159 | { USB_DEVICE(0x04fa, 0x2490) }, |
| @@ -35,21 +164,12 @@ MODULE_DEVICE_TABLE(usb, ds_id_table); | |||
| 35 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); | 164 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); |
| 36 | static void ds_disconnect(struct usb_interface *); | 165 | static void ds_disconnect(struct usb_interface *); |
| 37 | 166 | ||
| 38 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
| 39 | int ds_read_byte(struct ds_device *, u8 *); | ||
| 40 | int ds_read_bit(struct ds_device *, u8 *); | ||
| 41 | int ds_write_byte(struct ds_device *, u8); | ||
| 42 | int ds_write_bit(struct ds_device *, u8); | ||
| 43 | static int ds_start_pulse(struct ds_device *, int); | ||
| 44 | int ds_reset(struct ds_device *, struct ds_status *); | ||
| 45 | struct ds_device * ds_get_device(void); | ||
| 46 | void ds_put_device(struct ds_device *); | ||
| 47 | |||
| 48 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); | 167 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); |
| 49 | static int ds_send_control(struct ds_device *, u16, u16); | 168 | static int ds_send_control(struct ds_device *, u16, u16); |
| 50 | static int ds_send_control_mode(struct ds_device *, u16, u16); | ||
| 51 | static int ds_send_control_cmd(struct ds_device *, u16, u16); | 169 | static int ds_send_control_cmd(struct ds_device *, u16, u16); |
| 52 | 170 | ||
| 171 | static LIST_HEAD(ds_devices); | ||
| 172 | static DEFINE_MUTEX(ds_mutex); | ||
| 53 | 173 | ||
| 54 | static struct usb_driver ds_driver = { | 174 | static struct usb_driver ds_driver = { |
| 55 | .name = "DS9490R", | 175 | .name = "DS9490R", |
| @@ -58,20 +178,6 @@ static struct usb_driver ds_driver = { | |||
| 58 | .id_table = ds_id_table, | 178 | .id_table = ds_id_table, |
| 59 | }; | 179 | }; |
| 60 | 180 | ||
| 61 | static struct ds_device *ds_dev; | ||
| 62 | |||
| 63 | struct ds_device * ds_get_device(void) | ||
| 64 | { | ||
| 65 | if (ds_dev) | ||
| 66 | atomic_inc(&ds_dev->refcnt); | ||
| 67 | return ds_dev; | ||
| 68 | } | ||
| 69 | |||
| 70 | void ds_put_device(struct ds_device *dev) | ||
| 71 | { | ||
| 72 | atomic_dec(&dev->refcnt); | ||
| 73 | } | ||
| 74 | |||
| 75 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | 181 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) |
| 76 | { | 182 | { |
| 77 | int err; | 183 | int err; |
| @@ -86,7 +192,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | |||
| 86 | 192 | ||
| 87 | return err; | 193 | return err; |
| 88 | } | 194 | } |
| 89 | 195 | #if 0 | |
| 90 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | 196 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) |
| 91 | { | 197 | { |
| 92 | int err; | 198 | int err; |
| @@ -101,7 +207,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | |||
| 101 | 207 | ||
| 102 | return err; | 208 | return err; |
| 103 | } | 209 | } |
| 104 | 210 | #endif | |
| 105 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) | 211 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) |
| 106 | { | 212 | { |
| 107 | int err; | 213 | int err; |
| @@ -324,7 +430,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st) | |||
| 324 | return 0; | 430 | return 0; |
| 325 | } | 431 | } |
| 326 | 432 | ||
| 327 | int ds_reset(struct ds_device *dev, struct ds_status *st) | 433 | static int ds_reset(struct ds_device *dev, struct ds_status *st) |
| 328 | { | 434 | { |
| 329 | int err; | 435 | int err; |
| 330 | 436 | ||
| @@ -345,7 +451,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st) | |||
| 345 | } | 451 | } |
| 346 | 452 | ||
| 347 | #if 0 | 453 | #if 0 |
| 348 | int ds_set_speed(struct ds_device *dev, int speed) | 454 | static int ds_set_speed(struct ds_device *dev, int speed) |
| 349 | { | 455 | { |
| 350 | int err; | 456 | int err; |
| 351 | 457 | ||
| @@ -395,7 +501,7 @@ static int ds_start_pulse(struct ds_device *dev, int delay) | |||
| 395 | return err; | 501 | return err; |
| 396 | } | 502 | } |
| 397 | 503 | ||
| 398 | int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | 504 | static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) |
| 399 | { | 505 | { |
| 400 | int err, count; | 506 | int err, count; |
| 401 | struct ds_status st; | 507 | struct ds_status st; |
| @@ -427,7 +533,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | |||
| 427 | return 0; | 533 | return 0; |
| 428 | } | 534 | } |
| 429 | 535 | ||
| 430 | int ds_write_bit(struct ds_device *dev, u8 bit) | 536 | static int ds_write_bit(struct ds_device *dev, u8 bit) |
| 431 | { | 537 | { |
| 432 | int err; | 538 | int err; |
| 433 | struct ds_status st; | 539 | struct ds_status st; |
| @@ -441,7 +547,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit) | |||
| 441 | return 0; | 547 | return 0; |
| 442 | } | 548 | } |
| 443 | 549 | ||
| 444 | int ds_write_byte(struct ds_device *dev, u8 byte) | 550 | static int ds_write_byte(struct ds_device *dev, u8 byte) |
| 445 | { | 551 | { |
| 446 | int err; | 552 | int err; |
| 447 | struct ds_status st; | 553 | struct ds_status st; |
| @@ -464,26 +570,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte) | |||
| 464 | return !(byte == rbyte); | 570 | return !(byte == rbyte); |
| 465 | } | 571 | } |
| 466 | 572 | ||
| 467 | int ds_read_bit(struct ds_device *dev, u8 *bit) | 573 | static int ds_read_byte(struct ds_device *dev, u8 *byte) |
| 468 | { | ||
| 469 | int err; | ||
| 470 | |||
| 471 | err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); | ||
| 472 | if (err) | ||
| 473 | return err; | ||
| 474 | |||
| 475 | err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0); | ||
| 476 | if (err) | ||
| 477 | return err; | ||
| 478 | |||
| 479 | err = ds_recv_data(dev, bit, sizeof(*bit)); | ||
| 480 | if (err < 0) | ||
| 481 | return err; | ||
| 482 | |||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | int ds_read_byte(struct ds_device *dev, u8 *byte) | ||
| 487 | { | 574 | { |
| 488 | int err; | 575 | int err; |
| 489 | struct ds_status st; | 576 | struct ds_status st; |
| @@ -501,7 +588,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte) | |||
| 501 | return 0; | 588 | return 0; |
| 502 | } | 589 | } |
| 503 | 590 | ||
| 504 | int ds_read_block(struct ds_device *dev, u8 *buf, int len) | 591 | static int ds_read_block(struct ds_device *dev, u8 *buf, int len) |
| 505 | { | 592 | { |
| 506 | struct ds_status st; | 593 | struct ds_status st; |
| 507 | int err; | 594 | int err; |
| @@ -527,7 +614,7 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len) | |||
| 527 | return err; | 614 | return err; |
| 528 | } | 615 | } |
| 529 | 616 | ||
| 530 | int ds_write_block(struct ds_device *dev, u8 *buf, int len) | 617 | static int ds_write_block(struct ds_device *dev, u8 *buf, int len) |
| 531 | { | 618 | { |
| 532 | int err; | 619 | int err; |
| 533 | struct ds_status st; | 620 | struct ds_status st; |
| @@ -555,7 +642,7 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len) | |||
| 555 | 642 | ||
| 556 | #if 0 | 643 | #if 0 |
| 557 | 644 | ||
| 558 | int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) | 645 | static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) |
| 559 | { | 646 | { |
| 560 | int err; | 647 | int err; |
| 561 | u16 value, index; | 648 | u16 value, index; |
| @@ -584,7 +671,7 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi | |||
| 584 | return err/8; | 671 | return err/8; |
| 585 | } | 672 | } |
| 586 | 673 | ||
| 587 | int ds_match_access(struct ds_device *dev, u64 init) | 674 | static int ds_match_access(struct ds_device *dev, u64 init) |
| 588 | { | 675 | { |
| 589 | int err; | 676 | int err; |
| 590 | struct ds_status st; | 677 | struct ds_status st; |
| @@ -604,7 +691,7 @@ int ds_match_access(struct ds_device *dev, u64 init) | |||
| 604 | return 0; | 691 | return 0; |
| 605 | } | 692 | } |
| 606 | 693 | ||
| 607 | int ds_set_path(struct ds_device *dev, u64 init) | 694 | static int ds_set_path(struct ds_device *dev, u64 init) |
| 608 | { | 695 | { |
| 609 | int err; | 696 | int err; |
| 610 | struct ds_status st; | 697 | struct ds_status st; |
| @@ -630,45 +717,156 @@ int ds_set_path(struct ds_device *dev, u64 init) | |||
| 630 | 717 | ||
| 631 | #endif /* 0 */ | 718 | #endif /* 0 */ |
| 632 | 719 | ||
| 720 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
| 721 | { | ||
| 722 | u8 ret; | ||
| 723 | struct ds_device *dev = data; | ||
| 724 | |||
| 725 | if (ds_touch_bit(dev, bit, &ret)) | ||
| 726 | return 0; | ||
| 727 | |||
| 728 | return ret; | ||
| 729 | } | ||
| 730 | |||
| 731 | static void ds9490r_write_bit(void *data, u8 bit) | ||
| 732 | { | ||
| 733 | struct ds_device *dev = data; | ||
| 734 | |||
| 735 | ds_write_bit(dev, bit); | ||
| 736 | } | ||
| 737 | |||
| 738 | static void ds9490r_write_byte(void *data, u8 byte) | ||
| 739 | { | ||
| 740 | struct ds_device *dev = data; | ||
| 741 | |||
| 742 | ds_write_byte(dev, byte); | ||
| 743 | } | ||
| 744 | |||
| 745 | static u8 ds9490r_read_bit(void *data) | ||
| 746 | { | ||
| 747 | struct ds_device *dev = data; | ||
| 748 | int err; | ||
| 749 | u8 bit = 0; | ||
| 750 | |||
| 751 | err = ds_touch_bit(dev, 1, &bit); | ||
| 752 | if (err) | ||
| 753 | return 0; | ||
| 754 | |||
| 755 | return bit & 1; | ||
| 756 | } | ||
| 757 | |||
| 758 | static u8 ds9490r_read_byte(void *data) | ||
| 759 | { | ||
| 760 | struct ds_device *dev = data; | ||
| 761 | int err; | ||
| 762 | u8 byte = 0; | ||
| 763 | |||
| 764 | err = ds_read_byte(dev, &byte); | ||
| 765 | if (err) | ||
| 766 | return 0; | ||
| 767 | |||
| 768 | return byte; | ||
| 769 | } | ||
| 770 | |||
| 771 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
| 772 | { | ||
| 773 | struct ds_device *dev = data; | ||
| 774 | |||
| 775 | ds_write_block(dev, (u8 *)buf, len); | ||
| 776 | } | ||
| 777 | |||
| 778 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
| 779 | { | ||
| 780 | struct ds_device *dev = data; | ||
| 781 | int err; | ||
| 782 | |||
| 783 | err = ds_read_block(dev, buf, len); | ||
| 784 | if (err < 0) | ||
| 785 | return 0; | ||
| 786 | |||
| 787 | return len; | ||
| 788 | } | ||
| 789 | |||
| 790 | static u8 ds9490r_reset(void *data) | ||
| 791 | { | ||
| 792 | struct ds_device *dev = data; | ||
| 793 | struct ds_status st; | ||
| 794 | int err; | ||
| 795 | |||
| 796 | memset(&st, 0, sizeof(st)); | ||
| 797 | |||
| 798 | err = ds_reset(dev, &st); | ||
| 799 | if (err) | ||
| 800 | return 1; | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 805 | static int ds_w1_init(struct ds_device *dev) | ||
| 806 | { | ||
| 807 | memset(&dev->master, 0, sizeof(struct w1_bus_master)); | ||
| 808 | |||
| 809 | dev->master.data = dev; | ||
| 810 | dev->master.touch_bit = &ds9490r_touch_bit; | ||
| 811 | dev->master.read_bit = &ds9490r_read_bit; | ||
| 812 | dev->master.write_bit = &ds9490r_write_bit; | ||
| 813 | dev->master.read_byte = &ds9490r_read_byte; | ||
| 814 | dev->master.write_byte = &ds9490r_write_byte; | ||
| 815 | dev->master.read_block = &ds9490r_read_block; | ||
| 816 | dev->master.write_block = &ds9490r_write_block; | ||
| 817 | dev->master.reset_bus = &ds9490r_reset; | ||
| 818 | |||
| 819 | return w1_add_master_device(&dev->master); | ||
| 820 | } | ||
| 821 | |||
| 822 | static void ds_w1_fini(struct ds_device *dev) | ||
| 823 | { | ||
| 824 | w1_remove_master_device(&dev->master); | ||
| 825 | } | ||
| 826 | |||
| 633 | static int ds_probe(struct usb_interface *intf, | 827 | static int ds_probe(struct usb_interface *intf, |
| 634 | const struct usb_device_id *udev_id) | 828 | const struct usb_device_id *udev_id) |
| 635 | { | 829 | { |
| 636 | struct usb_device *udev = interface_to_usbdev(intf); | 830 | struct usb_device *udev = interface_to_usbdev(intf); |
| 637 | struct usb_endpoint_descriptor *endpoint; | 831 | struct usb_endpoint_descriptor *endpoint; |
| 638 | struct usb_host_interface *iface_desc; | 832 | struct usb_host_interface *iface_desc; |
| 833 | struct ds_device *dev; | ||
| 639 | int i, err; | 834 | int i, err; |
| 640 | 835 | ||
| 641 | ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); | 836 | dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); |
| 642 | if (!ds_dev) { | 837 | if (!dev) { |
| 643 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); | 838 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); |
| 644 | return -ENOMEM; | 839 | return -ENOMEM; |
| 645 | } | 840 | } |
| 841 | dev->udev = usb_get_dev(udev); | ||
| 842 | if (!dev->udev) { | ||
| 843 | err = -ENOMEM; | ||
| 844 | goto err_out_free; | ||
| 845 | } | ||
| 846 | memset(dev->ep, 0, sizeof(dev->ep)); | ||
| 646 | 847 | ||
| 647 | ds_dev->udev = usb_get_dev(udev); | 848 | usb_set_intfdata(intf, dev); |
| 648 | usb_set_intfdata(intf, ds_dev); | ||
| 649 | 849 | ||
| 650 | err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); | 850 | err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); |
| 651 | if (err) { | 851 | if (err) { |
| 652 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", | 852 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", |
| 653 | intf->altsetting[0].desc.bInterfaceNumber, err); | 853 | intf->altsetting[0].desc.bInterfaceNumber, err); |
| 654 | return err; | 854 | goto err_out_clear; |
| 655 | } | 855 | } |
| 656 | 856 | ||
| 657 | err = usb_reset_configuration(ds_dev->udev); | 857 | err = usb_reset_configuration(dev->udev); |
| 658 | if (err) { | 858 | if (err) { |
| 659 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); | 859 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); |
| 660 | return err; | 860 | goto err_out_clear; |
| 661 | } | 861 | } |
| 662 | 862 | ||
| 663 | iface_desc = &intf->altsetting[0]; | 863 | iface_desc = &intf->altsetting[0]; |
| 664 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { | 864 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { |
| 665 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); | 865 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); |
| 666 | return -ENODEV; | 866 | err = -EINVAL; |
| 867 | goto err_out_clear; | ||
| 667 | } | 868 | } |
| 668 | 869 | ||
| 669 | atomic_set(&ds_dev->refcnt, 0); | ||
| 670 | memset(ds_dev->ep, 0, sizeof(ds_dev->ep)); | ||
| 671 | |||
| 672 | /* | 870 | /* |
| 673 | * This loop doesn'd show control 0 endpoint, | 871 | * This loop doesn'd show control 0 endpoint, |
| 674 | * so we will fill only 1-3 endpoints entry. | 872 | * so we will fill only 1-3 endpoints entry. |
| @@ -676,54 +874,31 @@ static int ds_probe(struct usb_interface *intf, | |||
| 676 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 874 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
| 677 | endpoint = &iface_desc->endpoint[i].desc; | 875 | endpoint = &iface_desc->endpoint[i].desc; |
| 678 | 876 | ||
| 679 | ds_dev->ep[i+1] = endpoint->bEndpointAddress; | 877 | dev->ep[i+1] = endpoint->bEndpointAddress; |
| 680 | 878 | #if 0 | |
| 681 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", | 879 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", |
| 682 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), | 880 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), |
| 683 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", | 881 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", |
| 684 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); | 882 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); |
| 883 | #endif | ||
| 685 | } | 884 | } |
| 686 | 885 | ||
| 687 | #if 0 | 886 | err = ds_w1_init(dev); |
| 688 | { | 887 | if (err) |
| 689 | int err, i; | 888 | goto err_out_clear; |
| 690 | u64 buf[3]; | ||
| 691 | u64 init=0xb30000002078ee81ull; | ||
| 692 | struct ds_status st; | ||
| 693 | |||
| 694 | ds_reset(ds_dev, &st); | ||
| 695 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
| 696 | if (err < 0) | ||
| 697 | return err; | ||
| 698 | for (i=0; i<err; ++i) | ||
| 699 | printk("%d: %llx\n", i, buf[i]); | ||
| 700 | |||
| 701 | printk("Resetting...\n"); | ||
| 702 | ds_reset(ds_dev, &st); | ||
| 703 | printk("Setting path for %llx.\n", init); | ||
| 704 | err = ds_set_path(ds_dev, init); | ||
| 705 | if (err) | ||
| 706 | return err; | ||
| 707 | printk("Calling MATCH_ACCESS.\n"); | ||
| 708 | err = ds_match_access(ds_dev, init); | ||
| 709 | if (err) | ||
| 710 | return err; | ||
| 711 | |||
| 712 | printk("Searching the bus...\n"); | ||
| 713 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
| 714 | |||
| 715 | printk("ds_search() returned %d\n", err); | ||
| 716 | |||
| 717 | if (err < 0) | ||
| 718 | return err; | ||
| 719 | for (i=0; i<err; ++i) | ||
| 720 | printk("%d: %llx\n", i, buf[i]); | ||
| 721 | 889 | ||
| 722 | return 0; | 890 | mutex_lock(&ds_mutex); |
| 723 | } | 891 | list_add_tail(&dev->ds_entry, &ds_devices); |
| 724 | #endif | 892 | mutex_unlock(&ds_mutex); |
| 725 | 893 | ||
| 726 | return 0; | 894 | return 0; |
| 895 | |||
| 896 | err_out_clear: | ||
| 897 | usb_set_intfdata(intf, NULL); | ||
| 898 | usb_put_dev(dev->udev); | ||
| 899 | err_out_free: | ||
| 900 | kfree(dev); | ||
| 901 | return err; | ||
| 727 | } | 902 | } |
| 728 | 903 | ||
| 729 | static void ds_disconnect(struct usb_interface *intf) | 904 | static void ds_disconnect(struct usb_interface *intf) |
| @@ -731,19 +906,19 @@ static void ds_disconnect(struct usb_interface *intf) | |||
| 731 | struct ds_device *dev; | 906 | struct ds_device *dev; |
| 732 | 907 | ||
| 733 | dev = usb_get_intfdata(intf); | 908 | dev = usb_get_intfdata(intf); |
| 734 | usb_set_intfdata(intf, NULL); | 909 | if (!dev) |
| 910 | return; | ||
| 735 | 911 | ||
| 736 | while (atomic_read(&dev->refcnt)) { | 912 | mutex_lock(&ds_mutex); |
| 737 | printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n", | 913 | list_del(&dev->ds_entry); |
| 738 | atomic_read(&dev->refcnt)); | 914 | mutex_unlock(&ds_mutex); |
| 739 | 915 | ||
| 740 | if (msleep_interruptible(1000)) | 916 | ds_w1_fini(dev); |
| 741 | flush_signals(current); | 917 | |
| 742 | } | 918 | usb_set_intfdata(intf, NULL); |
| 743 | 919 | ||
| 744 | usb_put_dev(dev->udev); | 920 | usb_put_dev(dev->udev); |
| 745 | kfree(dev); | 921 | kfree(dev); |
| 746 | ds_dev = NULL; | ||
| 747 | } | 922 | } |
| 748 | 923 | ||
| 749 | static int ds_init(void) | 924 | static int ds_init(void) |
| @@ -769,27 +944,4 @@ module_exit(ds_fini); | |||
| 769 | 944 | ||
| 770 | MODULE_LICENSE("GPL"); | 945 | MODULE_LICENSE("GPL"); |
| 771 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | 946 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); |
| 772 | 947 | MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)"); | |
| 773 | EXPORT_SYMBOL(ds_touch_bit); | ||
| 774 | EXPORT_SYMBOL(ds_read_byte); | ||
| 775 | EXPORT_SYMBOL(ds_read_bit); | ||
| 776 | EXPORT_SYMBOL(ds_read_block); | ||
| 777 | EXPORT_SYMBOL(ds_write_byte); | ||
| 778 | EXPORT_SYMBOL(ds_write_bit); | ||
| 779 | EXPORT_SYMBOL(ds_write_block); | ||
| 780 | EXPORT_SYMBOL(ds_reset); | ||
| 781 | EXPORT_SYMBOL(ds_get_device); | ||
| 782 | EXPORT_SYMBOL(ds_put_device); | ||
| 783 | |||
| 784 | /* | ||
| 785 | * This functions can be used for EEPROM programming, | ||
| 786 | * when driver will be included into mainline this will | ||
| 787 | * require uncommenting. | ||
| 788 | */ | ||
| 789 | #if 0 | ||
| 790 | EXPORT_SYMBOL(ds_start_pulse); | ||
| 791 | EXPORT_SYMBOL(ds_set_speed); | ||
| 792 | EXPORT_SYMBOL(ds_detect); | ||
| 793 | EXPORT_SYMBOL(ds_stop_pulse); | ||
| 794 | EXPORT_SYMBOL(ds_search); | ||
| 795 | #endif | ||
diff --git a/drivers/w1/masters/ds_w1_bridge.c b/drivers/w1/masters/ds_w1_bridge.c deleted file mode 100644 index 5d30783a3eb6..000000000000 --- a/drivers/w1/masters/ds_w1_bridge.c +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * ds_w1_bridge.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
| 5 | * | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | |||
| 25 | #include "../w1.h" | ||
| 26 | #include "../w1_int.h" | ||
| 27 | #include "dscore.h" | ||
| 28 | |||
| 29 | static struct ds_device *ds_dev; | ||
| 30 | static struct w1_bus_master *ds_bus_master; | ||
| 31 | |||
| 32 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
| 33 | { | ||
| 34 | u8 ret; | ||
| 35 | struct ds_device *dev = data; | ||
| 36 | |||
| 37 | if (ds_touch_bit(dev, bit, &ret)) | ||
| 38 | return 0; | ||
| 39 | |||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | static void ds9490r_write_bit(void *data, u8 bit) | ||
| 44 | { | ||
| 45 | struct ds_device *dev = data; | ||
| 46 | |||
| 47 | ds_write_bit(dev, bit); | ||
| 48 | } | ||
| 49 | |||
| 50 | static void ds9490r_write_byte(void *data, u8 byte) | ||
| 51 | { | ||
| 52 | struct ds_device *dev = data; | ||
| 53 | |||
| 54 | ds_write_byte(dev, byte); | ||
| 55 | } | ||
| 56 | |||
| 57 | static u8 ds9490r_read_bit(void *data) | ||
| 58 | { | ||
| 59 | struct ds_device *dev = data; | ||
| 60 | int err; | ||
| 61 | u8 bit = 0; | ||
| 62 | |||
| 63 | err = ds_touch_bit(dev, 1, &bit); | ||
| 64 | if (err) | ||
| 65 | return 0; | ||
| 66 | //err = ds_read_bit(dev, &bit); | ||
| 67 | //if (err) | ||
| 68 | // return 0; | ||
| 69 | |||
| 70 | return bit & 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | static u8 ds9490r_read_byte(void *data) | ||
| 74 | { | ||
| 75 | struct ds_device *dev = data; | ||
| 76 | int err; | ||
| 77 | u8 byte = 0; | ||
| 78 | |||
| 79 | err = ds_read_byte(dev, &byte); | ||
| 80 | if (err) | ||
| 81 | return 0; | ||
| 82 | |||
| 83 | return byte; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
| 87 | { | ||
| 88 | struct ds_device *dev = data; | ||
| 89 | |||
| 90 | ds_write_block(dev, (u8 *)buf, len); | ||
| 91 | } | ||
| 92 | |||
| 93 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
| 94 | { | ||
| 95 | struct ds_device *dev = data; | ||
| 96 | int err; | ||
| 97 | |||
| 98 | err = ds_read_block(dev, buf, len); | ||
| 99 | if (err < 0) | ||
| 100 | return 0; | ||
| 101 | |||
| 102 | return len; | ||
| 103 | } | ||
| 104 | |||
| 105 | static u8 ds9490r_reset(void *data) | ||
| 106 | { | ||
| 107 | struct ds_device *dev = data; | ||
| 108 | struct ds_status st; | ||
| 109 | int err; | ||
| 110 | |||
| 111 | memset(&st, 0, sizeof(st)); | ||
| 112 | |||
| 113 | err = ds_reset(dev, &st); | ||
| 114 | if (err) | ||
| 115 | return 1; | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | static int __devinit ds_w1_init(void) | ||
| 121 | { | ||
| 122 | int err; | ||
| 123 | |||
| 124 | ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL); | ||
| 125 | if (!ds_bus_master) { | ||
| 126 | printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n"); | ||
| 127 | return -ENOMEM; | ||
| 128 | } | ||
| 129 | |||
| 130 | ds_dev = ds_get_device(); | ||
| 131 | if (!ds_dev) { | ||
| 132 | printk(KERN_ERR "DS9490R is not registered.\n"); | ||
| 133 | err = -ENODEV; | ||
| 134 | goto err_out_free_bus_master; | ||
| 135 | } | ||
| 136 | |||
| 137 | memset(ds_bus_master, 0, sizeof(*ds_bus_master)); | ||
| 138 | |||
| 139 | ds_bus_master->data = ds_dev; | ||
| 140 | ds_bus_master->touch_bit = &ds9490r_touch_bit; | ||
| 141 | ds_bus_master->read_bit = &ds9490r_read_bit; | ||
| 142 | ds_bus_master->write_bit = &ds9490r_write_bit; | ||
| 143 | ds_bus_master->read_byte = &ds9490r_read_byte; | ||
| 144 | ds_bus_master->write_byte = &ds9490r_write_byte; | ||
| 145 | ds_bus_master->read_block = &ds9490r_read_block; | ||
| 146 | ds_bus_master->write_block = &ds9490r_write_block; | ||
| 147 | ds_bus_master->reset_bus = &ds9490r_reset; | ||
| 148 | |||
| 149 | err = w1_add_master_device(ds_bus_master); | ||
| 150 | if (err) | ||
| 151 | goto err_out_put_device; | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | |||
| 155 | err_out_put_device: | ||
| 156 | ds_put_device(ds_dev); | ||
| 157 | err_out_free_bus_master: | ||
| 158 | kfree(ds_bus_master); | ||
| 159 | |||
| 160 | return err; | ||
| 161 | } | ||
| 162 | |||
| 163 | static void __devexit ds_w1_fini(void) | ||
| 164 | { | ||
| 165 | w1_remove_master_device(ds_bus_master); | ||
| 166 | ds_put_device(ds_dev); | ||
| 167 | kfree(ds_bus_master); | ||
| 168 | } | ||
| 169 | |||
| 170 | module_init(ds_w1_init); | ||
| 171 | module_exit(ds_w1_fini); | ||
| 172 | |||
| 173 | MODULE_LICENSE("GPL"); | ||
| 174 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | ||
diff --git a/drivers/w1/masters/dscore.h b/drivers/w1/masters/dscore.h deleted file mode 100644 index 6cf5671d6ebe..000000000000 --- a/drivers/w1/masters/dscore.h +++ /dev/null | |||
| @@ -1,166 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * dscore.h | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
| 5 | * | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef __DSCORE_H | ||
| 23 | #define __DSCORE_H | ||
| 24 | |||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <asm/atomic.h> | ||
| 27 | |||
| 28 | /* COMMAND TYPE CODES */ | ||
| 29 | #define CONTROL_CMD 0x00 | ||
| 30 | #define COMM_CMD 0x01 | ||
| 31 | #define MODE_CMD 0x02 | ||
| 32 | |||
| 33 | /* CONTROL COMMAND CODES */ | ||
| 34 | #define CTL_RESET_DEVICE 0x0000 | ||
| 35 | #define CTL_START_EXE 0x0001 | ||
| 36 | #define CTL_RESUME_EXE 0x0002 | ||
| 37 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
| 38 | #define CTL_HALT_EXE_DONE 0x0004 | ||
| 39 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
| 40 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
| 41 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
| 42 | #define CTL_GET_COMM_CMDS 0x000A | ||
| 43 | |||
| 44 | /* MODE COMMAND CODES */ | ||
| 45 | #define MOD_PULSE_EN 0x0000 | ||
| 46 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
| 47 | #define MOD_1WIRE_SPEED 0x0002 | ||
| 48 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
| 49 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
| 50 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
| 51 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
| 52 | #define MOD_DSOW0_TREC 0x0007 | ||
| 53 | |||
| 54 | /* COMMUNICATION COMMAND CODES */ | ||
| 55 | #define COMM_ERROR_ESCAPE 0x0601 | ||
| 56 | #define COMM_SET_DURATION 0x0012 | ||
| 57 | #define COMM_BIT_IO 0x0020 | ||
| 58 | #define COMM_PULSE 0x0030 | ||
| 59 | #define COMM_1_WIRE_RESET 0x0042 | ||
| 60 | #define COMM_BYTE_IO 0x0052 | ||
| 61 | #define COMM_MATCH_ACCESS 0x0064 | ||
| 62 | #define COMM_BLOCK_IO 0x0074 | ||
| 63 | #define COMM_READ_STRAIGHT 0x0080 | ||
| 64 | #define COMM_DO_RELEASE 0x6092 | ||
| 65 | #define COMM_SET_PATH 0x00A2 | ||
| 66 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
| 67 | #define COMM_WRITE_EPROM 0x00C4 | ||
| 68 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
| 69 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
| 70 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
| 71 | |||
| 72 | /* Communication command bits */ | ||
| 73 | #define COMM_TYPE 0x0008 | ||
| 74 | #define COMM_SE 0x0008 | ||
| 75 | #define COMM_D 0x0008 | ||
| 76 | #define COMM_Z 0x0008 | ||
| 77 | #define COMM_CH 0x0008 | ||
| 78 | #define COMM_SM 0x0008 | ||
| 79 | #define COMM_R 0x0008 | ||
| 80 | #define COMM_IM 0x0001 | ||
| 81 | |||
| 82 | #define COMM_PS 0x4000 | ||
| 83 | #define COMM_PST 0x4000 | ||
| 84 | #define COMM_CIB 0x4000 | ||
| 85 | #define COMM_RTS 0x4000 | ||
| 86 | #define COMM_DT 0x2000 | ||
| 87 | #define COMM_SPU 0x1000 | ||
| 88 | #define COMM_F 0x0800 | ||
| 89 | #define COMM_NTP 0x0400 | ||
| 90 | #define COMM_ICP 0x0200 | ||
| 91 | #define COMM_RST 0x0100 | ||
| 92 | |||
| 93 | #define PULSE_PROG 0x01 | ||
| 94 | #define PULSE_SPUE 0x02 | ||
| 95 | |||
| 96 | #define BRANCH_MAIN 0xCC | ||
| 97 | #define BRANCH_AUX 0x33 | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Duration of the strong pull-up pulse in milliseconds. | ||
| 101 | */ | ||
| 102 | #define PULLUP_PULSE_DURATION 750 | ||
| 103 | |||
| 104 | /* Status flags */ | ||
| 105 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
| 106 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
| 107 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
| 108 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
| 109 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
| 110 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
| 111 | #define ST_EPOF 0x80 | ||
| 112 | |||
| 113 | #define SPEED_NORMAL 0x00 | ||
| 114 | #define SPEED_FLEXIBLE 0x01 | ||
| 115 | #define SPEED_OVERDRIVE 0x02 | ||
| 116 | |||
| 117 | #define NUM_EP 4 | ||
| 118 | #define EP_CONTROL 0 | ||
| 119 | #define EP_STATUS 1 | ||
| 120 | #define EP_DATA_OUT 2 | ||
| 121 | #define EP_DATA_IN 3 | ||
| 122 | |||
| 123 | struct ds_device | ||
| 124 | { | ||
| 125 | struct usb_device *udev; | ||
| 126 | struct usb_interface *intf; | ||
| 127 | |||
| 128 | int ep[NUM_EP]; | ||
| 129 | |||
| 130 | atomic_t refcnt; | ||
| 131 | }; | ||
| 132 | |||
| 133 | struct ds_status | ||
| 134 | { | ||
| 135 | u8 enable; | ||
| 136 | u8 speed; | ||
| 137 | u8 pullup_dur; | ||
| 138 | u8 ppuls_dur; | ||
| 139 | u8 pulldown_slew; | ||
| 140 | u8 write1_time; | ||
| 141 | u8 write0_time; | ||
| 142 | u8 reserved0; | ||
| 143 | u8 status; | ||
| 144 | u8 command0; | ||
| 145 | u8 command1; | ||
| 146 | u8 command_buffer_status; | ||
| 147 | u8 data_out_buffer_status; | ||
| 148 | u8 data_in_buffer_status; | ||
| 149 | u8 reserved1; | ||
| 150 | u8 reserved2; | ||
| 151 | |||
| 152 | }; | ||
| 153 | |||
| 154 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
| 155 | int ds_read_byte(struct ds_device *, u8 *); | ||
| 156 | int ds_read_bit(struct ds_device *, u8 *); | ||
| 157 | int ds_write_byte(struct ds_device *, u8); | ||
| 158 | int ds_write_bit(struct ds_device *, u8); | ||
| 159 | int ds_reset(struct ds_device *, struct ds_status *); | ||
| 160 | struct ds_device * ds_get_device(void); | ||
| 161 | void ds_put_device(struct ds_device *); | ||
| 162 | int ds_write_block(struct ds_device *, u8 *, int); | ||
| 163 | int ds_read_block(struct ds_device *, u8 *, int); | ||
| 164 | |||
| 165 | #endif /* __DSCORE_H */ | ||
| 166 | |||
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index f9d4c91fc533..d18d6424cd21 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
| @@ -28,7 +28,7 @@ config W1_SLAVE_DS2433 | |||
| 28 | 28 | ||
| 29 | config W1_SLAVE_DS2433_CRC | 29 | config W1_SLAVE_DS2433_CRC |
| 30 | bool "Protect DS2433 data with a CRC16" | 30 | bool "Protect DS2433 data with a CRC16" |
| 31 | depends on W1_DS2433 | 31 | depends on W1_SLAVE_DS2433 |
| 32 | select CRC16 | 32 | select CRC16 |
| 33 | help | 33 | help |
| 34 | Say Y here to protect DS2433 data with a CRC16. | 34 | Say Y here to protect DS2433 data with a CRC16. |
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index fb118be789ea..2ac238f1480e 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | #include "../w1.h" | 24 | #include "../w1.h" |
| 25 | #include "../w1_io.h" | ||
| 26 | #include "../w1_int.h" | 25 | #include "../w1_int.h" |
| 27 | #include "../w1_family.h" | 26 | #include "../w1_family.h" |
| 28 | 27 | ||
| @@ -106,11 +105,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 106 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) | 105 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) |
| 107 | return 0; | 106 | return 0; |
| 108 | 107 | ||
| 109 | atomic_inc(&sl->refcnt); | 108 | mutex_lock(&sl->master->mutex); |
| 110 | if (down_interruptible(&sl->master->mutex)) { | ||
| 111 | count = 0; | ||
| 112 | goto out_dec; | ||
| 113 | } | ||
| 114 | 109 | ||
| 115 | #ifdef CONFIG_W1_F23_CRC | 110 | #ifdef CONFIG_W1_F23_CRC |
| 116 | 111 | ||
| @@ -141,9 +136,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 141 | #endif /* CONFIG_W1_F23_CRC */ | 136 | #endif /* CONFIG_W1_F23_CRC */ |
| 142 | 137 | ||
| 143 | out_up: | 138 | out_up: |
| 144 | up(&sl->master->mutex); | 139 | mutex_unlock(&sl->master->mutex); |
| 145 | out_dec: | ||
| 146 | atomic_dec(&sl->refcnt); | ||
| 147 | 140 | ||
| 148 | return count; | 141 | return count; |
| 149 | } | 142 | } |
| @@ -232,11 +225,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 232 | } | 225 | } |
| 233 | #endif /* CONFIG_W1_F23_CRC */ | 226 | #endif /* CONFIG_W1_F23_CRC */ |
| 234 | 227 | ||
| 235 | atomic_inc(&sl->refcnt); | 228 | mutex_lock(&sl->master->mutex); |
| 236 | if (down_interruptible(&sl->master->mutex)) { | ||
| 237 | count = 0; | ||
| 238 | goto out_dec; | ||
| 239 | } | ||
| 240 | 229 | ||
| 241 | /* Can only write data to one page at a time */ | 230 | /* Can only write data to one page at a time */ |
| 242 | idx = 0; | 231 | idx = 0; |
| @@ -254,9 +243,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 254 | } | 243 | } |
| 255 | 244 | ||
| 256 | out_up: | 245 | out_up: |
| 257 | up(&sl->master->mutex); | 246 | mutex_unlock(&sl->master->mutex); |
| 258 | out_dec: | ||
| 259 | atomic_dec(&sl->refcnt); | ||
| 260 | 247 | ||
| 261 | return count; | 248 | return count; |
| 262 | } | 249 | } |
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c index c6d3be54f94c..cc8c02e92593 100644 --- a/drivers/w1/slaves/w1_smem.c +++ b/drivers/w1/slaves/w1_smem.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| 29 | 29 | ||
| 30 | #include "../w1.h" | 30 | #include "../w1.h" |
| 31 | #include "../w1_io.h" | ||
| 32 | #include "../w1_int.h" | 31 | #include "../w1_int.h" |
| 33 | #include "../w1_family.h" | 32 | #include "../w1_family.h" |
| 34 | 33 | ||
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 536d16d78de7..5372cfcbd054 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
| 30 | 30 | ||
| 31 | #include "../w1.h" | 31 | #include "../w1.h" |
| 32 | #include "../w1_io.h" | ||
| 33 | #include "../w1_int.h" | 32 | #include "../w1_int.h" |
| 34 | #include "../w1_family.h" | 33 | #include "../w1_family.h" |
| 35 | 34 | ||
| @@ -166,12 +165,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
| 166 | u8 rom[9], crc, verdict; | 165 | u8 rom[9], crc, verdict; |
| 167 | int i, max_trying = 10; | 166 | int i, max_trying = 10; |
| 168 | 167 | ||
| 169 | atomic_inc(&sl->refcnt); | 168 | mutex_lock(&sl->master->mutex); |
| 170 | smp_mb__after_atomic_inc(); | ||
| 171 | if (down_interruptible(&sl->master->mutex)) { | ||
| 172 | count = 0; | ||
| 173 | goto out_dec; | ||
| 174 | } | ||
| 175 | 169 | ||
| 176 | if (off > W1_SLAVE_DATA_SIZE) { | 170 | if (off > W1_SLAVE_DATA_SIZE) { |
| 177 | count = 0; | 171 | count = 0; |
| @@ -234,10 +228,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
| 234 | 228 | ||
| 235 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); | 229 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); |
| 236 | out: | 230 | out: |
| 237 | up(&dev->mutex); | 231 | mutex_unlock(&dev->mutex); |
| 238 | out_dec: | ||
| 239 | smp_mb__before_atomic_inc(); | ||
| 240 | atomic_dec(&sl->refcnt); | ||
| 241 | 232 | ||
| 242 | return count; | 233 | return count; |
| 243 | } | 234 | } |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a698b517e863..de3e9791f80d 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
| @@ -35,7 +35,6 @@ | |||
| 35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
| 36 | 36 | ||
| 37 | #include "w1.h" | 37 | #include "w1.h" |
| 38 | #include "w1_io.h" | ||
| 39 | #include "w1_log.h" | 38 | #include "w1_log.h" |
| 40 | #include "w1_int.h" | 39 | #include "w1_int.h" |
| 41 | #include "w1_family.h" | 40 | #include "w1_family.h" |
| @@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_control_timeout, int, 0); | |||
| 55 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); | 54 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
| 56 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | 55 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
| 57 | 56 | ||
| 58 | DEFINE_SPINLOCK(w1_mlock); | 57 | DEFINE_MUTEX(w1_mlock); |
| 59 | LIST_HEAD(w1_masters); | 58 | LIST_HEAD(w1_masters); |
| 60 | 59 | ||
| 61 | static struct task_struct *w1_control_thread; | 60 | static struct task_struct *w1_control_thread; |
| @@ -75,8 +74,6 @@ static void w1_master_release(struct device *dev) | |||
| 75 | struct w1_master *md = dev_to_w1_master(dev); | 74 | struct w1_master *md = dev_to_w1_master(dev); |
| 76 | 75 | ||
| 77 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); | 76 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); |
| 78 | |||
| 79 | dev_fini_netlink(md); | ||
| 80 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | 77 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); |
| 81 | kfree(md); | 78 | kfree(md); |
| 82 | } | 79 | } |
| @@ -85,10 +82,10 @@ static void w1_slave_release(struct device *dev) | |||
| 85 | { | 82 | { |
| 86 | struct w1_slave *sl = dev_to_w1_slave(dev); | 83 | struct w1_slave *sl = dev_to_w1_slave(dev); |
| 87 | 84 | ||
| 88 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); | 85 | printk("%s: Releasing %s.\n", __func__, sl->name); |
| 89 | 86 | ||
| 90 | while (atomic_read(&sl->refcnt)) { | 87 | while (atomic_read(&sl->refcnt)) { |
| 91 | dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", | 88 | printk("Waiting for %s to become free: refcnt=%d.\n", |
| 92 | sl->name, atomic_read(&sl->refcnt)); | 89 | sl->name, atomic_read(&sl->refcnt)); |
| 93 | if (msleep_interruptible(1000)) | 90 | if (msleep_interruptible(1000)) |
| 94 | flush_signals(current); | 91 | flush_signals(current); |
| @@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 111 | { | 108 | { |
| 112 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 109 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
| 113 | 110 | ||
| 114 | atomic_inc(&sl->refcnt); | ||
| 115 | if (off > 8) { | 111 | if (off > 8) { |
| 116 | count = 0; | 112 | count = 0; |
| 117 | } else { | 113 | } else { |
| @@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 120 | 116 | ||
| 121 | memcpy(buf, (u8 *)&sl->reg_num, count); | 117 | memcpy(buf, (u8 *)&sl->reg_num, count); |
| 122 | } | 118 | } |
| 123 | atomic_dec(&sl->refcnt); | ||
| 124 | 119 | ||
| 125 | return count; | 120 | return count; |
| 126 | } | 121 | } |
| @@ -139,7 +134,63 @@ static struct bin_attribute w1_slave_attr_bin_id = { | |||
| 139 | }; | 134 | }; |
| 140 | 135 | ||
| 141 | /* Default family */ | 136 | /* Default family */ |
| 142 | static struct w1_family w1_default_family; | 137 | |
| 138 | static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
| 139 | { | ||
| 140 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 141 | |||
| 142 | mutex_lock(&sl->master->mutex); | ||
| 143 | if (w1_reset_select_slave(sl)) { | ||
| 144 | count = 0; | ||
| 145 | goto out_up; | ||
| 146 | } | ||
| 147 | |||
| 148 | w1_write_block(sl->master, buf, count); | ||
| 149 | |||
| 150 | out_up: | ||
| 151 | mutex_unlock(&sl->master->mutex); | ||
| 152 | return count; | ||
| 153 | } | ||
| 154 | |||
| 155 | static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
| 156 | { | ||
| 157 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 158 | |||
| 159 | mutex_lock(&sl->master->mutex); | ||
| 160 | w1_read_block(sl->master, buf, count); | ||
| 161 | mutex_unlock(&sl->master->mutex); | ||
| 162 | return count; | ||
| 163 | } | ||
| 164 | |||
| 165 | static struct bin_attribute w1_default_attr = { | ||
| 166 | .attr = { | ||
| 167 | .name = "rw", | ||
| 168 | .mode = S_IRUGO | S_IWUSR, | ||
| 169 | .owner = THIS_MODULE, | ||
| 170 | }, | ||
| 171 | .size = PAGE_SIZE, | ||
| 172 | .read = w1_default_read, | ||
| 173 | .write = w1_default_write, | ||
| 174 | }; | ||
| 175 | |||
| 176 | static int w1_default_add_slave(struct w1_slave *sl) | ||
| 177 | { | ||
| 178 | return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
| 179 | } | ||
| 180 | |||
| 181 | static void w1_default_remove_slave(struct w1_slave *sl) | ||
| 182 | { | ||
| 183 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
| 184 | } | ||
| 185 | |||
| 186 | static struct w1_family_ops w1_default_fops = { | ||
| 187 | .add_slave = w1_default_add_slave, | ||
| 188 | .remove_slave = w1_default_remove_slave, | ||
| 189 | }; | ||
| 190 | |||
| 191 | static struct w1_family w1_default_family = { | ||
| 192 | .fops = &w1_default_fops, | ||
| 193 | }; | ||
| 143 | 194 | ||
| 144 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); | 195 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); |
| 145 | 196 | ||
| @@ -183,12 +234,9 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a | |||
| 183 | struct w1_master *md = dev_to_w1_master(dev); | 234 | struct w1_master *md = dev_to_w1_master(dev); |
| 184 | ssize_t count; | 235 | ssize_t count; |
| 185 | 236 | ||
| 186 | if (down_interruptible (&md->mutex)) | 237 | mutex_lock(&md->mutex); |
| 187 | return -EBUSY; | ||
| 188 | |||
| 189 | count = sprintf(buf, "%s\n", md->name); | 238 | count = sprintf(buf, "%s\n", md->name); |
| 190 | 239 | mutex_unlock(&md->mutex); | |
| 191 | up(&md->mutex); | ||
| 192 | 240 | ||
| 193 | return count; | 241 | return count; |
| 194 | } | 242 | } |
| @@ -199,12 +247,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev, | |||
| 199 | { | 247 | { |
| 200 | struct w1_master *md = dev_to_w1_master(dev); | 248 | struct w1_master *md = dev_to_w1_master(dev); |
| 201 | 249 | ||
| 202 | if (down_interruptible (&md->mutex)) | 250 | mutex_lock(&md->mutex); |
| 203 | return -EBUSY; | ||
| 204 | |||
| 205 | md->search_count = simple_strtol(buf, NULL, 0); | 251 | md->search_count = simple_strtol(buf, NULL, 0); |
| 206 | 252 | mutex_unlock(&md->mutex); | |
| 207 | up(&md->mutex); | ||
| 208 | 253 | ||
| 209 | return count; | 254 | return count; |
| 210 | } | 255 | } |
| @@ -216,12 +261,9 @@ static ssize_t w1_master_attribute_show_search(struct device *dev, | |||
| 216 | struct w1_master *md = dev_to_w1_master(dev); | 261 | struct w1_master *md = dev_to_w1_master(dev); |
| 217 | ssize_t count; | 262 | ssize_t count; |
| 218 | 263 | ||
| 219 | if (down_interruptible (&md->mutex)) | 264 | mutex_lock(&md->mutex); |
| 220 | return -EBUSY; | ||
| 221 | |||
| 222 | count = sprintf(buf, "%d\n", md->search_count); | 265 | count = sprintf(buf, "%d\n", md->search_count); |
| 223 | 266 | mutex_unlock(&md->mutex); | |
| 224 | up(&md->mutex); | ||
| 225 | 267 | ||
| 226 | return count; | 268 | return count; |
| 227 | } | 269 | } |
| @@ -231,12 +273,9 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic | |||
| 231 | struct w1_master *md = dev_to_w1_master(dev); | 273 | struct w1_master *md = dev_to_w1_master(dev); |
| 232 | ssize_t count; | 274 | ssize_t count; |
| 233 | 275 | ||
| 234 | if (down_interruptible(&md->mutex)) | 276 | mutex_lock(&md->mutex); |
| 235 | return -EBUSY; | ||
| 236 | |||
| 237 | count = sprintf(buf, "0x%p\n", md->bus_master); | 277 | count = sprintf(buf, "0x%p\n", md->bus_master); |
| 238 | 278 | mutex_unlock(&md->mutex); | |
| 239 | up(&md->mutex); | ||
| 240 | return count; | 279 | return count; |
| 241 | } | 280 | } |
| 242 | 281 | ||
| @@ -252,12 +291,9 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru | |||
| 252 | struct w1_master *md = dev_to_w1_master(dev); | 291 | struct w1_master *md = dev_to_w1_master(dev); |
| 253 | ssize_t count; | 292 | ssize_t count; |
| 254 | 293 | ||
| 255 | if (down_interruptible(&md->mutex)) | 294 | mutex_lock(&md->mutex); |
| 256 | return -EBUSY; | ||
| 257 | |||
| 258 | count = sprintf(buf, "%d\n", md->max_slave_count); | 295 | count = sprintf(buf, "%d\n", md->max_slave_count); |
| 259 | 296 | mutex_unlock(&md->mutex); | |
| 260 | up(&md->mutex); | ||
| 261 | return count; | 297 | return count; |
| 262 | } | 298 | } |
| 263 | 299 | ||
| @@ -266,12 +302,9 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi | |||
| 266 | struct w1_master *md = dev_to_w1_master(dev); | 302 | struct w1_master *md = dev_to_w1_master(dev); |
| 267 | ssize_t count; | 303 | ssize_t count; |
| 268 | 304 | ||
| 269 | if (down_interruptible(&md->mutex)) | 305 | mutex_lock(&md->mutex); |
| 270 | return -EBUSY; | ||
| 271 | |||
| 272 | count = sprintf(buf, "%lu\n", md->attempts); | 306 | count = sprintf(buf, "%lu\n", md->attempts); |
| 273 | 307 | mutex_unlock(&md->mutex); | |
| 274 | up(&md->mutex); | ||
| 275 | return count; | 308 | return count; |
| 276 | } | 309 | } |
| 277 | 310 | ||
| @@ -280,12 +313,9 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d | |||
| 280 | struct w1_master *md = dev_to_w1_master(dev); | 313 | struct w1_master *md = dev_to_w1_master(dev); |
| 281 | ssize_t count; | 314 | ssize_t count; |
| 282 | 315 | ||
| 283 | if (down_interruptible(&md->mutex)) | 316 | mutex_lock(&md->mutex); |
| 284 | return -EBUSY; | ||
| 285 | |||
| 286 | count = sprintf(buf, "%d\n", md->slave_count); | 317 | count = sprintf(buf, "%d\n", md->slave_count); |
| 287 | 318 | mutex_unlock(&md->mutex); | |
| 288 | up(&md->mutex); | ||
| 289 | return count; | 319 | return count; |
| 290 | } | 320 | } |
| 291 | 321 | ||
| @@ -294,8 +324,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
| 294 | struct w1_master *md = dev_to_w1_master(dev); | 324 | struct w1_master *md = dev_to_w1_master(dev); |
| 295 | int c = PAGE_SIZE; | 325 | int c = PAGE_SIZE; |
| 296 | 326 | ||
| 297 | if (down_interruptible(&md->mutex)) | 327 | mutex_lock(&md->mutex); |
| 298 | return -EBUSY; | ||
| 299 | 328 | ||
| 300 | if (md->slave_count == 0) | 329 | if (md->slave_count == 0) |
| 301 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); | 330 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); |
| @@ -310,7 +339,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
| 310 | } | 339 | } |
| 311 | } | 340 | } |
| 312 | 341 | ||
| 313 | up(&md->mutex); | 342 | mutex_unlock(&md->mutex); |
| 314 | 343 | ||
| 315 | return PAGE_SIZE - c; | 344 | return PAGE_SIZE - c; |
| 316 | } | 345 | } |
| @@ -362,7 +391,8 @@ static void w1_destroy_master_attributes(struct w1_master *master) | |||
| 362 | } | 391 | } |
| 363 | 392 | ||
| 364 | #ifdef CONFIG_HOTPLUG | 393 | #ifdef CONFIG_HOTPLUG |
| 365 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 394 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
| 395 | char *buffer, int buffer_size) | ||
| 366 | { | 396 | { |
| 367 | struct w1_master *md = NULL; | 397 | struct w1_master *md = NULL; |
| 368 | struct w1_slave *sl = NULL; | 398 | struct w1_slave *sl = NULL; |
| @@ -382,7 +412,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
| 382 | return -EINVAL; | 412 | return -EINVAL; |
| 383 | } | 413 | } |
| 384 | 414 | ||
| 385 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id); | 415 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", |
| 416 | event_owner, name, dev->bus_id); | ||
| 386 | 417 | ||
| 387 | if (dev->driver != &w1_slave_driver || !sl) | 418 | if (dev->driver != &w1_slave_driver || !sl) |
| 388 | return 0; | 419 | return 0; |
| @@ -401,7 +432,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
| 401 | return 0; | 432 | return 0; |
| 402 | }; | 433 | }; |
| 403 | #else | 434 | #else |
| 404 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 435 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
| 436 | char *buffer, int buffer_size) | ||
| 405 | { | 437 | { |
| 406 | return 0; | 438 | return 0; |
| 407 | } | 439 | } |
| @@ -425,7 +457,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
| 425 | (unsigned int) sl->reg_num.family, | 457 | (unsigned int) sl->reg_num.family, |
| 426 | (unsigned long long) sl->reg_num.id); | 458 | (unsigned long long) sl->reg_num.id); |
| 427 | 459 | ||
| 428 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]); | 460 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, |
| 461 | &sl->dev.bus_id[0]); | ||
| 429 | 462 | ||
| 430 | err = device_register(&sl->dev); | 463 | err = device_register(&sl->dev); |
| 431 | if (err < 0) { | 464 | if (err < 0) { |
| @@ -496,6 +529,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
| 496 | sl->master = dev; | 529 | sl->master = dev; |
| 497 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 530 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
| 498 | 531 | ||
| 532 | memset(&msg, 0, sizeof(msg)); | ||
| 499 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 533 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
| 500 | atomic_set(&sl->refcnt, 0); | 534 | atomic_set(&sl->refcnt, 0); |
| 501 | init_completion(&sl->released); | 535 | init_completion(&sl->released); |
| @@ -526,7 +560,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
| 526 | sl->ttl = dev->slave_ttl; | 560 | sl->ttl = dev->slave_ttl; |
| 527 | dev->slave_count++; | 561 | dev->slave_count++; |
| 528 | 562 | ||
| 529 | memcpy(&msg.id.id, rn, sizeof(msg.id.id)); | 563 | memcpy(msg.id.id, rn, sizeof(msg.id)); |
| 530 | msg.type = W1_SLAVE_ADD; | 564 | msg.type = W1_SLAVE_ADD; |
| 531 | w1_netlink_send(dev, &msg); | 565 | w1_netlink_send(dev, &msg); |
| 532 | 566 | ||
| @@ -544,7 +578,8 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
| 544 | if (sl->family->fops && sl->family->fops->remove_slave) | 578 | if (sl->family->fops && sl->family->fops->remove_slave) |
| 545 | sl->family->fops->remove_slave(sl); | 579 | sl->family->fops->remove_slave(sl); |
| 546 | 580 | ||
| 547 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | 581 | memset(&msg, 0, sizeof(msg)); |
| 582 | memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); | ||
| 548 | msg.type = W1_SLAVE_REMOVE; | 583 | msg.type = W1_SLAVE_REMOVE; |
| 549 | w1_netlink_send(sl->master, &msg); | 584 | w1_netlink_send(sl->master, &msg); |
| 550 | 585 | ||
| @@ -561,7 +596,7 @@ static struct w1_master *w1_search_master(void *data) | |||
| 561 | struct w1_master *dev; | 596 | struct w1_master *dev; |
| 562 | int found = 0; | 597 | int found = 0; |
| 563 | 598 | ||
| 564 | spin_lock_bh(&w1_mlock); | 599 | mutex_lock(&w1_mlock); |
| 565 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 600 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
| 566 | if (dev->bus_master->data == data) { | 601 | if (dev->bus_master->data == data) { |
| 567 | found = 1; | 602 | found = 1; |
| @@ -569,22 +604,69 @@ static struct w1_master *w1_search_master(void *data) | |||
| 569 | break; | 604 | break; |
| 570 | } | 605 | } |
| 571 | } | 606 | } |
| 572 | spin_unlock_bh(&w1_mlock); | 607 | mutex_unlock(&w1_mlock); |
| 608 | |||
| 609 | return (found)?dev:NULL; | ||
| 610 | } | ||
| 611 | |||
| 612 | struct w1_master *w1_search_master_id(u32 id) | ||
| 613 | { | ||
| 614 | struct w1_master *dev; | ||
| 615 | int found = 0; | ||
| 616 | |||
| 617 | mutex_lock(&w1_mlock); | ||
| 618 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
| 619 | if (dev->id == id) { | ||
| 620 | found = 1; | ||
| 621 | atomic_inc(&dev->refcnt); | ||
| 622 | break; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | mutex_unlock(&w1_mlock); | ||
| 573 | 626 | ||
| 574 | return (found)?dev:NULL; | 627 | return (found)?dev:NULL; |
| 575 | } | 628 | } |
| 576 | 629 | ||
| 630 | struct w1_slave *w1_search_slave(struct w1_reg_num *id) | ||
| 631 | { | ||
| 632 | struct w1_master *dev; | ||
| 633 | struct w1_slave *sl = NULL; | ||
| 634 | int found = 0; | ||
| 635 | |||
| 636 | mutex_lock(&w1_mlock); | ||
| 637 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
| 638 | mutex_lock(&dev->mutex); | ||
| 639 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
| 640 | if (sl->reg_num.family == id->family && | ||
| 641 | sl->reg_num.id == id->id && | ||
| 642 | sl->reg_num.crc == id->crc) { | ||
| 643 | found = 1; | ||
| 644 | atomic_inc(&dev->refcnt); | ||
| 645 | atomic_inc(&sl->refcnt); | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | mutex_unlock(&dev->mutex); | ||
| 650 | |||
| 651 | if (found) | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | mutex_unlock(&w1_mlock); | ||
| 655 | |||
| 656 | return (found)?sl:NULL; | ||
| 657 | } | ||
| 658 | |||
| 577 | void w1_reconnect_slaves(struct w1_family *f) | 659 | void w1_reconnect_slaves(struct w1_family *f) |
| 578 | { | 660 | { |
| 579 | struct w1_master *dev; | 661 | struct w1_master *dev; |
| 580 | 662 | ||
| 581 | spin_lock_bh(&w1_mlock); | 663 | mutex_lock(&w1_mlock); |
| 582 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 664 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
| 583 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", | 665 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", |
| 584 | dev->name, f->fid); | 666 | dev->name, f->fid); |
| 585 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 667 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
| 586 | } | 668 | } |
| 587 | spin_unlock_bh(&w1_mlock); | 669 | mutex_unlock(&w1_mlock); |
| 588 | } | 670 | } |
| 589 | 671 | ||
| 590 | static void w1_slave_found(void *data, u64 rn) | 672 | static void w1_slave_found(void *data, u64 rn) |
| @@ -646,7 +728,7 @@ static void w1_slave_found(void *data, u64 rn) | |||
| 646 | * @dev The master device to search | 728 | * @dev The master device to search |
| 647 | * @cb Function to call when a device is found | 729 | * @cb Function to call when a device is found |
| 648 | */ | 730 | */ |
| 649 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | 731 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
| 650 | { | 732 | { |
| 651 | u64 last_rn, rn, tmp64; | 733 | u64 last_rn, rn, tmp64; |
| 652 | int i, slave_count = 0; | 734 | int i, slave_count = 0; |
| @@ -677,7 +759,7 @@ void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | |||
| 677 | } | 759 | } |
| 678 | 760 | ||
| 679 | /* Start the search */ | 761 | /* Start the search */ |
| 680 | w1_write_8(dev, W1_SEARCH); | 762 | w1_write_8(dev, search_type); |
| 681 | for (i = 0; i < 64; ++i) { | 763 | for (i = 0; i < 64; ++i) { |
| 682 | /* Determine the direction/search bit */ | 764 | /* Determine the direction/search bit */ |
| 683 | if (i == desc_bit) | 765 | if (i == desc_bit) |
| @@ -739,23 +821,23 @@ static int w1_control(void *data) | |||
| 739 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 821 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
| 740 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 822 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
| 741 | 823 | ||
| 742 | spin_lock(&w1_mlock); | 824 | mutex_lock(&w1_mlock); |
| 743 | list_del(&dev->w1_master_entry); | 825 | list_del(&dev->w1_master_entry); |
| 744 | spin_unlock(&w1_mlock); | 826 | mutex_unlock(&w1_mlock); |
| 745 | 827 | ||
| 746 | down(&dev->mutex); | 828 | mutex_lock(&dev->mutex); |
| 747 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 829 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
| 748 | w1_slave_detach(sl); | 830 | w1_slave_detach(sl); |
| 749 | } | 831 | } |
| 750 | w1_destroy_master_attributes(dev); | 832 | w1_destroy_master_attributes(dev); |
| 751 | up(&dev->mutex); | 833 | mutex_unlock(&dev->mutex); |
| 752 | atomic_dec(&dev->refcnt); | 834 | atomic_dec(&dev->refcnt); |
| 753 | continue; | 835 | continue; |
| 754 | } | 836 | } |
| 755 | 837 | ||
| 756 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { | 838 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { |
| 757 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); | 839 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); |
| 758 | down(&dev->mutex); | 840 | mutex_lock(&dev->mutex); |
| 759 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 841 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
| 760 | if (sl->family->fid == W1_FAMILY_DEFAULT) { | 842 | if (sl->family->fid == W1_FAMILY_DEFAULT) { |
| 761 | struct w1_reg_num rn; | 843 | struct w1_reg_num rn; |
| @@ -768,7 +850,7 @@ static int w1_control(void *data) | |||
| 768 | } | 850 | } |
| 769 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); | 851 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); |
| 770 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 852 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
| 771 | up(&dev->mutex); | 853 | mutex_unlock(&dev->mutex); |
| 772 | } | 854 | } |
| 773 | } | 855 | } |
| 774 | } | 856 | } |
| @@ -776,10 +858,31 @@ static int w1_control(void *data) | |||
| 776 | return 0; | 858 | return 0; |
| 777 | } | 859 | } |
| 778 | 860 | ||
| 861 | void w1_search_process(struct w1_master *dev, u8 search_type) | ||
| 862 | { | ||
| 863 | struct w1_slave *sl, *sln; | ||
| 864 | |||
| 865 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
| 866 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
| 867 | |||
| 868 | w1_search_devices(dev, search_type, w1_slave_found); | ||
| 869 | |||
| 870 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
| 871 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
| 872 | w1_slave_detach(sl); | ||
| 873 | |||
| 874 | dev->slave_count--; | ||
| 875 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
| 876 | sl->ttl = dev->slave_ttl; | ||
| 877 | } | ||
| 878 | |||
| 879 | if (dev->search_count > 0) | ||
| 880 | dev->search_count--; | ||
| 881 | } | ||
| 882 | |||
| 779 | int w1_process(void *data) | 883 | int w1_process(void *data) |
| 780 | { | 884 | { |
| 781 | struct w1_master *dev = (struct w1_master *) data; | 885 | struct w1_master *dev = (struct w1_master *) data; |
| 782 | struct w1_slave *sl, *sln; | ||
| 783 | 886 | ||
| 784 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 887 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
| 785 | try_to_freeze(); | 888 | try_to_freeze(); |
| @@ -794,27 +897,9 @@ int w1_process(void *data) | |||
| 794 | if (dev->search_count == 0) | 897 | if (dev->search_count == 0) |
| 795 | continue; | 898 | continue; |
| 796 | 899 | ||
| 797 | if (down_interruptible(&dev->mutex)) | 900 | mutex_lock(&dev->mutex); |
| 798 | continue; | 901 | w1_search_process(dev, W1_SEARCH); |
| 799 | 902 | mutex_unlock(&dev->mutex); | |
| 800 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
| 801 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
| 802 | |||
| 803 | w1_search_devices(dev, w1_slave_found); | ||
| 804 | |||
| 805 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
| 806 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
| 807 | w1_slave_detach(sl); | ||
| 808 | |||
| 809 | dev->slave_count--; | ||
| 810 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
| 811 | sl->ttl = dev->slave_ttl; | ||
| 812 | } | ||
| 813 | |||
| 814 | if (dev->search_count > 0) | ||
| 815 | dev->search_count--; | ||
| 816 | |||
| 817 | up(&dev->mutex); | ||
| 818 | } | 903 | } |
| 819 | 904 | ||
| 820 | atomic_dec(&dev->refcnt); | 905 | atomic_dec(&dev->refcnt); |
| @@ -828,6 +913,8 @@ static int w1_init(void) | |||
| 828 | 913 | ||
| 829 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); | 914 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); |
| 830 | 915 | ||
| 916 | w1_init_netlink(); | ||
| 917 | |||
| 831 | retval = bus_register(&w1_bus_type); | 918 | retval = bus_register(&w1_bus_type); |
| 832 | if (retval) { | 919 | if (retval) { |
| 833 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); | 920 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); |
| @@ -880,6 +967,8 @@ static void w1_fini(void) | |||
| 880 | list_for_each_entry(dev, &w1_masters, w1_master_entry) | 967 | list_for_each_entry(dev, &w1_masters, w1_master_entry) |
| 881 | __w1_remove_master_device(dev); | 968 | __w1_remove_master_device(dev); |
| 882 | 969 | ||
| 970 | w1_fini_netlink(); | ||
| 971 | |||
| 883 | kthread_stop(w1_control_thread); | 972 | kthread_stop(w1_control_thread); |
| 884 | 973 | ||
| 885 | driver_unregister(&w1_slave_driver); | 974 | driver_unregister(&w1_slave_driver); |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 56980505e6c4..f1df5343f4ad 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
| @@ -41,10 +41,7 @@ struct w1_reg_num | |||
| 41 | 41 | ||
| 42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
| 43 | #include <linux/device.h> | 43 | #include <linux/device.h> |
| 44 | 44 | #include <linux/mutex.h> | |
| 45 | #include <net/sock.h> | ||
| 46 | |||
| 47 | #include <asm/semaphore.h> | ||
| 48 | 45 | ||
| 49 | #include "w1_family.h" | 46 | #include "w1_family.h" |
| 50 | 47 | ||
| @@ -52,7 +49,7 @@ struct w1_reg_num | |||
| 52 | #define W1_SLAVE_DATA_SIZE 128 | 49 | #define W1_SLAVE_DATA_SIZE 128 |
| 53 | 50 | ||
| 54 | #define W1_SEARCH 0xF0 | 51 | #define W1_SEARCH 0xF0 |
| 55 | #define W1_CONDITIONAL_SEARCH 0xEC | 52 | #define W1_ALARM_SEARCH 0xEC |
| 56 | #define W1_CONVERT_TEMP 0x44 | 53 | #define W1_CONVERT_TEMP 0x44 |
| 57 | #define W1_SKIP_ROM 0xCC | 54 | #define W1_SKIP_ROM 0xCC |
| 58 | #define W1_READ_SCRATCHPAD 0xBE | 55 | #define W1_READ_SCRATCHPAD 0xBE |
| @@ -60,7 +57,7 @@ struct w1_reg_num | |||
| 60 | #define W1_READ_PSUPPLY 0xB4 | 57 | #define W1_READ_PSUPPLY 0xB4 |
| 61 | #define W1_MATCH_ROM 0x55 | 58 | #define W1_MATCH_ROM 0x55 |
| 62 | 59 | ||
| 63 | #define W1_SLAVE_ACTIVE (1<<0) | 60 | #define W1_SLAVE_ACTIVE 0 |
| 64 | 61 | ||
| 65 | struct w1_slave | 62 | struct w1_slave |
| 66 | { | 63 | { |
| @@ -145,8 +142,8 @@ struct w1_bus_master | |||
| 145 | */ | 142 | */ |
| 146 | u8 (*reset_bus)(void *); | 143 | u8 (*reset_bus)(void *); |
| 147 | 144 | ||
| 148 | /** Really nice hardware can handles the ROM searches */ | 145 | /** Really nice hardware can handles the different types of ROM search */ |
| 149 | void (*search)(void *, w1_slave_found_callback); | 146 | void (*search)(void *, u8, w1_slave_found_callback); |
| 150 | }; | 147 | }; |
| 151 | 148 | ||
| 152 | #define W1_MASTER_NEED_EXIT 0 | 149 | #define W1_MASTER_NEED_EXIT 0 |
| @@ -173,19 +170,30 @@ struct w1_master | |||
| 173 | long flags; | 170 | long flags; |
| 174 | 171 | ||
| 175 | struct task_struct *thread; | 172 | struct task_struct *thread; |
| 176 | struct semaphore mutex; | 173 | struct mutex mutex; |
| 177 | 174 | ||
| 178 | struct device_driver *driver; | 175 | struct device_driver *driver; |
| 179 | struct device dev; | 176 | struct device dev; |
| 180 | 177 | ||
| 181 | struct w1_bus_master *bus_master; | 178 | struct w1_bus_master *bus_master; |
| 182 | 179 | ||
| 183 | u32 seq, groups; | 180 | u32 seq; |
| 184 | struct sock *nls; | ||
| 185 | }; | 181 | }; |
| 186 | 182 | ||
| 187 | int w1_create_master_attributes(struct w1_master *); | 183 | int w1_create_master_attributes(struct w1_master *); |
| 188 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); | 184 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); |
| 185 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); | ||
| 186 | struct w1_slave *w1_search_slave(struct w1_reg_num *id); | ||
| 187 | void w1_search_process(struct w1_master *dev, u8 search_type); | ||
| 188 | struct w1_master *w1_search_master_id(u32 id); | ||
| 189 | |||
| 190 | u8 w1_triplet(struct w1_master *dev, int bdir); | ||
| 191 | void w1_write_8(struct w1_master *, u8); | ||
| 192 | int w1_reset_bus(struct w1_master *); | ||
| 193 | u8 w1_calc_crc8(u8 *, int); | ||
| 194 | void w1_write_block(struct w1_master *, const u8 *, int); | ||
| 195 | u8 w1_read_block(struct w1_master *, u8 *, int); | ||
| 196 | int w1_reset_select_slave(struct w1_slave *sl); | ||
| 189 | 197 | ||
| 190 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) | 198 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) |
| 191 | { | 199 | { |
| @@ -202,15 +210,14 @@ static inline struct w1_master* dev_to_w1_master(struct device *dev) | |||
| 202 | return container_of(dev, struct w1_master, dev); | 210 | return container_of(dev, struct w1_master, dev); |
| 203 | } | 211 | } |
| 204 | 212 | ||
| 213 | extern struct device_driver w1_master_driver; | ||
| 214 | extern struct device w1_master_device; | ||
| 205 | extern int w1_max_slave_count; | 215 | extern int w1_max_slave_count; |
| 206 | extern int w1_max_slave_ttl; | 216 | extern int w1_max_slave_ttl; |
| 207 | extern spinlock_t w1_mlock; | ||
| 208 | extern struct list_head w1_masters; | 217 | extern struct list_head w1_masters; |
| 209 | extern struct device_driver w1_master_driver; | 218 | extern struct mutex w1_mlock; |
| 210 | extern struct device w1_master_device; | ||
| 211 | 219 | ||
| 212 | int w1_process(void *data); | 220 | extern int w1_process(void *); |
| 213 | void w1_reconnect_slaves(struct w1_family *f); | ||
| 214 | 221 | ||
| 215 | #endif /* __KERNEL__ */ | 222 | #endif /* __KERNEL__ */ |
| 216 | 223 | ||
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 0e32c114f906..a3c95bd6890a 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c | |||
| @@ -107,6 +107,12 @@ struct w1_family * w1_family_registered(u8 fid) | |||
| 107 | return (ret) ? f : NULL; | 107 | return (ret) ? f : NULL; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static void __w1_family_put(struct w1_family *f) | ||
| 111 | { | ||
| 112 | if (atomic_dec_and_test(&f->refcnt)) | ||
| 113 | f->need_exit = 1; | ||
| 114 | } | ||
| 115 | |||
| 110 | void w1_family_put(struct w1_family *f) | 116 | void w1_family_put(struct w1_family *f) |
| 111 | { | 117 | { |
| 112 | spin_lock(&w1_flock); | 118 | spin_lock(&w1_flock); |
| @@ -114,19 +120,14 @@ void w1_family_put(struct w1_family *f) | |||
| 114 | spin_unlock(&w1_flock); | 120 | spin_unlock(&w1_flock); |
| 115 | } | 121 | } |
| 116 | 122 | ||
| 117 | void __w1_family_put(struct w1_family *f) | 123 | #if 0 |
| 118 | { | ||
| 119 | if (atomic_dec_and_test(&f->refcnt)) | ||
| 120 | f->need_exit = 1; | ||
| 121 | } | ||
| 122 | |||
| 123 | void w1_family_get(struct w1_family *f) | 124 | void w1_family_get(struct w1_family *f) |
| 124 | { | 125 | { |
| 125 | spin_lock(&w1_flock); | 126 | spin_lock(&w1_flock); |
| 126 | __w1_family_get(f); | 127 | __w1_family_get(f); |
| 127 | spin_unlock(&w1_flock); | 128 | spin_unlock(&w1_flock); |
| 128 | |||
| 129 | } | 129 | } |
| 130 | #endif /* 0 */ | ||
| 130 | 131 | ||
| 131 | void __w1_family_get(struct w1_family *f) | 132 | void __w1_family_get(struct w1_family *f) |
| 132 | { | 133 | { |
| @@ -135,8 +136,5 @@ void __w1_family_get(struct w1_family *f) | |||
| 135 | smp_mb__after_atomic_inc(); | 136 | smp_mb__after_atomic_inc(); |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | EXPORT_SYMBOL(w1_family_get); | ||
| 139 | EXPORT_SYMBOL(w1_family_put); | ||
| 140 | EXPORT_SYMBOL(w1_family_registered); | ||
| 141 | EXPORT_SYMBOL(w1_unregister_family); | 139 | EXPORT_SYMBOL(w1_unregister_family); |
| 142 | EXPORT_SYMBOL(w1_register_family); | 140 | EXPORT_SYMBOL(w1_register_family); |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 2ca0489c716a..1e2ac40c2c14 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
| @@ -57,12 +57,11 @@ struct w1_family | |||
| 57 | 57 | ||
| 58 | extern spinlock_t w1_flock; | 58 | extern spinlock_t w1_flock; |
| 59 | 59 | ||
| 60 | void w1_family_get(struct w1_family *); | ||
| 61 | void w1_family_put(struct w1_family *); | 60 | void w1_family_put(struct w1_family *); |
| 62 | void __w1_family_get(struct w1_family *); | 61 | void __w1_family_get(struct w1_family *); |
| 63 | void __w1_family_put(struct w1_family *); | ||
| 64 | struct w1_family * w1_family_registered(u8); | 62 | struct w1_family * w1_family_registered(u8); |
| 65 | void w1_unregister_family(struct w1_family *); | 63 | void w1_unregister_family(struct w1_family *); |
| 66 | int w1_register_family(struct w1_family *); | 64 | int w1_register_family(struct w1_family *); |
| 65 | void w1_reconnect_slaves(struct w1_family *f); | ||
| 67 | 66 | ||
| 68 | #endif /* __W1_FAMILY_H */ | 67 | #endif /* __W1_FAMILY_H */ |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 68565aacec7b..357a2e0f637a 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
| @@ -65,7 +65,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
| 65 | atomic_set(&dev->refcnt, 2); | 65 | atomic_set(&dev->refcnt, 2); |
| 66 | 66 | ||
| 67 | INIT_LIST_HEAD(&dev->slist); | 67 | INIT_LIST_HEAD(&dev->slist); |
| 68 | init_MUTEX(&dev->mutex); | 68 | mutex_init(&dev->mutex); |
| 69 | 69 | ||
| 70 | memcpy(&dev->dev, device, sizeof(struct device)); | 70 | memcpy(&dev->dev, device, sizeof(struct device)); |
| 71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
| @@ -74,16 +74,11 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
| 74 | 74 | ||
| 75 | dev->driver = driver; | 75 | dev->driver = driver; |
| 76 | 76 | ||
| 77 | dev->groups = 1; | ||
| 78 | dev->seq = 1; | 77 | dev->seq = 1; |
| 79 | dev_init_netlink(dev); | ||
| 80 | 78 | ||
| 81 | err = device_register(&dev->dev); | 79 | err = device_register(&dev->dev); |
| 82 | if (err) { | 80 | if (err) { |
| 83 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); | 81 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); |
| 84 | |||
| 85 | dev_fini_netlink(dev); | ||
| 86 | |||
| 87 | memset(dev, 0, sizeof(struct w1_master)); | 82 | memset(dev, 0, sizeof(struct w1_master)); |
| 88 | kfree(dev); | 83 | kfree(dev); |
| 89 | dev = NULL; | 84 | dev = NULL; |
| @@ -131,12 +126,12 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
| 131 | 126 | ||
| 132 | dev->initialized = 1; | 127 | dev->initialized = 1; |
| 133 | 128 | ||
| 134 | spin_lock(&w1_mlock); | 129 | mutex_lock(&w1_mlock); |
| 135 | list_add(&dev->w1_master_entry, &w1_masters); | 130 | list_add(&dev->w1_master_entry, &w1_masters); |
| 136 | spin_unlock(&w1_mlock); | 131 | mutex_unlock(&w1_mlock); |
| 137 | 132 | ||
| 133 | memset(&msg, 0, sizeof(msg)); | ||
| 138 | msg.id.mst.id = dev->id; | 134 | msg.id.mst.id = dev->id; |
| 139 | msg.id.mst.pid = dev->thread->pid; | ||
| 140 | msg.type = W1_MASTER_ADD; | 135 | msg.type = W1_MASTER_ADD; |
| 141 | w1_netlink_send(dev, &msg); | 136 | w1_netlink_send(dev, &msg); |
| 142 | 137 | ||
| @@ -153,7 +148,6 @@ err_out_free_dev: | |||
| 153 | void __w1_remove_master_device(struct w1_master *dev) | 148 | void __w1_remove_master_device(struct w1_master *dev) |
| 154 | { | 149 | { |
| 155 | struct w1_netlink_msg msg; | 150 | struct w1_netlink_msg msg; |
| 156 | pid_t pid = dev->thread->pid; | ||
| 157 | 151 | ||
| 158 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 152 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
| 159 | kthread_stop(dev->thread); | 153 | kthread_stop(dev->thread); |
| @@ -166,8 +160,8 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
| 166 | flush_signals(current); | 160 | flush_signals(current); |
| 167 | } | 161 | } |
| 168 | 162 | ||
| 163 | memset(&msg, 0, sizeof(msg)); | ||
| 169 | msg.id.mst.id = dev->id; | 164 | msg.id.mst.id = dev->id; |
| 170 | msg.id.mst.pid = pid; | ||
| 171 | msg.type = W1_MASTER_REMOVE; | 165 | msg.type = W1_MASTER_REMOVE; |
| 172 | w1_netlink_send(dev, &msg); | 166 | w1_netlink_send(dev, &msg); |
| 173 | 167 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index f7f7e8bec30e..30b6fbf83bd4 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
| @@ -23,10 +23,10 @@ | |||
| 23 | 23 | ||
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
| 26 | #include <linux/module.h> | ||
| 26 | 27 | ||
| 27 | #include "w1.h" | 28 | #include "w1.h" |
| 28 | #include "w1_log.h" | 29 | #include "w1_log.h" |
| 29 | #include "w1_io.h" | ||
| 30 | 30 | ||
| 31 | static int w1_delay_parm = 1; | 31 | static int w1_delay_parm = 1; |
| 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
| @@ -50,7 +50,7 @@ static u8 w1_crc8_table[] = { | |||
| 50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 | 50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | void w1_delay(unsigned long tm) | 53 | static void w1_delay(unsigned long tm) |
| 54 | { | 54 | { |
| 55 | udelay(tm * w1_delay_parm); | 55 | udelay(tm * w1_delay_parm); |
| 56 | } | 56 | } |
| @@ -61,7 +61,7 @@ static u8 w1_read_bit(struct w1_master *dev); | |||
| 61 | /** | 61 | /** |
| 62 | * Generates a write-0 or write-1 cycle and samples the level. | 62 | * Generates a write-0 or write-1 cycle and samples the level. |
| 63 | */ | 63 | */ |
| 64 | u8 w1_touch_bit(struct w1_master *dev, int bit) | 64 | static u8 w1_touch_bit(struct w1_master *dev, int bit) |
| 65 | { | 65 | { |
| 66 | if (dev->bus_master->touch_bit) | 66 | if (dev->bus_master->touch_bit) |
| 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); | 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); |
| @@ -108,6 +108,7 @@ void w1_write_8(struct w1_master *dev, u8 byte) | |||
| 108 | for (i = 0; i < 8; ++i) | 108 | for (i = 0; i < 8; ++i) |
| 109 | w1_touch_bit(dev, (byte >> i) & 0x1); | 109 | w1_touch_bit(dev, (byte >> i) & 0x1); |
| 110 | } | 110 | } |
| 111 | EXPORT_SYMBOL_GPL(w1_write_8); | ||
| 111 | 112 | ||
| 112 | 113 | ||
| 113 | /** | 114 | /** |
| @@ -176,7 +177,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir) | |||
| 176 | * @param dev the master device | 177 | * @param dev the master device |
| 177 | * @return the byte read | 178 | * @return the byte read |
| 178 | */ | 179 | */ |
| 179 | u8 w1_read_8(struct w1_master * dev) | 180 | static u8 w1_read_8(struct w1_master * dev) |
| 180 | { | 181 | { |
| 181 | int i; | 182 | int i; |
| 182 | u8 res = 0; | 183 | u8 res = 0; |
| @@ -208,6 +209,7 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | |||
| 208 | for (i = 0; i < len; ++i) | 209 | for (i = 0; i < len; ++i) |
| 209 | w1_write_8(dev, buf[i]); | 210 | w1_write_8(dev, buf[i]); |
| 210 | } | 211 | } |
| 212 | EXPORT_SYMBOL_GPL(w1_write_block); | ||
| 211 | 213 | ||
| 212 | /** | 214 | /** |
| 213 | * Reads a series of bytes. | 215 | * Reads a series of bytes. |
| @@ -232,6 +234,7 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) | |||
| 232 | 234 | ||
| 233 | return ret; | 235 | return ret; |
| 234 | } | 236 | } |
| 237 | EXPORT_SYMBOL_GPL(w1_read_block); | ||
| 235 | 238 | ||
| 236 | /** | 239 | /** |
| 237 | * Issues a reset bus sequence. | 240 | * Issues a reset bus sequence. |
| @@ -257,6 +260,7 @@ int w1_reset_bus(struct w1_master *dev) | |||
| 257 | 260 | ||
| 258 | return result; | 261 | return result; |
| 259 | } | 262 | } |
| 263 | EXPORT_SYMBOL_GPL(w1_reset_bus); | ||
| 260 | 264 | ||
| 261 | u8 w1_calc_crc8(u8 * data, int len) | 265 | u8 w1_calc_crc8(u8 * data, int len) |
| 262 | { | 266 | { |
| @@ -267,14 +271,15 @@ u8 w1_calc_crc8(u8 * data, int len) | |||
| 267 | 271 | ||
| 268 | return crc; | 272 | return crc; |
| 269 | } | 273 | } |
| 274 | EXPORT_SYMBOL_GPL(w1_calc_crc8); | ||
| 270 | 275 | ||
| 271 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | 276 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
| 272 | { | 277 | { |
| 273 | dev->attempts++; | 278 | dev->attempts++; |
| 274 | if (dev->bus_master->search) | 279 | if (dev->bus_master->search) |
| 275 | dev->bus_master->search(dev->bus_master->data, cb); | 280 | dev->bus_master->search(dev->bus_master->data, search_type, cb); |
| 276 | else | 281 | else |
| 277 | w1_search(dev, cb); | 282 | w1_search(dev, search_type, cb); |
| 278 | } | 283 | } |
| 279 | 284 | ||
| 280 | /** | 285 | /** |
| @@ -299,14 +304,4 @@ int w1_reset_select_slave(struct w1_slave *sl) | |||
| 299 | } | 304 | } |
| 300 | return 0; | 305 | return 0; |
| 301 | } | 306 | } |
| 302 | 307 | EXPORT_SYMBOL_GPL(w1_reset_select_slave); | |
| 303 | EXPORT_SYMBOL(w1_touch_bit); | ||
| 304 | EXPORT_SYMBOL(w1_write_8); | ||
| 305 | EXPORT_SYMBOL(w1_read_8); | ||
| 306 | EXPORT_SYMBOL(w1_reset_bus); | ||
| 307 | EXPORT_SYMBOL(w1_calc_crc8); | ||
| 308 | EXPORT_SYMBOL(w1_delay); | ||
| 309 | EXPORT_SYMBOL(w1_read_block); | ||
| 310 | EXPORT_SYMBOL(w1_write_block); | ||
| 311 | EXPORT_SYMBOL(w1_search_devices); | ||
| 312 | EXPORT_SYMBOL(w1_reset_select_slave); | ||
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 232860184a29..9a76d2ad69c5 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h | |||
| @@ -24,11 +24,8 @@ | |||
| 24 | 24 | ||
| 25 | #include "w1.h" | 25 | #include "w1.h" |
| 26 | 26 | ||
| 27 | void w1_delay(unsigned long); | ||
| 28 | u8 w1_touch_bit(struct w1_master *, int); | ||
| 29 | u8 w1_triplet(struct w1_master *dev, int bdir); | 27 | u8 w1_triplet(struct w1_master *dev, int bdir); |
| 30 | void w1_write_8(struct w1_master *, u8); | 28 | void w1_write_8(struct w1_master *, u8); |
| 31 | u8 w1_read_8(struct w1_master *); | ||
| 32 | int w1_reset_bus(struct w1_master *); | 29 | int w1_reset_bus(struct w1_master *); |
| 33 | u8 w1_calc_crc8(u8 *, int); | 30 | u8 w1_calc_crc8(u8 *, int); |
| 34 | void w1_write_block(struct w1_master *, const u8 *, int); | 31 | void w1_write_block(struct w1_master *, const u8 *, int); |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 328645da7972..65c5ebd0787e 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
| @@ -21,72 +21,225 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
| 23 | #include <linux/netlink.h> | 23 | #include <linux/netlink.h> |
| 24 | #include <linux/connector.h> | ||
| 24 | 25 | ||
| 25 | #include "w1.h" | 26 | #include "w1.h" |
| 26 | #include "w1_log.h" | 27 | #include "w1_log.h" |
| 27 | #include "w1_netlink.h" | 28 | #include "w1_netlink.h" |
| 28 | 29 | ||
| 29 | #ifndef NETLINK_DISABLED | 30 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) |
| 30 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 31 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
| 31 | { | 32 | { |
| 32 | unsigned int size; | 33 | char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; |
| 33 | struct sk_buff *skb; | 34 | struct cn_msg *m = (struct cn_msg *)buf; |
| 34 | struct w1_netlink_msg *data; | 35 | struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); |
| 35 | struct nlmsghdr *nlh; | ||
| 36 | 36 | ||
| 37 | if (!dev->nls) | 37 | memset(buf, 0, sizeof(buf)); |
| 38 | return; | ||
| 39 | 38 | ||
| 40 | size = NLMSG_SPACE(sizeof(struct w1_netlink_msg)); | 39 | m->id.idx = CN_W1_IDX; |
| 40 | m->id.val = CN_W1_VAL; | ||
| 41 | 41 | ||
| 42 | skb = alloc_skb(size, GFP_ATOMIC); | 42 | m->seq = dev->seq++; |
| 43 | if (!skb) { | 43 | m->len = sizeof(struct w1_netlink_msg); |
| 44 | dev_err(&dev->dev, "skb_alloc() failed.\n"); | 44 | |
| 45 | return; | 45 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); |
| 46 | } | 46 | |
| 47 | cn_netlink_send(m, 0, GFP_KERNEL); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, | ||
| 51 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 52 | { | ||
| 53 | dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", | ||
| 54 | __func__, dev->name, cmd->cmd, cmd->len); | ||
| 55 | |||
| 56 | if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) | ||
| 57 | return -EINVAL; | ||
| 58 | |||
| 59 | w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | ||
| 64 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 65 | { | ||
| 66 | void *data; | ||
| 67 | struct w1_netlink_msg *h; | ||
| 68 | struct w1_netlink_cmd *c; | ||
| 69 | struct cn_msg *cm; | ||
| 70 | int err; | ||
| 71 | |||
| 72 | data = kzalloc(sizeof(struct cn_msg) + | ||
| 73 | sizeof(struct w1_netlink_msg) + | ||
| 74 | sizeof(struct w1_netlink_cmd) + | ||
| 75 | cmd->len, GFP_KERNEL); | ||
| 76 | if (!data) | ||
| 77 | return -ENOMEM; | ||
| 78 | |||
| 79 | cm = (struct cn_msg *)(data); | ||
| 80 | h = (struct w1_netlink_msg *)(cm + 1); | ||
| 81 | c = (struct w1_netlink_cmd *)(h + 1); | ||
| 82 | |||
| 83 | memcpy(cm, msg, sizeof(struct cn_msg)); | ||
| 84 | memcpy(h, hdr, sizeof(struct w1_netlink_msg)); | ||
| 85 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | ||
| 47 | 86 | ||
| 48 | nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh)); | 87 | cm->ack = msg->seq+1; |
| 88 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
| 49 | 89 | ||
| 50 | data = (struct w1_netlink_msg *)NLMSG_DATA(nlh); | 90 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; |
| 51 | 91 | ||
| 52 | memcpy(data, msg, sizeof(struct w1_netlink_msg)); | 92 | memcpy(c->data, cmd->data, c->len); |
| 53 | 93 | ||
| 54 | NETLINK_CB(skb).dst_group = dev->groups; | 94 | err = cn_netlink_send(cm, 0, GFP_KERNEL); |
| 55 | netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC); | ||
| 56 | 95 | ||
| 57 | nlmsg_failure: | 96 | kfree(data); |
| 58 | return; | 97 | |
| 98 | return err; | ||
| 59 | } | 99 | } |
| 60 | 100 | ||
| 61 | int dev_init_netlink(struct w1_master *dev) | 101 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, |
| 102 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 62 | { | 103 | { |
| 63 | dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE); | 104 | int err = 0; |
| 64 | if (!dev->nls) { | 105 | |
| 65 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", | 106 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", |
| 66 | NETLINK_W1, dev->dev.bus_id); | 107 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, |
| 108 | cmd->cmd, cmd->len); | ||
| 109 | |||
| 110 | switch (cmd->cmd) { | ||
| 111 | case W1_CMD_READ: | ||
| 112 | w1_read_block(sl->master, cmd->data, cmd->len); | ||
| 113 | w1_send_read_reply(sl, msg, hdr, cmd); | ||
| 114 | break; | ||
| 115 | case W1_CMD_WRITE: | ||
| 116 | w1_write_block(sl->master, cmd->data, cmd->len); | ||
| 117 | break; | ||
| 118 | case W1_CMD_SEARCH: | ||
| 119 | case W1_CMD_ALARM_SEARCH: | ||
| 120 | w1_search_process(sl->master, | ||
| 121 | (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | err = -1; | ||
| 125 | break; | ||
| 67 | } | 126 | } |
| 68 | 127 | ||
| 69 | return 0; | 128 | return err; |
| 70 | } | 129 | } |
| 71 | 130 | ||
| 72 | void dev_fini_netlink(struct w1_master *dev) | 131 | static void w1_cn_callback(void *data) |
| 73 | { | 132 | { |
| 74 | if (dev->nls && dev->nls->sk_socket) | 133 | struct cn_msg *msg = data; |
| 75 | sock_release(dev->nls->sk_socket); | 134 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); |
| 135 | struct w1_netlink_cmd *cmd; | ||
| 136 | struct w1_slave *sl; | ||
| 137 | struct w1_master *dev; | ||
| 138 | int err = 0; | ||
| 139 | |||
| 140 | while (msg->len && !err) { | ||
| 141 | struct w1_reg_num id; | ||
| 142 | u16 mlen = m->len; | ||
| 143 | u8 *cmd_data = m->data; | ||
| 144 | |||
| 145 | dev = NULL; | ||
| 146 | sl = NULL; | ||
| 147 | |||
| 148 | memcpy(&id, m->id.id, sizeof(id)); | ||
| 149 | #if 0 | ||
| 150 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", | ||
| 151 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); | ||
| 152 | #endif | ||
| 153 | if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { | ||
| 154 | err = -E2BIG; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (!mlen) | ||
| 159 | goto out_cont; | ||
| 160 | |||
| 161 | if (m->type == W1_MASTER_CMD) { | ||
| 162 | dev = w1_search_master_id(m->id.mst.id); | ||
| 163 | } else if (m->type == W1_SLAVE_CMD) { | ||
| 164 | sl = w1_search_slave(&id); | ||
| 165 | if (sl) | ||
| 166 | dev = sl->master; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (!dev) { | ||
| 170 | err = -ENODEV; | ||
| 171 | goto out_cont; | ||
| 172 | } | ||
| 173 | |||
| 174 | mutex_lock(&dev->mutex); | ||
| 175 | |||
| 176 | if (sl && w1_reset_select_slave(sl)) { | ||
| 177 | err = -ENODEV; | ||
| 178 | goto out_up; | ||
| 179 | } | ||
| 180 | |||
| 181 | while (mlen) { | ||
| 182 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
| 183 | |||
| 184 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
| 185 | err = -E2BIG; | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | |||
| 189 | if (sl) | ||
| 190 | w1_process_command_slave(sl, msg, m, cmd); | ||
| 191 | else | ||
| 192 | w1_process_command_master(dev, msg, m, cmd); | ||
| 193 | |||
| 194 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
| 195 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
| 196 | } | ||
| 197 | out_up: | ||
| 198 | atomic_dec(&dev->refcnt); | ||
| 199 | if (sl) | ||
| 200 | atomic_dec(&sl->refcnt); | ||
| 201 | mutex_unlock(&dev->mutex); | ||
| 202 | out_cont: | ||
| 203 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | ||
| 204 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Let's allow requests for nonexisting devices. | ||
| 208 | */ | ||
| 209 | if (err == -ENODEV) | ||
| 210 | err = 0; | ||
| 211 | } | ||
| 212 | #if 0 | ||
| 213 | if (err) { | ||
| 214 | printk("%s: malformed message. Dropping.\n", __func__); | ||
| 215 | } | ||
| 216 | #endif | ||
| 76 | } | 217 | } |
| 77 | #else | ||
| 78 | #warning Netlink support is disabled. Please compile with NET support enabled. | ||
| 79 | 218 | ||
| 219 | int w1_init_netlink(void) | ||
| 220 | { | ||
| 221 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
| 222 | |||
| 223 | return cn_add_callback(&w1_id, "w1", &w1_cn_callback); | ||
| 224 | } | ||
| 225 | |||
| 226 | void w1_fini_netlink(void) | ||
| 227 | { | ||
| 228 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
| 229 | |||
| 230 | cn_del_callback(&w1_id); | ||
| 231 | } | ||
| 232 | #else | ||
| 80 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 233 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
| 81 | { | 234 | { |
| 82 | } | 235 | } |
| 83 | 236 | ||
| 84 | int dev_init_netlink(struct w1_master *dev) | 237 | int w1_init_netlink(void) |
| 85 | { | 238 | { |
| 86 | return 0; | 239 | return 0; |
| 87 | } | 240 | } |
| 88 | 241 | ||
| 89 | void dev_fini_netlink(struct w1_master *dev) | 242 | void w1_fini_netlink(void) |
| 90 | { | 243 | { |
| 91 | } | 244 | } |
| 92 | #endif | 245 | #endif |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index eb0c8b3152c8..56122b9e9294 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #define __W1_NETLINK_H | 23 | #define __W1_NETLINK_H |
| 24 | 24 | ||
| 25 | #include <asm/types.h> | 25 | #include <asm/types.h> |
| 26 | #include <linux/connector.h> | ||
| 26 | 27 | ||
| 27 | #include "w1.h" | 28 | #include "w1.h" |
| 28 | 29 | ||
| @@ -31,29 +32,43 @@ enum w1_netlink_message_types { | |||
| 31 | W1_SLAVE_REMOVE, | 32 | W1_SLAVE_REMOVE, |
| 32 | W1_MASTER_ADD, | 33 | W1_MASTER_ADD, |
| 33 | W1_MASTER_REMOVE, | 34 | W1_MASTER_REMOVE, |
| 35 | W1_MASTER_CMD, | ||
| 36 | W1_SLAVE_CMD, | ||
| 34 | }; | 37 | }; |
| 35 | 38 | ||
| 36 | struct w1_netlink_msg | 39 | struct w1_netlink_msg |
| 37 | { | 40 | { |
| 38 | __u8 type; | 41 | __u8 type; |
| 39 | __u8 reserved[3]; | 42 | __u8 reserved; |
| 40 | union | 43 | __u16 len; |
| 41 | { | 44 | union { |
| 42 | struct w1_reg_num id; | 45 | __u8 id[8]; |
| 43 | __u64 w1_id; | 46 | struct w1_mst { |
| 44 | struct | ||
| 45 | { | ||
| 46 | __u32 id; | 47 | __u32 id; |
| 47 | __u32 pid; | 48 | __u32 res; |
| 48 | } mst; | 49 | } mst; |
| 49 | } id; | 50 | } id; |
| 51 | __u8 data[0]; | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define W1_CMD_READ 0x0 | ||
| 55 | #define W1_CMD_WRITE 0x1 | ||
| 56 | #define W1_CMD_SEARCH 0x2 | ||
| 57 | #define W1_CMD_ALARM_SEARCH 0x3 | ||
| 58 | |||
| 59 | struct w1_netlink_cmd | ||
| 60 | { | ||
| 61 | __u8 cmd; | ||
| 62 | __u8 res; | ||
| 63 | __u16 len; | ||
| 64 | __u8 data[0]; | ||
| 50 | }; | 65 | }; |
| 51 | 66 | ||
| 52 | #ifdef __KERNEL__ | 67 | #ifdef __KERNEL__ |
| 53 | 68 | ||
| 54 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); | 69 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); |
| 55 | int dev_init_netlink(struct w1_master *dev); | 70 | int w1_init_netlink(void); |
| 56 | void dev_fini_netlink(struct w1_master *dev); | 71 | void w1_fini_netlink(void); |
| 57 | 72 | ||
| 58 | #endif /* __KERNEL__ */ | 73 | #endif /* __KERNEL__ */ |
| 59 | #endif /* __W1_NETLINK_H */ | 74 | #endif /* __W1_NETLINK_H */ |
