diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
commit | 95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch) | |
tree | 27a92a942821cde1edda9a1b088718d436b3efe4 /drivers/pcmcia | |
parent | 45b27b0a0652331d104c953a5b192d843fff88f8 (diff) |
Merge with Linux 2.3.40.
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/bulkmem.c | 7 | ||||
-rw-r--r-- | drivers/pcmcia/cardbus.c | 147 | ||||
-rw-r--r-- | drivers/pcmcia/cb_enabler.c | 18 | ||||
-rw-r--r-- | drivers/pcmcia/cistpl.c | 112 | ||||
-rw-r--r-- | drivers/pcmcia/cs.c | 126 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 91 | ||||
-rw-r--r-- | drivers/pcmcia/i82365.c | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pci_socket.c | 7 | ||||
-rw-r--r-- | drivers/pcmcia/pci_socket.h | 11 | ||||
-rw-r--r-- | drivers/pcmcia/ricoh.h | 72 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_mgr.c | 47 | ||||
-rw-r--r-- | drivers/pcmcia/tcic.c | 7 | ||||
-rw-r--r-- | drivers/pcmcia/ti113x.h | 125 | ||||
-rw-r--r-- | drivers/pcmcia/yenta.c | 204 |
14 files changed, 581 insertions, 394 deletions
diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c index 269f5c337..1c0a21146 100644 --- a/drivers/pcmcia/bulkmem.c +++ b/drivers/pcmcia/bulkmem.c @@ -2,7 +2,7 @@ PCMCIA Bulk Memory Services - bulkmem.c 1.33 1999/10/25 20:03:33 + bulkmem.c 1.34 1999/11/17 01:37:55 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -179,7 +179,7 @@ static void retry_erase(erase_busy_t *busy, u_int cause) } busy->client->event_callback_args.info = erase; EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW); - kfree_s(busy, sizeof(*busy)); + kfree(busy); /* Resubmit anything waiting for a request to finish */ wake_up_interruptible(&mtd->mtd_req); retry_erase_list(&mtd->erase_busy, 0); @@ -484,6 +484,7 @@ int pcmcia_register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header, if ((handle == NULL) || CHECK_HANDLE(*handle)) return CS_BAD_HANDLE; queue = kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) return CS_OUT_OF_RESOURCE; queue->eraseq_magic = ERASEQ_MAGIC; queue->handle = *handle; queue->count = header->QueueEntryCnt; @@ -502,7 +503,7 @@ int pcmcia_deregister_erase_queue(eraseq_handle_t eraseq) if (i < eraseq->count) return CS_BUSY; eraseq->eraseq_magic = 0; - kfree_s(eraseq, sizeof(*eraseq)); + kfree(eraseq); return CS_SUCCESS; } /* deregister_erase_queue */ diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 88175e08d..74114b4fe 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -99,11 +99,6 @@ static int pc_debug = PCMCIA_DEBUG; #define PCDATA_CODE_TYPE 0x0014 #define PCDATA_INDICATOR 0x0015 -#ifndef CONFIG_PROC_FS -#define pci_proc_attach_device(dev) do { } while (0) -#define pci_proc_detach_device(dev) do { } while (0) -#endif - typedef struct cb_config_t { struct pci_dev dev; } cb_config_t; @@ -111,39 +106,12 @@ typedef struct cb_config_t { /*===================================================================== Expansion ROM's have a special layout, and pointers specify an - image number and an offset within that image. check_rom() - verifies that the expansion ROM exists and has the standard - layout. xlate_rom_addr() converts an image/offset address to an - absolute offset from the ROM's base address. + image number and an offset within that image. xlate_rom_addr() + converts an image/offset address to an absolute offset from the + ROM's base address. =====================================================================*/ -static int check_rom(u_char * b, u_long len) -{ - u_int img = 0, ofs = 0, sz; - u_short data; - DEBUG(0, "ROM image dump:\n"); - while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { - data = readb(b + ROM_DATA_PTR) + - (readb(b + ROM_DATA_PTR + 1) << 8); - sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + - (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); - DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", - img, ofs, ofs + sz - 1, - readb(b + data + PCDATA_SIGNATURE), - readb(b + data + PCDATA_SIGNATURE + 1), - readb(b + data + PCDATA_SIGNATURE + 2), - readb(b + data + PCDATA_SIGNATURE + 3)); - ofs += sz; - img++; - if ((readb(b + data + PCDATA_INDICATOR) & 0x80) || - (sz == 0) || (ofs >= len)) - break; - b += sz; - } - return img; -} - static u_int xlate_rom_addr(u_char * b, u_int addr) { u_int img = 0, ofs = 0, sz; @@ -261,6 +229,21 @@ fail: =====================================================================*/ +static int cb_assign_irq(u32 mask) +{ + int irq, try; + + for (try = 0; try < 2; try++) { + for (irq = 1; irq < 32; irq++) { + if ((mask >> irq) & 1) { + if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0) + return irq; + } + } + } + return 0; +} + int cb_alloc(socket_info_t * s) { struct pci_bus *bus; @@ -268,6 +251,7 @@ int cb_alloc(socket_info_t * s) u_short vend, v, dev; u_char i, hdr, fn; cb_config_t *c; + int irq; bus = s->cap.cb_dev->subordinate; memset(&tmp, 0, sizeof(tmp)); @@ -297,8 +281,10 @@ int cb_alloc(socket_info_t * s) return CS_OUT_OF_RESOURCE; memset(c, 0, fn * sizeof(struct cb_config_t)); + irq = s->cap.pci_irq; for (i = 0; i < fn; i++) { struct pci_dev *dev = &c[i].dev; + u8 irq_pin; int r; dev->bus = bus; @@ -306,41 +292,35 @@ int cb_alloc(socket_info_t * s) dev->devfn = i; dev->vendor = vend; pci_readw(dev, PCI_DEVICE_ID, &dev->device); - dev->hdr_type = hdr; + dev->hdr_type = hdr & 0x7f; pci_setup_device(dev); + /* FIXME: Do we need to enable the expansion ROM? */ for (r = 0; r < 7; r++) { struct resource *res = dev->resource + r; - if (res->flags) { - /* Unset resource address, assign new one! */ - res->end -= res->start; - res->start = 0; + if (res->flags) pci_assign_resource(dev, r); - } } - - list_add_tail(&dev->bus_list, &bus->devices); - list_add_tail(&dev->global_list, &pci_devices); - pci_proc_attach_device(dev); pci_enable_device(dev); + + /* Does this function have an interrupt at all? */ + pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin); + if (irq_pin) { + if (!irq) + irq = cb_assign_irq(s->cap.irq_mask); + dev->irq = irq; + pci_writeb(dev, PCI_INTERRUPT_LINE, irq); + } + + pci_insert_device(dev, bus); } s->cb_config = c; + s->irq.AssignedIRQ = irq; return CS_SUCCESS; } -static void free_resources(struct pci_dev *dev) -{ - int i; - - for (i = 0; i < 7; i++) { - struct resource *res = dev->resource + i; - if (res->parent) - release_resource(res); - } -} - void cb_free(socket_info_t * s) { cb_config_t *c = s->cb_config; @@ -349,14 +329,9 @@ void cb_free(socket_info_t * s) int i; s->cb_config = NULL; - for(i=0; i<s->functions; i++) { - struct pci_dev *dev = &c[i].dev; + for (i = 0 ; i < s->functions ; i++) + pci_remove_device(&c[i].dev); - list_del(&dev->bus_list); - list_del(&dev->global_list); - free_resources(dev); - pci_proc_detach_device(dev); - } kfree(c); printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number); } @@ -374,54 +349,8 @@ void cb_free(socket_info_t * s) ======================================================================*/ -static int cb_assign_irq(u32 mask) -{ - int irq, try; - - for (try = 0; try < 2; try++) { - for (irq = 1; irq < 32; irq++) { - if ((mask >> irq) & 1) { - if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0) - return irq; - } - } - } - return 0; -} - int cb_config(socket_info_t * s) { - cb_config_t *c = s->cb_config; - u_char fn = s->functions; - int i, irq; - - printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number); - - /* - * If we have a PCI interrupt for the bridge, - * then use that.. - */ - irq = s->cap.pci_irq; - - for (i = 0; i < fn; i++) { - struct pci_dev *dev = &c[i].dev; - u8 irq_pin; - - /* Does this function have an interrupt at all? */ - pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin); - if (!irq_pin) - continue; - - if (!irq) { - irq = cb_assign_irq(s->cap.irq_mask); - if (!irq) - return CS_OUT_OF_RESOURCE; - } - - dev->irq = irq; - pci_writeb(dev, PCI_INTERRUPT_LINE, irq); - } - s->irq.AssignedIRQ = irq; return CS_SUCCESS; } diff --git a/drivers/pcmcia/cb_enabler.c b/drivers/pcmcia/cb_enabler.c index bb8fe17b2..0e5ddeb93 100644 --- a/drivers/pcmcia/cb_enabler.c +++ b/drivers/pcmcia/cb_enabler.c @@ -1,8 +1,8 @@ /*====================================================================== - Cardbus device enabler + CardBus device enabler - cb_enabler.c 1.25 1999/10/25 20:03:33 + cb_enabler.c 1.28 1999/12/09 20:57:37 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -58,11 +58,14 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"cb_enabler.c 1.25 1999/10/25 20:03:33 (David Hinds)"; +"cb_enabler.c 1.28 1999/12/09 20:57:37 (David Hinds)"; #else #define DEBUG(n, args...) do { } while (0) #endif +MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>"); +MODULE_DESCRIPTION("CardBus stub enabler module"); + /*====================================================================*/ /* Parameters that can be set with 'insmod' */ @@ -126,10 +129,11 @@ struct dev_link_t *cb_attach(int n) DEBUG(0, "cb_attach(%d)\n", n); - MOD_INC_USE_COUNT; link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + if (!link) return NULL; + MOD_INC_USE_COUNT; + memset(link, 0, sizeof(struct dev_link_t)); link->conf.IntType = INT_CARDBUS; link->conf.Vcc = 33; @@ -142,7 +146,7 @@ struct dev_link_t *cb_attach(int n) client_reg.dev_info = &driver[n].dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &cb_event; - client_reg.EventMask = + client_reg.EventMask = CS_EVENT_RESET_PHYSICAL | CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; @@ -186,7 +190,7 @@ static void cb_detach(dev_link_t *link) pcmcia_deregister_client(link->handle); *linkp = link->next; - kfree_s(link, sizeof(struct dev_link_t)); + kfree(link); MOD_DEC_USE_COUNT; } diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index eb287bee9..acca17316 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -2,7 +2,7 @@ PCMCIA Card Information Structure parser - cistpl.c 1.74 1999/11/08 20:47:02 + cistpl.c 1.77 2000/01/16 19:19:01 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -52,6 +52,7 @@ #include <pcmcia/ss.h> #include <pcmcia/cs.h> #include <pcmcia/bulkmem.h> +#include <pcmcia/cisreg.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" #include "rsrc_mgr.h" @@ -83,12 +84,15 @@ static const u_int exponent[] = { ======================================================================*/ +/* Bits in attr field */ +#define IS_ATTR 1 +#define IS_INDIRECT 8 + void read_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr) { pccard_mem_map *mem = &s->cis_mem; - u_char *sys; - u_int inc = 1; + u_char *sys, *buf = ptr; DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (setup_cis_mem(s) != 0) { @@ -96,47 +100,81 @@ void read_cis_mem(socket_info_t *s, int attr, u_int addr, return; } mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB; - if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - sys = s->cis_virt + (addr & (s->cap.map_size-1)); - mem->card_start = addr & ~(s->cap.map_size-1); - - for (; len > 0; sys = s->cis_virt) { + sys = s->cis_virt; + + if (attr & IS_INDIRECT) { + /* Indirect accesses use a bunch of special registers at fixed + locations in common memory */ + u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; + if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } + mem->card_start = 0; s->ss_entry->set_mem_map(s->sock, mem); - DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n", - bus_readb(s->cap.bus, sys), - bus_readb(s->cap.bus, sys+inc), - bus_readb(s->cap.bus, sys+2*inc), - bus_readb(s->cap.bus, sys+3*inc), - bus_readb(s->cap.bus, sys+4*inc)); - for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - *(u_char *)ptr = bus_readb(s->cap.bus, sys); + bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); + bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); + bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); + bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); + bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); + for ( ; len > 0; len--, buf++) + *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0); + } else { + u_int inc = 1; + if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } + sys += (addr & (s->cap.map_size-1)); + mem->card_start = addr & ~(s->cap.map_size-1); + + for (; len > 0; sys = s->cis_virt) { + s->ss_entry->set_mem_map(s->sock, mem); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == s->cis_virt+s->cap.map_size) break; + *buf = bus_readb(s->cap.bus, sys); + } + mem->card_start += s->cap.map_size; } - mem->card_start += s->cap.map_size; } + DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", + *(u_char *)(ptr+0), *(u_char *)(ptr+1), + *(u_char *)(ptr+2), *(u_char *)(ptr+3)); } void write_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr) { pccard_mem_map *mem = &s->cis_mem; - u_char *sys; - int inc = 1; + u_char *sys, *buf = ptr; DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (setup_cis_mem(s) != 0) return; - mem->flags &= ~MAP_ATTRIB; - if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - sys = s->cis_virt + (addr & (s->cap.map_size-1)); - mem->card_start = addr & ~(s->cap.map_size-1); - - for (; len > 0; sys = s->cis_virt) { + mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB; + sys = s->cis_virt; + + if (attr & IS_INDIRECT) { + /* Indirect accesses use a bunch of special registers at fixed + locations in common memory */ + u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; + if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } + mem->card_start = 0; s->ss_entry->set_mem_map(s->sock, mem); - for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - bus_writeb(s->cap.bus, *(u_char *)ptr, sys); + bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); + bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); + bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); + bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); + bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); + for ( ; len > 0; len--, buf++) + bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0); + } else { + int inc = 1; + if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } + sys += (addr & (s->cap.map_size-1)); + mem->card_start = addr & ~(s->cap.map_size-1); + + for (; len > 0; sys = s->cis_virt) { + s->ss_entry->set_mem_map(s->sock, mem); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == s->cis_virt+s->cap.map_size) break; + bus_writeb(s->cap.bus, *buf, sys); + } + mem->card_start += s->cap.map_size; } - mem->card_start += s->cap.map_size; } } @@ -342,10 +380,10 @@ int pcmcia_replace_cis(client_handle_t handle, cisdump_t *cis) ======================================================================*/ typedef struct tuple_flags { - u_int link_space:3; + u_int link_space:4; u_int has_link:1; u_int mfc_fn:3; - u_int space:3; + u_int space:4; } tuple_flags; #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) @@ -469,18 +507,24 @@ int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple) (link[0] == CISTPL_LONGLINK_C) || (link[0] == CISTPL_LONGLINK_MFC) || (link[0] == CISTPL_LINKTARGET) || + (link[0] == CISTPL_INDIRECT) || (link[0] == CISTPL_NO_LINK)) { switch (link[0]) { case CISTPL_LONGLINK_A: HAS_LINK(tuple->Flags) = 1; - LINK_SPACE(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = attr | IS_ATTR; read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); break; case CISTPL_LONGLINK_C: HAS_LINK(tuple->Flags) = 1; - LINK_SPACE(tuple->Flags) = 0; + LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); break; + case CISTPL_INDIRECT: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT; + tuple->LinkOffset = 0; + break; case CISTPL_LONGLINK_MFC: tuple->LinkOffset = ofs + 3; LINK_SPACE(tuple->Flags) = attr; diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d44d505ca..bd671c1b2 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -2,7 +2,7 @@ PCMCIA Card Services -- core services - cs.c 1.235 1999/11/11 17:52:05 + cs.c 1.247 2000/01/15 04:30:35 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -59,7 +59,6 @@ #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/bus_ops.h> - #include "cs_internal.h" #include "rsrc_mgr.h" @@ -72,28 +71,40 @@ static int handle_apm_event(apm_event_t event); int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"cs.c 1.235 1999/11/11 17:52:05 (David Hinds)"; +"cs.c 1.247 2000/01/15 04:30:35 (David Hinds)"; #endif -static const char *release = "Linux PCMCIA Card Services " CS_RELEASE; -#ifdef MODULE -static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION; -#endif -static const char *options = "options: " #ifdef CONFIG_PCI -" [pci]" +#define PCI_OPT " [pci]" +#else +#define PCI_OPT "" #endif #ifdef CONFIG_CARDBUS -" [cardbus]" +#define CB_OPT " [cardbus]" +#else +#define CB_OPT "" #endif #ifdef CONFIG_APM -" [apm]" +#define APM_OPT " [apm]" +#else +#define APM_OPT "" #endif #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \ - !defined(CONFIG_APM) && !defined(CONFIG_PNP_BIOS) -" none" + !defined(CONFIG_APM) +#define OPTIONS " none" +#else +#define OPTIONS PCI_OPT CB_OPT APM_OPT +#endif + +static const char *release = "Linux PCMCIA Card Services " CS_RELEASE; +#ifdef MODULE +static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION; #endif -; +static const char *options = "options: " OPTIONS; + +MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE + "\n options:" OPTIONS); /*====================================================================*/ @@ -263,11 +274,6 @@ static int set_socket(socket_info_t *s, socket_state_t *state) return s->ss_entry->set_socket(s->sock, state); } -static int get_io_map(socket_info_t *s, struct pccard_io_map *io) -{ - return s->ss_entry->get_io_map(s->sock, io); -} - static int set_io_map(socket_info_t *s, struct pccard_io_map *io) { return s->ss_entry->set_io_map(s->sock, io); @@ -734,18 +740,18 @@ static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base, int i; ioaddr_t try, align; - align = (*base) ? (1<<lines) : 1; + align = (*base) ? (lines ? 1<<lines : 0) : 1; if (align && (align < num)) { - printk(KERN_INFO "odd IO request: num %04x align %04x\n", - num, align); - if (*base) + if (*base) { + DEBUG(0, "odd IO request: num %04x align %04x\n", + num, align); align = 0; - else + } else while (align && (align < num)) align <<= 1; } if (*base & ~(align-1)) { - printk(KERN_INFO "odd IO request: base %04x align %04x\n", - *base, align); + DEBUG(0, "odd IO request: base %04x align %04x\n", + *base, align); align = 0; } for (i = 0; i < MAX_IO_WIN; i++) { @@ -862,6 +868,7 @@ int pcmcia_bind_device(bind_req_t *req) s = SOCKET(req); client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL); + if (!client) return CS_OUT_OF_RESOURCE; memset(client, '\0', sizeof(client_t)); client->client_magic = CLIENT_MAGIC; strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); @@ -1122,18 +1129,18 @@ int pcmcia_get_window(window_handle_t *handle, int idx, win_req_t *req) if (win->ctl.flags & MAP_ACTIVE) req->Attributes |= WIN_ENABLE; if (win->ctl.flags & MAP_16BIT) - req->Attributes |= WIN_DATA_WIDTH; + req->Attributes |= WIN_DATA_WIDTH_16; if (win->ctl.flags & MAP_USE_WAIT) req->Attributes |= WIN_USE_WAIT; *handle = win; return CS_SUCCESS; } /* get_window */ -int pcmcia_get_first_window(client_handle_t *handle, win_req_t *req) +int pcmcia_get_first_window(window_handle_t *win, win_req_t *req) { - if ((handle == NULL) || CHECK_HANDLE(*handle)) + if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC)) return CS_BAD_HANDLE; - return pcmcia_get_window((window_handle_t *)handle, 0, req); + return pcmcia_get_window(win, 0, req); } int pcmcia_get_next_window(window_handle_t *win, win_req_t *req) @@ -1143,6 +1150,29 @@ int pcmcia_get_next_window(window_handle_t *win, win_req_t *req) return pcmcia_get_window(win, (*win)->index+1, req); } +/*===================================================================== + + Return the PCI device associated with a card.. + +======================================================================*/ + +#ifdef CONFIG_CARDBUS + +struct pci_bus *pcmcia_lookup_bus(client_handle_t handle) +{ + socket_info_t *s; + + if (CHECK_HANDLE(handle)) + return NULL; + s = SOCKET(handle); + if (!(s->state & SOCKET_CARDBUS)) + return NULL; + + return s->cap.cb_dev->subordinate; +} + +#endif + /*====================================================================== Get the current socket state bits. We don't support the latched @@ -1308,7 +1338,7 @@ int pcmcia_modify_window(window_handle_t win, modwin_t *req) win->ctl.flags |= MAP_ATTRIB; if (req->Attributes & WIN_ENABLE) win->ctl.flags |= MAP_ACTIVE; - if (req->Attributes & WIN_DATA_WIDTH) + if (req->Attributes & WIN_DATA_WIDTH_16) win->ctl.flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) win->ctl.flags |= MAP_USE_WAIT; @@ -1403,7 +1433,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) int pcmcia_release_configuration(client_handle_t handle) { - pccard_io_map io; + pccard_io_map io = { 0, 0, 0, 0, 1 }; socket_info_t *s; int i; @@ -1437,8 +1467,6 @@ int pcmcia_release_configuration(client_handle_t handle) if (s->io[i].Config != 0) continue; io.map = i; - get_io_map(s, &io); - io.flags &= ~MAP_ACTIVE; set_io_map(s, &io); } c->state &= ~CONFIG_LOCKED; @@ -1840,7 +1868,8 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle { socket_info_t *s; window_t *win; - int w, align; + u_long align; + int w; if (CHECK_HANDLE(*handle)) return CS_BAD_HANDLE; @@ -1850,16 +1879,25 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle if (req->Attributes & (WIN_PAGED | WIN_SHARED)) return CS_BAD_ATTRIBUTE; - for (w = 0; w < MAX_WIN; w++) - if (!(s->state & SOCKET_WIN_REQ(w))) break; - if (w == MAX_WIN) - return CS_OUT_OF_RESOURCE; - /* Window size defaults to smallest available */ if (req->Size == 0) req->Size = s->cap.map_size; + align = (((s->cap.features & SS_CAP_MEM_ALIGN) || + (req->Attributes & WIN_STRICT_ALIGN)) ? + req->Size : s->cap.map_size); + if (req->Size & (s->cap.map_size-1)) + return CS_BAD_SIZE; + if (req->Base & (align-1)) + return CS_BAD_BASE; + if (req->Base) + align = 0; /* Allocate system memory window */ + for (w = 0; w < MAX_WIN; w++) + if (!(s->state & SOCKET_WIN_REQ(w))) break; + if (w == MAX_WIN) + return CS_OUT_OF_RESOURCE; + win = &s->win[w]; win->magic = WINDOW_MAGIC; win->index = w; @@ -1867,10 +1905,8 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle win->sock = s; win->base = req->Base; win->size = req->Size; - align = ((s->cap.features & SS_CAP_MEM_ALIGN) || - (req->Attributes & WIN_STRICT_ALIGN)); - if (find_mem_region(&win->base, win->size, - (align ? req->Size : s->cap.map_size), + + if (find_mem_region(&win->base, win->size, align, (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS), (*handle)->dev_info)) @@ -1886,7 +1922,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle win->ctl.flags |= MAP_ATTRIB; if (req->Attributes & WIN_ENABLE) win->ctl.flags |= MAP_ACTIVE; - if (req->Attributes & WIN_DATA_WIDTH) + if (req->Attributes & WIN_DATA_WIDTH_16) win->ctl.flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) win->ctl.flags |= MAP_USE_WAIT; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 5a9b1a4e7..f85e2b4f9 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -2,7 +2,7 @@ PC Card Driver Services - ds.c 1.100 1999/11/08 20:47:02 + ds.c 1.104 2000/01/11 01:18:02 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -46,6 +46,7 @@ #include <linux/ioctl.h> #include <linux/proc_fs.h> #include <linux/poll.h> +#include <linux/pci.h> #include <pcmcia/version.h> #include <pcmcia/cs_types.h> @@ -59,11 +60,14 @@ int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static const char *version = -"ds.c 1.100 1999/11/08 20:47:02 (David Hinds)"; +"ds.c 1.104 2000/01/11 01:18:02 (David Hinds)"; #else #define DEBUG(n, args...) #endif +MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>"); +MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); + /*====================================================================*/ typedef struct driver_info_t { @@ -154,6 +158,7 @@ int register_pccard_driver(dev_info_t *dev_info, break; if (!driver) { driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); + if (!driver) return -ENOMEM; strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN); driver->use_count = 0; driver->status = init_status; @@ -192,7 +197,7 @@ int unregister_pccard_driver(dev_info_t *dev_info) DEV_NAME_LEN) != 0)) d = &(*d)->next; if (*d == NULL) - return -1; + return -ENODEV; target = *d; if (target->use_count == 0) { @@ -376,6 +381,7 @@ static int bind_request(int i, bind_info_t *bind_info) break; if (driver == NULL) { driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); + if (!driver) return -ENOMEM; strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN); driver->use_count = 0; driver->next = root_driver; @@ -429,15 +435,55 @@ static int get_device_info(int i, bind_info_t *bind_info, int first) socket_info_t *s = &socket_table[i]; socket_bind_t *b; dev_node_t *node; - + +#ifdef CONFIG_CARDBUS + /* + * Some unbelievably ugly code to associate the PCI cardbus + * device and its driver with the PCMCIA "bind" information. + */ + { + struct pci_bus *bus; + + bus = pcmcia_lookup_bus(s->handle); + if (bus) { + struct list_head *list; + struct pci_dev *dev = NULL; + + list = bus->devices.next; + while (list != &bus->devices) { + struct pci_dev *pdev = pci_dev_b(list); + list = list->next; + + if (first) { + dev = pdev; + break; + } + + /* Try to handle "next" here some way? */ + } + if (dev && dev->driver) { + strncpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); + bind_info->name[DEV_NAME_LEN-1] = '\0'; + bind_info->major = 0; + bind_info->minor = 0; + bind_info->next = NULL; + return 0; + } + } + } +#endif + for (b = s->bind; b; b = b->next) if (strcmp((char *)b->driver->dev_info, (char *)bind_info->dev_info) == 0) break; if (b == NULL) return -ENODEV; - if ((b->instance == NULL) || - (b->instance->state & DEV_CONFIG_PENDING)) + + if (b->instance == NULL) return -EAGAIN; + if (b->instance->state & DEV_CONFIG_PENDING) + return -EAGAIN; + if (first) node = b->instance->dev; else @@ -481,11 +527,11 @@ static int unbind_request(int i, bind_info_t *bind_info) for (d = &root_driver; *d; d = &((*d)->next)) if (c->driver == *d) break; *d = (*d)->next; - kfree_s(c->driver, sizeof(driver_info_t)); + kfree(c->driver); } } *b = c->next; - kfree_s(c, sizeof(socket_bind_t)); + kfree(c); return 0; } /* unbind_request */ @@ -513,8 +559,9 @@ static int ds_open(struct inode *inode, struct file *file) s->state |= SOCKET_BUSY; } - MOD_INC_USE_COUNT; user = kmalloc(sizeof(user_info_t), GFP_KERNEL); + if (!user) return -ENOMEM; + MOD_INC_USE_COUNT; user->event_tail = user->event_head = 0; user->next = s->user; user->user_magic = USER_MAGIC; @@ -552,7 +599,7 @@ static int ds_release(struct inode *inode, struct file *file) return 0; *link = user->next; user->user_magic = 0; - kfree_s(user, sizeof(user_info_t)); + kfree(user); MOD_DEC_USE_COUNT; return 0; @@ -663,7 +710,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; /* Permission check */ - if (!(cmd & IOC_OUT) && !suser()) + if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (cmd & IOC_IN) { @@ -732,7 +779,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = pcmcia_insert_card(s->handle, NULL); break; case DS_ACCESS_CONFIGURATION_REGISTER: - if ((buf.conf_reg.Action == CS_WRITE) && !suser()) + if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) return -EPERM; ret = pcmcia_access_configuration_register(s->handle, &buf.conf_reg); break; @@ -757,7 +804,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = pcmcia_replace_cis(s->handle, &buf.cisdump); break; case DS_BIND_REQUEST: - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = bind_request(i, &buf.bind_info); break; case DS_GET_DEVICE_INFO: @@ -806,17 +853,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, /*====================================================================*/ static struct file_operations ds_fops = { - NULL, /* lseek */ - ds_read, /* read */ - ds_write, /* write */ - NULL, /* readdir */ - ds_poll, /* poll */ - ds_ioctl, /* ioctl */ - NULL, /* mmap */ - ds_open, /* open */ - NULL, /* flush */ - ds_release, /* release */ - NULL /* fsync */ + open: ds_open, + release: ds_release, + ioctl: ds_ioctl, + read: ds_read, + write: ds_write, + poll: ds_poll }; EXPORT_SYMBOL(register_pccard_driver); @@ -846,6 +888,7 @@ int __init init_pcmcia_ds(void) sockets = serv.Count; socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL); + if (!socket_table) return -1; for (i = 0, s = socket_table; i < sockets; i++, s++) { s->state = 0; s->user = NULL; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 8c96585c6..73c177d8d 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -66,7 +66,6 @@ /* PCI-bus controllers */ #include "old-yenta.h" -#include "ti113x.h" #include "smc34c90.h" #include "topic.h" diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c index 51981e41e..3f4463e75 100644 --- a/drivers/pcmcia/pci_socket.c +++ b/drivers/pcmcia/pci_socket.c @@ -70,9 +70,8 @@ static int pci_inquire_socket(unsigned int sock, socket_cap_t *cap) { pci_socket_t *socket = pci_socket_array + sock; - if (socket->op && socket->op->inquire) - return socket->op->inquire(socket, cap); - return -EINVAL; + *cap = socket->cap; + return 0; } static int pci_get_status(unsigned int sock, unsigned int *value) @@ -166,8 +165,10 @@ static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ { pci_socket_t *socket = nr + pci_socket_array; + memset(socket, 0, sizeof(*socket)); socket->dev = dev; socket->op = ops; + init_waitqueue_head(&socket->wait); return socket->op->open(socket); } diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h index 41ea4ec09..8db7c68b5 100644 --- a/drivers/pcmcia/pci_socket.h +++ b/drivers/pcmcia/pci_socket.h @@ -4,6 +4,9 @@ * (C) Copyright 1999 Linus Torvalds */ +#ifndef __PCI_SOCKET_H +#define __PCI_SOCKET_H + struct pci_socket_ops; typedef struct pci_socket { @@ -14,7 +17,11 @@ typedef struct pci_socket { void *info; struct pci_socket_ops *op; socket_cap_t cap; - struct timer_list timer; + wait_queue_head_t wait; + unsigned int events; + + /* A few words of private data for the low-level driver.. */ + unsigned int private[8]; } pci_socket_t; struct pci_socket_ops { @@ -23,7 +30,6 @@ struct pci_socket_ops { int (*init)(struct pci_socket *); int (*suspend)(struct pci_socket *); - int (*inquire)(struct pci_socket *, socket_cap_t *cap); int (*get_status)(struct pci_socket *, unsigned int *); int (*get_socket)(struct pci_socket *, socket_state_t *); int (*set_socket)(struct pci_socket *, socket_state_t *); @@ -37,3 +43,4 @@ struct pci_socket_ops { extern struct pci_socket_ops yenta_operations; extern struct pci_socket_ops ricoh_operations; +#endif diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h index 8cfd30dac..3084dd5b9 100644 --- a/drivers/pcmcia/ricoh.h +++ b/drivers/pcmcia/ricoh.h @@ -30,6 +30,8 @@ #ifndef _LINUX_RICOH_H #define _LINUX_RICOH_H +#include <linux/config.h> + #define RF5C_MODE_CTL 0x1f /* Mode control */ #define RF5C_PWR_CTL 0x2f /* Mixed voltage control */ #define RF5C_CHIP_ID 0x3a /* Chip identification */ @@ -70,25 +72,6 @@ /* Register definitions for Ricoh PCI-to-CardBus bridges */ -#ifndef PCI_VENDOR_ID_RICOH -#define PCI_VENDOR_ID_RICOH 0x1180 -#endif -#ifndef PCI_DEVICE_ID_RICOH_RL5C465 -#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465 -#endif -#ifndef PCI_DEVICE_ID_RICOH_RL5C466 -#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 -#endif -#ifndef PCI_DEVICE_ID_RICOH_RL5C475 -#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475 -#endif -#ifndef PCI_DEVICE_ID_RICOH_RL5C476 -#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 -#endif -#ifndef PCI_DEVICE_ID_RICOH_RL5C478 -#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 -#endif - /* Extra bits in CB_BRIDGE_CONTROL */ #define RL5C46X_BCR_3E0_ENA 0x0800 #define RL5C46X_BCR_3E2_ENA 0x1000 @@ -129,4 +112,55 @@ #define RL5C4XX_HOLD_MASK 0x1c00 #define RL5C4XX_HOLD_SHIFT 10 +#ifdef __YENTA_H + +#define rl_misc(socket) ((socket)->private[0]) +#define rl_ctl(socket) ((socket)->private[1]) +#define rl_io(socket) ((socket)->private[2]) +#define rl_mem(socket) ((socket)->private[3]) + +/* + * Magic Ricoh initialization code.. Save state at + * beginning, re-initialize it after suspend. + */ +static int ricoh_open(pci_socket_t *socket) +{ + rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); + rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL); + rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); + rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0); + + /* Set the default timings, don't trust the original values */ + rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; + return 0; +} + +static int ricoh_init(pci_socket_t *socket) +{ + yenta_init(socket); + + config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); + config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); + config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); + config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); + return 0; +} + +static struct pci_socket_ops ricoh_ops = { + ricoh_open, + yenta_close, + ricoh_init, + yenta_suspend, + yenta_get_status, + yenta_get_socket, + yenta_set_socket, + yenta_get_io_map, + yenta_set_io_map, + yenta_get_mem_map, + yenta_set_mem_map, + yenta_proc_setup +}; + +#endif /* CONFIG_CARDBUS */ + #endif /* _LINUX_RICOH_H */ diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 569ff8678..d059c4fdb 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -2,7 +2,7 @@ Resource management routines - rsrc_mgr.c 1.76 1999/11/08 20:47:02 + rsrc_mgr.c 1.77 1999/11/16 03:32:59 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -124,10 +124,11 @@ static int add_interval(resource_map_t *map, u_long base, u_long num) break; } q = kmalloc(sizeof(resource_map_t), GFP_KERNEL); + if (!q) return CS_OUT_OF_RESOURCE; q->base = base; q->num = num; q->next = p->next; p->next = q; - return 0; -} /* add_interval */ + return CS_SUCCESS; +} /*====================================================================*/ @@ -158,6 +159,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num) } else { /* Split the block into two pieces */ p = kmalloc(sizeof(resource_map_t), GFP_KERNEL); + if (!p) return CS_OUT_OF_RESOURCE; p->base = base+num; p->num = q->base+q->num - p->base; q->num = base - q->base; @@ -165,8 +167,8 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num) } } } - return 0; -} /* sub_interval */ + return CS_SUCCESS; +} /*====================================================================== @@ -383,7 +385,7 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, } } return -1; -} /* find_io_region */ +} int find_mem_region(u_long *base, u_long num, u_long align, int force_low, char *name) @@ -411,7 +413,7 @@ int find_mem_region(u_long *base, u_long num, u_long align, force_low++; } return -1; -} /* find_mem_region */ +} /*====================================================================== @@ -482,7 +484,7 @@ int try_irq(u_int Attributes, int irq, int specific) } } return 0; -} /* try_irq */ +} #endif @@ -524,34 +526,35 @@ void undo_irq(u_int Attributes, int irq) static int adjust_memory(adjust_t *adj) { u_long base, num; - int i; + int i, ret; base = adj->resource.memory.Base; num = adj->resource.memory.Size; if ((num == 0) || (base+num-1 < base)) return CS_BAD_SIZE; + ret = CS_SUCCESS; switch (adj->Action) { case ADD_MANAGED_RESOURCE: - if (add_interval(&mem_db, base, num) != 0) - return CS_IN_USE; + ret = add_interval(&mem_db, base, num); break; case REMOVE_MANAGED_RESOURCE: - sub_interval(&mem_db, base, num); - for (i = 0; i < sockets; i++) { - release_cis_mem(socket_table[i]); + ret = sub_interval(&mem_db, base, num); + if (ret == CS_SUCCESS) { + for (i = 0; i < sockets; i++) { + release_cis_mem(socket_table[i]); #ifdef CONFIG_CARDBUS - cb_release_cis_mem(socket_table[i]); + cb_release_cis_mem(socket_table[i]); #endif + } } break; default: - return CS_UNSUPPORTED_FUNCTION; - break; + ret = CS_UNSUPPORTED_FUNCTION; } - return CS_SUCCESS; -} /* adjust_mem */ + return ret; +} /*====================================================================*/ @@ -584,7 +587,7 @@ static int adjust_io(adjust_t *adj) } return CS_SUCCESS; -} /* adjust_io */ +} /*====================================================================*/ @@ -625,7 +628,7 @@ static int adjust_irq(adjust_t *adj) } #endif return CS_SUCCESS; -} /* adjust_irq */ +} /*====================================================================*/ @@ -646,7 +649,7 @@ int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj) break; } return CS_UNSUPPORTED_FUNCTION; -} /* adjust_resource_info */ +} /*====================================================================*/ diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index d5900c6f8..ff25ac893 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -2,7 +2,7 @@ Device driver for Databook TCIC-2 PCMCIA controller - tcic.c 1.107 1999/10/25 20:03:34 + tcic.c 1.108 1999/12/09 20:17:29 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -60,12 +60,15 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"tcic.c 1.107 1999/10/25 20:03:34 (David Hinds)"; +"tcic.c 1.108 1999/12/09 20:17:29 (David Hinds)"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) #endif +MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>"); +MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver"); + /*====================================================================*/ /* Parameters that can be set with 'insmod' */ diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index f37faeba5..b8664c6b5 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -30,49 +30,7 @@ #ifndef _LINUX_TI113X_H #define _LINUX_TI113X_H -#ifndef PCI_VENDOR_ID_TI -#define PCI_VENDOR_ID_TI 0x104c -#endif - -#ifndef PCI_DEVICE_ID_TI_1130 -#define PCI_DEVICE_ID_TI_1130 0xac12 -#endif -#ifndef PCI_DEVICE_ID_TI_1131 -#define PCI_DEVICE_ID_TI_1131 0xac15 -#endif -#ifndef PCI_DEVICE_ID_TI_1031 -#define PCI_DEVICE_ID_TI_1031 0xac13 -#endif -#ifndef PCI_DEVICE_ID_TI_1250A -#define PCI_DEVICE_ID_TI_1250A 0xac16 -#endif -#ifndef PCI_DEVICE_ID_TI_1220 -#define PCI_DEVICE_ID_TI_1220 0xac17 -#endif -#ifndef PCI_DEVICE_ID_TI_1221 -#define PCI_DEVICE_ID_TI_1221 0xac19 -#endif -#ifndef PCI_DEVICE_ID_TI_1210 -#define PCI_DEVICE_ID_TI_1210 0xac1a -#endif -#ifndef PCI_DEVICE_ID_TI_1450 -#define PCI_DEVICE_ID_TI_1450 0xac1b -#endif -#ifndef PCI_DEVICE_ID_TI_1225 -#define PCI_DEVICE_ID_TI_1225 0xac1c -#endif -#ifndef PCI_DEVICE_ID_TI_1251A -#define PCI_DEVICE_ID_TI_1251A 0xac1d -#endif -#ifndef PCI_DEVICE_ID_TI_1211 -#define PCI_DEVICE_ID_TI_1211 0xac1e -#endif -#ifndef PCI_DEVICE_ID_TI_1251B -#define PCI_DEVICE_ID_TI_1251B 0xac1f -#endif -#ifndef PCI_DEVICE_ID_TI_1420 -#define PCI_DEVICE_ID_TI_1420 0xac51 -#endif +#include <linux/config.h> /* Register definitions for TI 113X PCI-to-CardBus bridges */ @@ -176,5 +134,86 @@ /* ExCA IO offset registers */ #define TI113X_IO_OFFSET(map) (0x36+((map)<<1)) +#ifdef CONFIG_CARDBUS + +#define ti_sysctl(socket) ((socket)->private[0]) +#define ti_cardctl(socket) ((socket)->private[1]) +#define ti_devctl(socket) ((socket)->private[2]) + +static int ti113x_open(pci_socket_t *socket) +{ + ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL); + ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL); + ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL); + + ti_cardctl(socket) &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC); + if (socket->cb_irq) + ti_cardctl(socket) |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ; + return 0; +} + +static int ti113x_init(pci_socket_t *socket) +{ + yenta_init(socket); + + config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); + config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); + config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket)); + + return 0; +} + +static struct pci_socket_ops ti113x_ops = { + ti113x_open, + yenta_close, + ti113x_init, + yenta_suspend, + yenta_get_status, + yenta_get_socket, + yenta_set_socket, + yenta_get_io_map, + yenta_set_io_map, + yenta_get_mem_map, + yenta_set_mem_map, + yenta_proc_setup +}; + +#define ti_diag(socket) ((socket)->private[0]) + +static int ti1250_open(pci_socket_t *socket) +{ + ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC); + + ti_diag(socket) &= ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ); + if (socket->cb_irq) + ti_diag(socket) |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ; + return 0; +} + +static int ti1250_init(pci_socket_t *socket) +{ + yenta_init(socket); + + config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); + return 0; +} + +static struct pci_socket_ops ti1250_ops = { + ti1250_open, + yenta_close, + ti1250_init, + yenta_suspend, + yenta_get_status, + yenta_get_socket, + yenta_set_socket, + yenta_get_io_map, + yenta_set_io_map, + yenta_get_mem_map, + yenta_set_mem_map, + yenta_proc_setup +}; + +#endif /* CONFIG_CARDBUS */ + #endif /* _LINUX_TI113X_H */ diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index e686a6436..b5a2e35de 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -15,7 +15,6 @@ #include "yenta.h" #include "i82365.h" -#include "ricoh.h" /* Don't ask.. */ #define to_cycles(ns) ((ns)/120) @@ -68,12 +67,6 @@ static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val) exca_writeb(socket, reg+1, val >> 8); } -static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap) -{ - *cap = socket->cap; - return 0; -} - /* * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend * on what kind of card is inserted.. @@ -190,20 +183,22 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) u16 bridge; yenta_set_power(socket, state); - bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST; + 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) { bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; - bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; /* ISA interrupt control? */ - if (bridge & CB_BRIDGE_INTR) { + if (!socket->cb_irq) { u8 intr = exca_readb(socket, I365_INTCTL); intr = (intr & ~0xf) | state->io_irq; exca_writeb(socket, I365_INTCTL, intr); + bridge |= CB_BRIDGE_INTR; } } else { u8 reg; + bridge |= CB_BRIDGE_INTR; reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA); reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; @@ -385,13 +380,12 @@ static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base) /* Not done yet */ } -static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static unsigned int yenta_events(pci_socket_t *socket) { u8 csc; u32 cb_event; unsigned int events; - pci_socket_t *socket = (pci_socket_t *) dev_id; - + /* Clear interrupt status for the event */ cb_event = cb_readl(socket, CB_SOCKET_EVENT); cb_writel(socket, CB_SOCKET_EVENT, cb_event); @@ -407,16 +401,50 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; events |= (csc & I365_CSC_READY) ? SS_READY : 0; } + return events; +} - if (events && socket->handler) - socket->handler(socket->info, events); +static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int events; + pci_socket_t *socket = (pci_socket_t *) dev_id; - mod_timer(&socket->timer, jiffies + HZ); + events = yenta_events(socket); + if (events) { + socket->events |= events; + wake_up_interruptible(&socket->wait); + } } -static void yenta_timer(unsigned long data) +/* + * Watch a socket every second (and possibly in a + * more timely manner if the state change interrupt + * works..) + */ +static int yenta_socket_thread(void * data) { - yenta_interrupt(0, (pci_socket_t *) data, NULL); + pci_socket_t * socket = (pci_socket_t *) data; + DECLARE_WAITQUEUE(wait, current); + + daemonize(); + strcpy(current->comm, "CardBus Watcher"); + + do { + unsigned int events = socket->events | yenta_events(socket); + + if (events) { + socket->events = 0; + if (socket->handler) + socket->handler(socket->info, events); + } + + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&socket->wait, &wait); + if (!socket->events) + schedule_timeout(HZ); + remove_wait_queue(&socket->wait, &wait); + } while (!signal_pending(current)); + return 0; } static unsigned int yenta_probe_irq(pci_socket_t *socket) @@ -424,20 +452,10 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket) int i; unsigned long val; u16 bridge_ctrl; + u32 mask; - /* Are we set up to route the IO irq to the PCI irq? */ + /* Set up ISA irq routing to probe the ISA irqs.. */ bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - if (socket->cb_irq) { - if (bridge_ctrl & CB_BRIDGE_INTR) { - bridge_ctrl &= ~CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - } - printk("CardBus: using PCI interrupt %d\n", socket->cb_irq); - return 1 << socket->cb_irq; - } - - /* Uhhuh. No PCI interrupt: try falling back on ISA interrupts */ - printk("CardBus: Hmm.. No PCI irq routing (irq%d).\n", socket->cb_irq); if (!(bridge_ctrl & CB_BRIDGE_INTR)) { bridge_ctrl |= CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); @@ -459,7 +477,13 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket) cb_writel(socket, CB_SOCKET_EVENT, -1); } cb_writel(socket, CB_SOCKET_MASK, 0); - return probe_irq_mask(val) & 0xffff; + + mask = probe_irq_mask(val) & 0xffff; + + bridge_ctrl &= ~CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); + + return mask; } static void yenta_clear_maps(pci_socket_t *socket) @@ -483,6 +507,7 @@ static void yenta_clear_maps(pci_socket_t *socket) /* Called at resume and initialization events */ static int yenta_init(pci_socket_t *socket) { + u16 bridge; struct pci_dev *dev = socket->dev; pci_set_power_state(socket->dev, 0); @@ -503,6 +528,19 @@ static int yenta_init(pci_socket_t *socket) config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number); config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number); + /* + * Set up the bridging state: + * - enable write posting. + * - memory window 0 prefetchable, window 1 non-prefetchable + * - PCI interrupts enabled if a PCI interrupt exists.. + */ + bridge = config_readw(socket, CB_BRIDGE_CONTROL); + bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); + bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; + if (!socket->cb_irq) + bridge |= CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge); + exca_writeb(socket, I365_GBLCTL, 0x00); exca_writeb(socket, I365_GENCTL, 0x00); @@ -510,29 +548,6 @@ static int yenta_init(pci_socket_t *socket) return 0; } -/* - * More of an example than anything else... The standard - * yenta init code works well enough - but this is how - * you'd do it if you wanted to have a special init sequence. - */ -static int ricoh_init(pci_socket_t *socket) -{ - u16 misc = config_readw(socket, RL5C4XX_MISC); - u16 ctl = config_readw(socket, RL5C4XX_16BIT_CTL); - u16 io = config_readw(socket, RL5C4XX_16BIT_IO_0); - u16 mem = config_readw(socket, RL5C4XX_16BIT_MEM_0); - - ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; - - config_writew(socket, RL5C4XX_MISC, misc); - config_writew(socket, RL5C4XX_16BIT_CTL, ctl); - config_writew(socket, RL5C4XX_16BIT_IO_0, io); - config_writew(socket, RL5C4XX_16BIT_MEM_0, mem); - - return yenta_init(socket); -} - - static int yenta_suspend(pci_socket_t *socket) { yenta_set_socket(socket, &dead_socket); @@ -552,7 +567,7 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket) socket->cap.cb_dev = socket->dev; socket->cap.bus = NULL; - printk("Yenta IRQ list %04x\n", socket->cap.irq_mask); + printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq); } static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) @@ -585,11 +600,11 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) } align = size = 4*1024*1024; - min = 0x10000000; max = ~0U; + min = PCIBIOS_MIN_MEM; max = ~0U; if (type & IORESOURCE_IO) { align = 1024; size = 256; - min = 0x1000; + min = PCIBIOS_MIN_IO; max = 0xffff; } @@ -611,12 +626,50 @@ static void yenta_allocate_resources(pci_socket_t *socket) } /* + * Close it down - release our resources and go home.. + */ +static void yenta_close(pci_socket_t *sock) +{ + if (sock->cb_irq) + free_irq(sock->cb_irq, sock); + if (sock->base) + iounmap(sock->base); +} + +#include "ti113x.h" +#include "ricoh.h" + +/* + * Different cardbus controllers have slightly different + * initialization sequences etc details. List them here.. + */ +#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y +static struct cardbus_override_struct { + unsigned short vendor; + unsigned short device; + struct pci_socket_ops *op; +} cardbus_override[] = { + { PD(TI,1130), &ti113x_ops }, + { PD(TI,1131), &ti113x_ops }, + { PD(TI,1250), &ti1250_ops }, + + { PD(RICOH,RL5C465), &ricoh_ops }, + { PD(RICOH,RL5C466), &ricoh_ops }, + { PD(RICOH,RL5C475), &ricoh_ops }, + { PD(RICOH,RL5C476), &ricoh_ops }, + { PD(RICOH,RL5C478), &ricoh_ops } +}; + +#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct)) + +/* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the * socket information structure.. */ static int yenta_open(pci_socket_t *socket) { + int i; struct pci_dev *dev = socket->dev; /* @@ -645,38 +698,31 @@ static int yenta_open(pci_socket_t *socket) /* Set up the bridge regions.. */ yenta_allocate_resources(socket); - /* - * Always poll the socket too, just in case the cardbus interrupt - * doesn't exist (it happens), or we just lose an interrupt.. - */ - init_timer(&socket->timer); - socket->timer.expires = jiffies + HZ; - socket->timer.data = (unsigned long)socket; - socket->timer.function = yenta_timer; - add_timer(&socket->timer); - if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket)) socket->cb_irq = dev->irq; /* And figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket); + /* Do we have special options for the device? */ + for (i = 0; i < NR_OVERRIDES; i++) { + struct cardbus_override_struct *d = cardbus_override+i; + if (dev->vendor == d->vendor && dev->device == d->device) { + socket->op = d->op; + if (d->op->open) { + int retval = d->op->open(socket); + if (retval < 0) + return retval; + } + } + } + + kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); return 0; } /* - * Close it down - release our resources and go home.. - */ -static void yenta_close(pci_socket_t *sock) -{ - if (sock->cb_irq) - free_irq(sock->cb_irq, sock); - if (sock->base) - iounmap(sock->base); -} - -/* * Standard plain cardbus - no frills, no extensions */ struct pci_socket_ops yenta_operations = { @@ -684,7 +730,6 @@ struct pci_socket_ops yenta_operations = { yenta_close, yenta_init, yenta_suspend, - yenta_inquire, yenta_get_status, yenta_get_socket, yenta_set_socket, @@ -704,7 +749,6 @@ struct pci_socket_ops ricoh_operations = { yenta_close, ricoh_init, yenta_suspend, - yenta_inquire, yenta_get_status, yenta_get_socket, yenta_set_socket, |