From d250a4810402ec68f64802b66340a0e70c61cbd3 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Mon, 6 Mar 2006 17:37:04 +0100 Subject: [PATCH 01/15] [PATCH] yenta: do power-up only after socket is configured Power-up the card only after the socket is configured. power-down in the old place. The point is not to power-up the card before the interrupt routing is set up correctly. Signed-off-by: Daniel Ritz Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 4145eb83b9b6..006749dc8d75 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -287,7 +287,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); u16 bridge; - yenta_set_power(socket, state); + /* if powering down: do it immediately */ + if (state->Vcc == 0) + yenta_set_power(socket, state); + socket->io_irq = state->io_irq; bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { @@ -339,6 +342,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) /* Socket event mask: get card insert/remove events.. */ cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); + + /* if powering up: do it as the last step when the socket is configured */ + if (state->Vcc != 0) + yenta_set_power(socket, state); return 0; } From b435261b1e09bb2bb6acc4abbc7f6e3d885f9e62 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Tue, 30 May 2006 18:00:34 +0200 Subject: [PATCH 02/15] [PATCH] yenta: fix hidden PCI bus numbers Fixup the subordinate number parent bridge of yenta Cardbus Bridges before the PCI bus scan starts to make the cardbus cards which are otherwise hidden for PCI scans work. Signed-off-by: Bernhard Kaindl Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 006749dc8d75..d9d005ec920c 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1005,6 +1005,77 @@ static void yenta_config_init(struct yenta_socket *socket) config_writew(socket, CB_BRIDGE_CONTROL, bridge); } +/** + * yenta_fixup_parent_subordinate - Fix subordinate bus# of the parent bridge + * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to + * + * Checks if devices on the bus which the CardBus bridge bridges to would be + * invisible during PCI scans because of a misconfigured subordinate number + * of the parent brige - some BIOSes seem to be too lazy to set it right. + * Does the fixup carefully by checking how far it can go without conflicts. + * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information. + */ +static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge) +{ + struct list_head *tmp; + unsigned char upper_limit; + /* + * We only check and fix the parent bridge: All systems which need + * this fixup that have been reviewed are laptops and the only bridge + * which needed fixing was the parent bridge of the CardBus bridge: + */ + struct pci_bus *bridge_to_fix = cardbus_bridge->parent; + + /* Check bus numbers are already set up correctly: */ + if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate) + return; /* The subordinate number is ok, nothing to do */ + + if (!bridge_to_fix->parent) + return; /* Root bridges are ok */ + + /* stay within the limits of the bus range of the parent: */ + upper_limit = bridge_to_fix->parent->subordinate; + + /* check the bus ranges of all silbling bridges to prevent overlap */ + list_for_each(tmp, &bridge_to_fix->parent->children) { + struct pci_bus * silbling = pci_bus_b(tmp); + /* + * If the silbling has a higher secondary bus number + * and it's secondary is equal or smaller than our + * current upper limit, set the new upper limit to + * the bus number below the silbling's range: + */ + if (silbling->secondary > bridge_to_fix->subordinate + && silbling->secondary <= upper_limit) + upper_limit = silbling->secondary - 1; + } + + /* Show that the wanted subordinate number is not possible: */ + if (cardbus_bridge->subordinate > upper_limit) + printk(KERN_WARNING "Yenta: Upper limit for fixing this " + "bridge's parent bridge: #%02x\n", upper_limit); + + /* If we have room to increase the bridge's subordinate number, */ + if (bridge_to_fix->subordinate < upper_limit) { + + /* use the highest number of the hidden bus, within limits */ + unsigned char subordinate_to_assign = + min(cardbus_bridge->subordinate, upper_limit); + + printk(KERN_INFO "Yenta: Raising subordinate bus# of parent " + "bus (#%02x) from #%02x to #%02x\n", + bridge_to_fix->number, + bridge_to_fix->subordinate, subordinate_to_assign); + + /* Save the new subordinate in the bus struct of the bridge */ + bridge_to_fix->subordinate = subordinate_to_assign; + + /* and update the PCI config space with the new subordinate */ + pci_write_config_byte(bridge_to_fix->self, + PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate); + } +} + /* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the @@ -1120,6 +1191,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i yenta_get_socket_capabilities(socket, isa_interrupts); printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); + yenta_fixup_parent_bridge(dev->subordinate); + /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); if (ret == 0) { From fec21889cd6ef5e604b410c08b50a8c1522d74d4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 26 Apr 2006 19:57:32 +0200 Subject: [PATCH 03/15] [PATCH] pcmcia: another ID for serial_cs.c Add an ID for "GlobeTrotter" cards which need a CIS override Signed-off-by: Dominik Brodowski --- drivers/serial/serial_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 2c70773543e0..cbf260bc225d 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -786,6 +786,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"), PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"), + PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"), /* too generic */ /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */ From d29693bf10f376870d9bfd34bde80dd061cc4575 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 21 May 2006 20:57:42 -0700 Subject: [PATCH 04/15] [PATCH] pcmcia: expose tool in pcmcia/Documentation/pcmcia/ Expose example and tool source files in the Documentation/ directory in their own files instead of being buried (almost hidden) in readme/txt files. This will make them more visible/usable to users who may need to use them, to developers who may need to test with them, and to janitors who would update them if they were more visible. Also, if any of these possibly should not be in the kernel tree at all, it will be clearer that they are here and we can discuss if they should be removed. Signed-off-by: Randy Dunlap Signed-off-by: Dominik Brodowski --- Documentation/pcmcia/crc32hash.c | 32 +++++++++++++++++++++++++ Documentation/pcmcia/devicetable.txt | 36 +++------------------------- 2 files changed, 35 insertions(+), 33 deletions(-) create mode 100644 Documentation/pcmcia/crc32hash.c diff --git a/Documentation/pcmcia/crc32hash.c b/Documentation/pcmcia/crc32hash.c new file mode 100644 index 000000000000..cbc36d299af8 --- /dev/null +++ b/Documentation/pcmcia/crc32hash.c @@ -0,0 +1,32 @@ +/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */ +/* Usage example: +$ ./crc32hash "Dual Speed" +*/ + +#include +#include +#include +#include + +unsigned int crc32(unsigned char const *p, unsigned int len) +{ + int i; + unsigned int crc = 0; + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); + } + return crc; +} + +int main(int argc, char **argv) { + unsigned int result; + if (argc != 2) { + printf("no string passed as argument\n"); + return -1; + } + result = crc32(argv[1], strlen(argv[1])); + printf("0x%x\n", result); + return 0; +} diff --git a/Documentation/pcmcia/devicetable.txt b/Documentation/pcmcia/devicetable.txt index 3351c0355143..199afd100cf2 100644 --- a/Documentation/pcmcia/devicetable.txt +++ b/Documentation/pcmcia/devicetable.txt @@ -27,37 +27,7 @@ pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000 The hex value after "pa" is the hash of product ID string 1, after "pb" for string 2 and so on. -Alternatively, you can use this small tool to determine the crc32 hash. -simply pass the string you want to evaluate as argument to this program, -e.g. +Alternatively, you can use crc32hash (see Documentation/pcmcia/crc32hash.c) +to determine the crc32 hash. Simply pass the string you want to evaluate +as argument to this program, e.g.: $ ./crc32hash "Dual Speed" - -------------------------------------------------------------------------- -/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */ -#include -#include -#include -#include - -unsigned int crc32(unsigned char const *p, unsigned int len) -{ - int i; - unsigned int crc = 0; - while (len--) { - crc ^= *p++; - for (i = 0; i < 8; i++) - crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); - } - return crc; -} - -int main(int argc, char **argv) { - unsigned int result; - if (argc != 2) { - printf("no string passed as argument\n"); - return -1; - } - result = crc32(argv[1], strlen(argv[1])); - printf("0x%x\n", result); - return 0; -} From c533120b8da215dc02310c535fa87c5c480d0f14 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 May 2006 16:16:44 +0100 Subject: [PATCH 05/15] [PATCH] pcmcia: warn if driver requests exclusive, but gets a shared IRQ The patch below cleans up the pcmcia code a bit on the IRQ side (I did this while debugging the problem just so I could read wtf it was doing), and also adds a warning and passes back the correct information when a device asks for exclusive but gets given shared. This at least means the dmesg dump of a problem triggered by this will have a signature to find. Signed-off-by: Alan Cox Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 3131bb0a0095..3281e519e714 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -788,6 +788,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) struct pcmcia_socket *s = p_dev->socket; config_t *c; int ret = CS_IN_USE, irq = 0; + int type; if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; @@ -797,6 +798,13 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (c->state & CONFIG_IRQ_REQ) return CS_IN_USE; + /* Decide what type of interrupt we are registering */ + type = 0; + if (s->functions > 1) /* All of this ought to be handled higher up */ + type = SA_SHIRQ; + if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) + type = SA_SHIRQ; + #ifdef CONFIG_PCMCIA_PROBE if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must be the same */ @@ -822,9 +830,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) * marked as used by the kernel resource management core */ ret = request_irq(irq, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, - ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || - (s->functions > 1) || - (irq == s->pci_irq)) ? SA_SHIRQ : 0, + type, p_dev->devname, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); if (!ret) { @@ -839,18 +845,21 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (ret && !s->irq.AssignedIRQ) { if (!s->pci_irq) return ret; + type = SA_SHIRQ; irq = s->pci_irq; } - if (ret && req->Attributes & IRQ_HANDLE_PRESENT) { - if (request_irq(irq, req->Handler, - ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || - (s->functions > 1) || - (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->devname, req->Instance)) + if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) { + if (request_irq(irq, req->Handler, type, p_dev->devname, req->Instance)) return CS_IN_USE; } + /* Make sure the fact the request type was overridden is passed back */ + if (type == SA_SHIRQ && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) { + req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING; + printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n"); + printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n"); + } c->irq.Attributes = req->Attributes; s->irq.AssignedIRQ = req->AssignedIRQ = irq; s->irq.Config++; From 59e35ba1257903eaff5203f62f77554da02f5b63 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 May 2006 23:22:07 -0600 Subject: [PATCH 06/15] [PATCH] pcmcia: TI PCIxx12 CardBus controller support The patch below adds support for the TI PCIxx12 CardBus controllers. This seems to be sufficient to detect the cardbus bridge on an HP nc6320 and works with an orinoco wifi card. Signed-off-by: Alex Williamson Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ti113x.h | 1 + drivers/pcmcia/yenta_socket.c | 1 + include/linux/pci_ids.h | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 7a3d1b8e16b9..62e9ebf967f9 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -647,6 +647,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) */ break; + case PCI_DEVICE_ID_TI_XX12: case PCI_DEVICE_ID_TI_X515: case PCI_DEVICE_ID_TI_X420: case PCI_DEVICE_ID_TI_X620: diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index d9d005ec920c..9fcd6612aeb2 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1312,6 +1312,7 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX), diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9ae6b1a75366..b093479a531d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -729,6 +729,7 @@ #define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 #define PCI_DEVICE_ID_TI_X515 0x8036 +#define PCI_DEVICE_ID_TI_XX12 0x8039 #define PCI_DEVICE_ID_TI_1130 0xac12 #define PCI_DEVICE_ID_TI_1031 0xac13 #define PCI_DEVICE_ID_TI_1131 0xac15 From 5040cb8b7e61b7a03e8837920b9eb2c839bb1947 Mon Sep 17 00:00:00 2001 From: Thomas Kleffel Date: Sun, 14 May 2006 15:16:30 +0200 Subject: [PATCH 07/15] [PATCH] pcmcia: Make ide_cs work with the memory space of CF-Cards if IO space is not available This patch enables ide_cs to access CF-cards via their common memory rather than via their IO space. Signed-off-by: Thomas Kleffel Signed-off-by: Dominik Brodowski --- drivers/ide/legacy/ide-cs.c | 81 ++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 602797a44208..b7e459e4f284 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -146,7 +146,16 @@ static void ide_detach(struct pcmcia_device *link) kfree(link->priv); } /* ide_detach */ -static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle) +static void idecs_mmio_fixup(ide_hwif_t *hwif) +{ + default_hwif_mmiops(hwif); + hwif->mmio = 2; + + ide_undecoded_slave(hwif); +} + +static int idecs_register(unsigned long io, unsigned long ctl, + unsigned long irq, struct pcmcia_device *handle, int is_mmio) { hw_regs_t hw; memset(&hw, 0, sizeof(hw)); @@ -154,7 +163,19 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq hw.irq = irq; hw.chipset = ide_pci; hw.dev = &handle->dev; - return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); + + if(is_mmio) + return ide_register_hw_with_fixup(&hw, NULL, idecs_mmio_fixup); + else + return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); +} + +void outb_io(unsigned char value, unsigned long port) { + outb(value, port); +} + +void outb_mem(unsigned char value, unsigned long port) { + writeb(value, (void __iomem *) port); } /*====================================================================== @@ -180,7 +201,8 @@ static int ide_config(struct pcmcia_device *link) } *stk = NULL; cistpl_cftable_entry_t *cfg; int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0; - unsigned long io_base, ctl_base; + unsigned long io_base, ctl_base, is_mmio, try_slave; + void (*my_outb)(unsigned char, unsigned long); DEBUG(0, "ide_config(0x%p)\n", link); @@ -210,7 +232,7 @@ static int ide_config(struct pcmcia_device *link) /* Not sure if this is right... look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); - pass = io_base = ctl_base = 0; + pass = io_base = ctl_base = is_mmio = try_slave = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); @@ -258,11 +280,45 @@ static int ide_config(struct pcmcia_device *link) goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort1 + 0x0e; + + if (io->win[0].len >= 0x20) + try_slave = 1; + } else goto next_entry; /* If we've got this far, we're done */ break; } + if ((cfg->mem.nwin > 0) || (stk->dflt.mem.nwin > 0)) { + win_req_t req; + memreq_t map; + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &stk->dflt.mem; + + if (mem->win[0].len < 16) + goto next_entry; + + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = 0; + + req.AccessSpeed = 0; + if (pcmcia_request_window(&link, &req, &link->win) != 0) + goto next_entry; + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(link->win, &map) != 0) + goto next_entry; + + io_base = (unsigned long) ioremap(req.Base, req.Size); + ctl_base = io_base + 0x0e; + is_mmio = 1; + + if (mem->win[0].len >= 0x20) + try_slave = 1; + + break; + } + next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); @@ -278,21 +334,26 @@ static int ide_config(struct pcmcia_device *link) CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + if(is_mmio) + my_outb = outb_mem; + else + my_outb = outb_io; + /* disable drive interrupts during IDE probe */ - outb(0x02, ctl_base); + my_outb(0x02, ctl_base); /* special setup for KXLC005 card */ if (is_kme) - outb(0x81, ctl_base+1); + my_outb(0x81, ctl_base+1); /* retry registration in case device is still spinning up */ for (hd = -1, i = 0; i < 10; i++) { - hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); + hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link, is_mmio); if (hd >= 0) break; - if (link->io.NumPorts1 == 0x20) { - outb(0x02, ctl_base + 0x10); + if (try_slave) { + my_outb(0x02, ctl_base + 0x10); hd = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq.AssignedIRQ, link); + link->irq.AssignedIRQ, link, is_mmio); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; From 0db6095d4ff8918350797dfe299d572980e82fa0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 19 Apr 2006 06:37:48 -0700 Subject: [PATCH 08/15] [PATCH] pcmcia: at91_cf suspend/resume/wakeup AT91 CF updates, mostly for power management: - Add suspend/resume methods to the AT91 CF driver, disabling non-wakeup IRQs during system suspend. The card detect IRQ serves as a wakeup event source. - Convert the driver to the more-current "platform_driver" style. So inserting or removing a CF card will wake the system, unless that has been disabled by updating the sysfs file; and there will be no more warnings about spurious IRQs during suspend/resume cycles. Signed-off-by: David Brownell Signed-off-by: Dominik Brodowski --- drivers/pcmcia/at91_cf.c | 75 +++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index a4d50940ebeb..5256342e8532 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = { /*--------------------------------------------------------------------------*/ -static int __init at91_cf_probe(struct device *dev) +static int __init at91_cf_probe(struct platform_device *pdev) { struct at91_cf_socket *cf; - struct at91_cf_data *board = dev->platform_data; - struct platform_device *pdev = to_platform_device(dev); + struct at91_cf_data *board = pdev->dev.platform_data; struct resource *io; unsigned int csa; int status; @@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev) cf->board = board; cf->pdev = pdev; - dev_set_drvdata(dev, cf); + platform_set_drvdata(pdev, cf); /* CF takes over CS4, CS5, CS6 */ csa = at91_sys_read(AT91_EBI_CSA); @@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev) SA_SAMPLE_RANDOM, driver_name, cf); if (status < 0) goto fail0; + device_init_wakeup(&pdev->dev, 1); /* * The card driver will request this irq later as needed. @@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev) board->det_pin, board->irq_pin); cf->socket.owner = THIS_MODULE; - cf->socket.dev.dev = dev; + cf->socket.dev.dev = &pdev->dev; cf->socket.ops = &at91_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP @@ -323,21 +323,25 @@ fail1: free_irq(board->irq_pin, cf); fail0a: free_irq(board->det_pin, cf); + device_init_wakeup(&pdev->dev, 0); fail0: at91_sys_write(AT91_EBI_CSA, csa); kfree(cf); return status; } -static int __exit at91_cf_remove(struct device *dev) +static int __exit at91_cf_remove(struct platform_device *pdev) { - struct at91_cf_socket *cf = dev_get_drvdata(dev); + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; struct resource *io = cf->socket.io[0].res; unsigned int csa; pcmcia_unregister_socket(&cf->socket); - free_irq(cf->board->irq_pin, cf); - free_irq(cf->board->det_pin, cf); + if (board->irq_pin) + free_irq(board->irq_pin, cf); + free_irq(board->det_pin, cf); + device_init_wakeup(&pdev->dev, 0); iounmap((void __iomem *) cf->socket.io_offset); release_mem_region(io->start, io->end + 1 - io->start); @@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev) return 0; } -static struct device_driver at91_cf_driver = { - .name = (char *) driver_name, - .bus = &platform_bus_type, +#ifdef CONFIG_PM + +static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; + + pcmcia_socket_dev_suspend(&pdev->dev, mesg); + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(board->det_pin); + else { + disable_irq_wake(board->det_pin); + disable_irq(board->det_pin); + } + if (board->irq_pin) + disable_irq(board->irq_pin); + return 0; +} + +static int at91_cf_resume(struct platform_device *pdev) +{ + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; + + if (board->irq_pin) + enable_irq(board->irq_pin); + if (!device_may_wakeup(&pdev->dev)) + enable_irq(board->det_pin); + pcmcia_socket_dev_resume(&pdev->dev); + return 0; +} + +#else +#define at91_cf_suspend NULL +#define at91_cf_resume NULL +#endif + +static struct platform_driver at91_cf_driver = { + .driver = { + .name = (char *) driver_name, + .owner = THIS_MODULE, + }, .probe = at91_cf_probe, .remove = __exit_p(at91_cf_remove), - .suspend = pcmcia_socket_dev_suspend, - .resume = pcmcia_socket_dev_resume, + .suspend = at91_cf_suspend, + .resume = at91_cf_resume, }; /*--------------------------------------------------------------------------*/ static int __init at91_cf_init(void) { - return driver_register(&at91_cf_driver); + return platform_driver_register(&at91_cf_driver); } module_init(at91_cf_init); static void __exit at91_cf_exit(void) { - driver_unregister(&at91_cf_driver); + platform_driver_unregister(&at91_cf_driver); } module_exit(at91_cf_exit); From fd99ddd0701385344eadaf2daa6abbc5fb086750 Mon Sep 17 00:00:00 2001 From: Komuro Date: Mon, 17 Apr 2006 21:41:21 +0900 Subject: [PATCH 09/15] [PATCH] pcmcia: hostap_cs.c - 0xc00f,0x0000 conflicts with pcnet_cs Comment out the ID 0xc00f,0x0000 in hostap_cs.c, as it conflicts with the pcnet_cs driver. Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Dominik Brodowski --- drivers/net/wireless/hostap/hostap_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index db03dc2646df..fbb41893ee81 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -844,7 +844,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), +/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), From 66005216074337e3925514456175b202f17e23ef Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 6 Jun 2006 12:06:41 -0700 Subject: [PATCH 10/15] [PATCH] pcmcia: fix kernel-doc function name Fix kernel-doc function name spello. Signed-off-by: Randy Dunlap Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 9fcd6612aeb2..47e57602d5ea 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1006,7 +1006,7 @@ static void yenta_config_init(struct yenta_socket *socket) } /** - * yenta_fixup_parent_subordinate - Fix subordinate bus# of the parent bridge + * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to * * Checks if devices on the bus which the CardBus bridge bridges to would be From 1da9ab7389b8a0789a1b3ad43d3efe80b4c57c03 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Wed, 14 Jun 2006 08:01:26 -0500 Subject: [PATCH 11/15] [PATCH] pcmcia: convert pcmcia_cs to kthread Convert pcmcia_cs to use kthread instead of the deprecated kernel_thread. Signed-off-by: Serge E. Hallyn Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 3162998579c1..06e2cda4e07b 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -176,6 +177,7 @@ static int pccardd(void *__skt); */ int pcmcia_register_socket(struct pcmcia_socket *socket) { + struct task_struct *tsk; int ret; if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) @@ -239,15 +241,18 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) mutex_init(&socket->skt_mutex); spin_lock_init(&socket->thread_lock); - ret = kernel_thread(pccardd, socket, CLONE_KERNEL); - if (ret < 0) + tsk = kthread_run(pccardd, socket, "pccardd"); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); goto err; + } wait_for_completion(&socket->thread_done); - if(!socket->thread) { + if (!socket->thread) { printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket); return -EIO; } + pcmcia_parse_events(socket, SS_DETECT); return 0; @@ -272,10 +277,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); if (socket->thread) { - init_completion(&socket->thread_done); - socket->thread = NULL; wake_up(&socket->thread_wait); - wait_for_completion(&socket->thread_done); + kthread_stop(socket->thread); } release_cis_mem(socket); @@ -630,8 +633,6 @@ static int pccardd(void *__skt) DECLARE_WAITQUEUE(wait, current); int ret; - daemonize("pccardd"); - skt->thread = current; skt->socket = dead_socket; skt->ops->init(skt); @@ -643,7 +644,8 @@ static int pccardd(void *__skt) printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", skt); skt->thread = NULL; - complete_and_exit(&skt->thread_done, 0); + complete(&skt->thread_done); + return 0; } add_wait_queue(&skt->thread_wait, &wait); @@ -674,7 +676,7 @@ static int pccardd(void *__skt) continue; } - if (!skt->thread) + if (kthread_should_stop()) break; schedule(); @@ -688,7 +690,7 @@ static int pccardd(void *__skt) /* remove from the device core */ class_device_unregister(&skt->dev); - complete_and_exit(&skt->thread_done, 0); + return 0; } /* From a2bcce8ede4fbda0c2a5f2132115715dff056b9c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 15 Jun 2006 12:26:55 +0100 Subject: [PATCH 12/15] [PATCH] kill open-coded offsetof in cm4000_cs.c ZERO_DEV() ... to make sure that it doesn't break again when a field changes (see "[PATCH] pcmcia: fix zeroing of cm4000_cs.c data" for recent example). Signed-off-by: Al Viro Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/cm4000_cs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index eab5394da666..31c8a21f9d87 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -149,12 +149,7 @@ struct cm4000_dev { #define ZERO_DEV(dev) \ memset(&dev->atr_csum,0, \ sizeof(struct cm4000_dev) - \ - /*link*/ sizeof(struct pcmcia_device *) - \ - /*node*/ sizeof(dev_node_t) - \ - /*atr*/ MAX_ATR*sizeof(char) - \ - /*rbuf*/ 512*sizeof(char) - \ - /*sbuf*/ 512*sizeof(char) - \ - /*queue*/ 4*sizeof(wait_queue_head_t)) + offsetof(struct cm4000_dev, atr_csum)) static struct pcmcia_device *dev_table[CM4000_MAX_DEV]; static struct class *cmm_class; From 0973ddddca72bc8aee8a273c232060b9608d1793 Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Fri, 23 Jun 2006 12:06:56 +0100 Subject: [PATCH 13/15] [PATCH] au1xxx: pcmcia: fix __init called from non-init This must not be marked __init, as it is called from au1x00_drv_pcmcia_probe. Signed-off-by: Domen Puncer Signed-off-by: Dominik Brodowski --- drivers/pcmcia/au1000_db1x00.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index abc13f28ba3f..fef99f4e30c3 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c @@ -296,7 +296,7 @@ struct pcmcia_low_level db1x00_pcmcia_ops = { .socket_suspend = db1x00_socket_suspend }; -int __init au1x_board_init(struct device *dev) +int au1x_board_init(struct device *dev) { int ret = -ENODEV; bcsr->pcmcia = 0; /* turn off power, if it's not already off */ From 6bb1c39a43d23e4cecc7e815491b6964c6758a29 Mon Sep 17 00:00:00 2001 From: Marc Sowen Date: Sun, 25 Jun 2006 01:56:24 -0700 Subject: [PATCH 14/15] [PATCH] com20020_cs: more device support Enable the com20020_cs arcnet driver to see the SoHard (now Mercury Computer Systems Inc.) SH ARC-PCMCIA card. Signed-off-by: Andrew Morton Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/com20020_cs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 441de824ab6b..48434d7924eb 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -387,7 +387,10 @@ static int com20020_resume(struct pcmcia_device *link) } static struct pcmcia_device_id com20020_ids[] = { - PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), + PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", + "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), + PCMCIA_DEVICE_PROD_ID12("SoHard AG", + "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, com20020_ids); From 4b7a89a3c1cf545b03470416aa821fc2ff826b91 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 30 Jun 2006 10:31:13 +0200 Subject: [PATCH 15/15] [PATCH] pcmcia: fix deadlock in pcmcia_parse_events The PCMCIA layer calls pcmcia_parse_events both from user context and IRQ context; the lock thus needs to be irqsave to avoid deadlocks Signed-off-by: Arjan van de Ven Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 06e2cda4e07b..f9cd831a3f31 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -699,11 +699,12 @@ static int pccardd(void *__skt) */ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) { + unsigned long flags; cs_dbg(s, 4, "parse_events: events %08x\n", events); if (s->thread) { - spin_lock(&s->thread_lock); + spin_lock_irqsave(&s->thread_lock, flags); s->thread_events |= events; - spin_unlock(&s->thread_lock); + spin_unlock_irqrestore(&s->thread_lock, flags); wake_up(&s->thread_wait); }