Commit 3b47277b authored by Simon Evans's avatar Simon Evans Committed by Linus Torvalds

[PATCH] pcmciamtd update

Resync with CVS. Minor update including better handling of device removal.
parent a463251e
/* /*
* $Id: pcmciamtd.c,v 1.47 2003/05/28 13:36:14 dwmw2 Exp $ * $Id: pcmciamtd.c,v 1.48 2003/06/24 07:14:38 spse Exp $
* *
* pcmciamtd.c - MTD driver for PCMCIA flash memory cards * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
* *
...@@ -43,33 +43,32 @@ MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); ...@@ -43,33 +43,32 @@ MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
static const int debug = 0; static const int debug = 0;
#endif #endif
#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) #define err(format, arg...) printk(KERN_ERR "pcmciamtd: " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg) #define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg) #define warn(format, arg...) printk(KERN_WARNING "pcmciamtd: " format "\n" , ## arg)
#define DRIVER_DESC "PCMCIA Flash memory card driver" #define DRIVER_DESC "PCMCIA Flash memory card driver"
#define DRIVER_VERSION "$Revision: 1.47 $" #define DRIVER_VERSION "$Revision: 1.48 $"
/* Size of the PCMCIA address space: 26 bits = 64 MB */ /* Size of the PCMCIA address space: 26 bits = 64 MB */
#define MAX_PCMCIA_ADDR 0x4000000 #define MAX_PCMCIA_ADDR 0x4000000
struct pcmciamtd_dev { struct pcmciamtd_dev {
struct list_head list;
dev_link_t link; /* PCMCIA link */ dev_link_t link; /* PCMCIA link */
dev_node_t node; /* device node */
caddr_t win_base; /* ioremapped address of PCMCIA window */ caddr_t win_base; /* ioremapped address of PCMCIA window */
unsigned int win_size; /* size of window */ unsigned int win_size; /* size of window */
unsigned int cardsize; /* size of whole card */
unsigned int offset; /* offset into card the window currently points at */ unsigned int offset; /* offset into card the window currently points at */
struct map_info pcmcia_map; struct map_info pcmcia_map;
struct mtd_info *mtd_info; struct mtd_info *mtd_info;
u8 vpp; int vpp;
char mtd_name[sizeof(struct cistpl_vers_1_t)]; char mtd_name[sizeof(struct cistpl_vers_1_t)];
}; };
static dev_info_t dev_info = "pcmciamtd"; static dev_info_t dev_info = "pcmciamtd";
static LIST_HEAD(dev_list); static dev_link_t *dev_list;
/* Module parameters */ /* Module parameters */
...@@ -99,7 +98,7 @@ MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)"); ...@@ -99,7 +98,7 @@ MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
MODULE_PARM(mem_speed, "i"); MODULE_PARM(mem_speed, "i");
MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns"); MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
MODULE_PARM(force_size, "i"); MODULE_PARM(force_size, "i");
MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)"); MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)");
MODULE_PARM(setvpp, "i"); MODULE_PARM(setvpp, "i");
MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)"); MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
MODULE_PARM(vpp, "i"); MODULE_PARM(vpp, "i");
...@@ -116,6 +115,11 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) ...@@ -116,6 +115,11 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
memreq_t mrq; memreq_t mrq;
int ret; int ret;
if(!(dev->link.state & DEV_PRESENT)) {
DEBUG(1, "device removed state = 0x%4.4X", dev->link.state);
return 0;
}
mrq.CardOffset = to & ~(dev->win_size-1); mrq.CardOffset = to & ~(dev->win_size-1);
if(mrq.CardOffset != dev->offset) { if(mrq.CardOffset != dev->offset) {
DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
...@@ -238,11 +242,16 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v ...@@ -238,11 +242,16 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v
/* read/write{8,16} copy_{from,to} routines with direct access */ /* read/write{8,16} copy_{from,to} routines with direct access */
#define DEV_REMOVED(x) (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
static u8 pcmcia_read8(struct map_info *map, unsigned long ofs) static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
{ {
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
u8 d; u8 d;
if(DEV_REMOVED(map))
return 0;
d = readb(win_base + ofs); d = readb(win_base + ofs);
DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d); DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
return d; return d;
...@@ -254,6 +263,9 @@ static u16 pcmcia_read16(struct map_info *map, unsigned long ofs) ...@@ -254,6 +263,9 @@ static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
u16 d; u16 d;
if(DEV_REMOVED(map))
return 0;
d = readw(win_base + ofs); d = readw(win_base + ofs);
DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d); DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
return d; return d;
...@@ -264,6 +276,9 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ...@@ -264,6 +276,9 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from,
{ {
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
if(DEV_REMOVED(map))
return;
DEBUG(3, "to = %p from = %lu len = %u", to, from, len); DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
memcpy_fromio(to, win_base + from, len); memcpy_fromio(to, win_base + from, len);
} }
...@@ -273,6 +288,9 @@ static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr) ...@@ -273,6 +288,9 @@ static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
{ {
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
if(DEV_REMOVED(map))
return;
DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, win_base + adr, d); DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, win_base + adr, d);
writeb(d, win_base + adr); writeb(d, win_base + adr);
} }
...@@ -282,6 +300,9 @@ static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr) ...@@ -282,6 +300,9 @@ static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
{ {
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
if(DEV_REMOVED(map))
return;
DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, win_base + adr, d); DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, win_base + adr, d);
writew(d, win_base + adr); writew(d, win_base + adr);
} }
...@@ -291,6 +312,9 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f ...@@ -291,6 +312,9 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f
{ {
caddr_t win_base = (caddr_t)map->map_priv_2; caddr_t win_base = (caddr_t)map->map_priv_2;
if(DEV_REMOVED(map))
return;
DEBUG(3, "to = %lu from = %p len = %u", to, from, len); DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
memcpy_toio(win_base + to, from, len); memcpy_toio(win_base + to, from, len);
} }
...@@ -323,40 +347,18 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) ...@@ -323,40 +347,18 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)
static void pcmciamtd_release(u_long arg) static void pcmciamtd_release(u_long arg)
{ {
dev_link_t *link = (dev_link_t *)arg; dev_link_t *link = (dev_link_t *)arg;
struct pcmciamtd_dev *dev = NULL; struct pcmciamtd_dev *dev = link->priv;
int ret;
struct list_head *temp1, *temp2;
DEBUG(3, "link = 0x%p", link); DEBUG(3, "link = 0x%p", link);
/* Find device in list */
list_for_each_safe(temp1, temp2, &dev_list) {
dev = list_entry(temp1, struct pcmciamtd_dev, list);
if(link == &dev->link)
break;
}
if(link != &dev->link) {
DEBUG(1, "Cant find %p in dev_list", link);
return;
}
if(dev) { if (link->win) {
if(dev->mtd_info) { if(dev->win_base) {
del_mtd_device(dev->mtd_info); iounmap(dev->win_base);
dev->mtd_info = NULL; dev->win_base = NULL;
MOD_DEC_USE_COUNT;
} }
if (link->win) { CardServices(ReleaseWindow, link->win);
if(dev->win_base) {
iounmap(dev->win_base);
dev->win_base = NULL;
}
CardServices(ReleaseWindow, link->win);
}
ret = CardServices(ReleaseConfiguration, link->handle);
if(ret != CS_SUCCESS)
cs_error(link->handle, ReleaseConfiguration, ret);
} }
CardServices(ReleaseConfiguration, link->handle);
link->state &= ~DEV_CONFIG; link->state &= ~DEV_CONFIG;
} }
...@@ -465,7 +467,6 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ ...@@ -465,7 +467,6 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
if(force_size) { if(force_size) {
dev->pcmcia_map.size = force_size << 20; dev->pcmcia_map.size = force_size << 20;
DEBUG(2, "size forced to %dM", force_size); DEBUG(2, "size forced to %dM", force_size);
} }
if(buswidth) { if(buswidth) {
...@@ -580,9 +581,8 @@ static void pcmciamtd_config(dev_link_t *link) ...@@ -580,9 +581,8 @@ static void pcmciamtd_config(dev_link_t *link)
} }
DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x", DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
dev, req.Base, dev->win_base, req.Size); dev, req.Base, dev->win_base, req.Size);
dev->cardsize = 0;
dev->offset = 0;
dev->offset = 0;
dev->pcmcia_map.map_priv_1 = (unsigned long)dev; dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
dev->pcmcia_map.map_priv_2 = (unsigned long)link->win; dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
...@@ -614,9 +614,6 @@ static void pcmciamtd_config(dev_link_t *link) ...@@ -614,9 +614,6 @@ static void pcmciamtd_config(dev_link_t *link)
cs_error(link->handle, RequestConfiguration, ret); cs_error(link->handle, RequestConfiguration, ret);
} }
link->dev = NULL;
link->state &= ~DEV_CONFIG_PENDING;
if(mem_type == 1) { if(mem_type == 1) {
mtd = do_map_probe("map_ram", &dev->pcmcia_map); mtd = do_map_probe("map_ram", &dev->pcmcia_map);
} else if(mem_type == 2) { } else if(mem_type == 2) {
...@@ -640,7 +637,6 @@ static void pcmciamtd_config(dev_link_t *link) ...@@ -640,7 +637,6 @@ static void pcmciamtd_config(dev_link_t *link)
dev->mtd_info = mtd; dev->mtd_info = mtd;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
dev->cardsize = mtd->size;
if(new_name) { if(new_name) {
int size = 0; int size = 0;
...@@ -649,19 +645,19 @@ static void pcmciamtd_config(dev_link_t *link) ...@@ -649,19 +645,19 @@ static void pcmciamtd_config(dev_link_t *link)
size */ size */
if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */ if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */
size = mtd->size >> 10; size = mtd->size >> 10;
unit = 'K'; unit = 'K';
} else { } else {
size = mtd->size >> 20; size = mtd->size >> 20;
unit = 'M'; unit = 'M';
} }
sprintf(mtd->name, "%d%ciB %s", size, unit, "PCMCIA Memory card"); snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card");
} }
/* If the memory found is fits completely into the mapped PCMCIA window, /* If the memory found is fits completely into the mapped PCMCIA window,
use the faster non-remapping read/write functions */ use the faster non-remapping read/write functions */
if(dev->cardsize <= dev->win_size) { if(mtd->size <= dev->win_size) {
DEBUG(1, "Using non remapping memory functions"); DEBUG(1, "Using non remapping memory functions");
dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
dev->pcmcia_map.read8 = pcmcia_read8; dev->pcmcia_map.read8 = pcmcia_read8;
dev->pcmcia_map.read16 = pcmcia_read16; dev->pcmcia_map.read16 = pcmcia_read16;
...@@ -671,16 +667,17 @@ static void pcmciamtd_config(dev_link_t *link) ...@@ -671,16 +667,17 @@ static void pcmciamtd_config(dev_link_t *link)
dev->pcmcia_map.copy_to = pcmcia_copy_to; dev->pcmcia_map.copy_to = pcmcia_copy_to;
} }
MOD_INC_USE_COUNT;
if(add_mtd_device(mtd)) { if(add_mtd_device(mtd)) {
map_destroy(mtd);
dev->mtd_info = NULL; dev->mtd_info = NULL;
MOD_DEC_USE_COUNT;
err("Couldnt register MTD device"); err("Couldnt register MTD device");
pcmciamtd_release((u_long)link); pcmciamtd_release((u_long)link);
return; return;
} }
DEBUG(1, "mtd added @ %p mtd->priv = %p", mtd, mtd->priv); snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index);
info("mtd%d: %s", mtd->index, mtd->name);
link->state &= ~DEV_CONFIG_PENDING;
link->dev = &dev->node;
return; return;
cs_failed: cs_failed:
...@@ -707,8 +704,14 @@ static int pcmciamtd_event(event_t event, int priority, ...@@ -707,8 +704,14 @@ static int pcmciamtd_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL: case CS_EVENT_CARD_REMOVAL:
DEBUG(2, "EVENT_CARD_REMOVAL"); DEBUG(2, "EVENT_CARD_REMOVAL");
link->state &= ~DEV_PRESENT; link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) if (link->state & DEV_CONFIG) {
struct pcmciamtd_dev *dev = link->priv;
if(dev->mtd_info) {
del_mtd_device(dev->mtd_info);
info("mtd%d: Removed", dev->mtd_info->index);
}
mod_timer(&link->release, jiffies + HZ/20); mod_timer(&link->release, jiffies + HZ/20);
}
break; break;
case CS_EVENT_CARD_INSERTION: case CS_EVENT_CARD_INSERTION:
DEBUG(2, "EVENT_CARD_INSERTION"); DEBUG(2, "EVENT_CARD_INSERTION");
...@@ -746,47 +749,23 @@ static int pcmciamtd_event(event_t event, int priority, ...@@ -746,47 +749,23 @@ static int pcmciamtd_event(event_t event, int priority,
static void pcmciamtd_detach(dev_link_t *link) static void pcmciamtd_detach(dev_link_t *link)
{ {
int ret;
struct pcmciamtd_dev *dev = NULL;
struct list_head *temp1, *temp2;
DEBUG(3, "link=0x%p", link); DEBUG(3, "link=0x%p", link);
/* Find device in list */
list_for_each_safe(temp1, temp2, &dev_list) {
dev = list_entry(temp1, struct pcmciamtd_dev, list);
if(link == &dev->link)
break;
}
if(link != &dev->link) {
DEBUG(1, "Cant find %p in dev_list", link);
return;
}
del_timer(&link->release); del_timer(&link->release);
if(!dev) { if(link->state & DEV_CONFIG) {
DEBUG(3, "dev is NULL"); pcmciamtd_release((u_long)link);
return;
}
if (link->state & DEV_CONFIG) {
//pcmciamtd_release((u_long)link);
DEBUG(3, "DEV_CONFIG set");
link->state |= DEV_STALE_LINK;
return;
} }
if (link->handle) { if (link->handle) {
int ret;
DEBUG(2, "Deregistering with card services"); DEBUG(2, "Deregistering with card services");
ret = CardServices(DeregisterClient, link->handle); ret = CardServices(DeregisterClient, link->handle);
if (ret != CS_SUCCESS) if (ret != CS_SUCCESS)
cs_error(link->handle, DeregisterClient, ret); cs_error(link->handle, DeregisterClient, ret);
} }
DEBUG(3, "Freeing dev (%p)", dev);
list_del(&dev->list); link->state |= DEV_STALE_LINK;
link->priv = NULL;
kfree(dev);
} }
...@@ -808,15 +787,18 @@ static dev_link_t *pcmciamtd_attach(void) ...@@ -808,15 +787,18 @@ static dev_link_t *pcmciamtd_attach(void)
DEBUG(1, "dev=0x%p", dev); DEBUG(1, "dev=0x%p", dev);
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
link = &dev->link; link->priv = dev; link = &dev->link;
link->priv = dev;
init_timer(&link->release);
link->release.function = &pcmciamtd_release; link->release.function = &pcmciamtd_release;
link->release.data = (u_long)link; link->release.data = (u_long)link;
link->conf.Attributes = 0; link->conf.Attributes = 0;
link->conf.IntType = INT_MEMORY; link->conf.IntType = INT_MEMORY;
list_add(&dev->list, &dev_list); link->next = dev_list;
dev_list = link;
/* Register with Card Services */ /* Register with Card Services */
client_reg.dev_info = &dev_info; client_reg.dev_info = &dev_info;
...@@ -835,19 +817,21 @@ static dev_link_t *pcmciamtd_attach(void) ...@@ -835,19 +817,21 @@ static dev_link_t *pcmciamtd_attach(void)
pcmciamtd_detach(link); pcmciamtd_detach(link);
return NULL; return NULL;
} }
DEBUG(2, "link = %p", link);
return link; return link;
} }
static struct pcmcia_driver pcmciamtd_driver = { static struct pcmcia_driver pcmciamtd_driver = {
.owner = THIS_MODULE,
.drv = { .drv = {
.name = "pcmciamtd", .name = "pcmciamtd"
}, },
.attach = pcmciamtd_attach, .attach = pcmciamtd_attach,
.detach = pcmciamtd_detach, .detach = pcmciamtd_detach,
.owner = THIS_MODULE
}; };
static int __init init_pcmciamtd(void) static int __init init_pcmciamtd(void)
{ {
info(DRIVER_DESC " " DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION);
...@@ -864,25 +848,41 @@ static int __init init_pcmciamtd(void) ...@@ -864,25 +848,41 @@ static int __init init_pcmciamtd(void)
info("bad mem_type (%d), using default", mem_type); info("bad mem_type (%d), using default", mem_type);
mem_type = 0; mem_type = 0;
} }
return pcmcia_register_driver(&pcmciamtd_driver); return pcmcia_register_driver(&pcmciamtd_driver);
} }
static void __exit exit_pcmciamtd(void) static void __exit exit_pcmciamtd(void)
{ {
struct list_head *temp1, *temp2;
DEBUG(1, DRIVER_DESC " unloading"); DEBUG(1, DRIVER_DESC " unloading");
pcmcia_unregister_driver(&pcmciamtd_driver); pcmcia_unregister_driver(&pcmciamtd_driver);
/* XXX: this really needs to move into generic code.. */ while(dev_list) {
list_for_each_safe(temp1, temp2, &dev_list) { dev_link_t *link = dev_list;
dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
if (link && (link->state & DEV_CONFIG)) { dev_list = link->next;
pcmciamtd_release((u_long)link); if (link) {
pcmciamtd_detach(link); struct pcmciamtd_dev *dev = link->priv;
if(dev) {
if(link->state & DEV_PRESENT) {
if (!(link->state & DEV_STALE_LINK)) {
pcmciamtd_detach(link);
}
link->state &= ~DEV_PRESENT;
if(dev->mtd_info) {
del_mtd_device(dev->mtd_info);
info("mtd%d: Removed",
dev->mtd_info->index);
}
}
if(dev->mtd_info) {
DEBUG(2, "Destroying map for mtd%d",
dev->mtd_info->index);
map_destroy(dev->mtd_info);
}
kfree(dev);
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment