Commit 05ea2914 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-pcmcia

into home.osdl.org:/home/torvalds/v2.5/linux
parents ba8a0415 1d921834
......@@ -281,72 +281,29 @@ int pcmcia_socket_dev_resume(struct device *dev)
EXPORT_SYMBOL(pcmcia_socket_dev_resume);
static int pccardd(void *__skt);
#define to_class_data(dev) dev->class_data
static int pcmcia_add_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
int ret = 0;
/* base address = 0, map = 0 */
socket->cis_mem.flags = 0;
socket->cis_mem.speed = cis_speed;
socket->erase_busy.next = socket->erase_busy.prev = &socket->erase_busy;
INIT_LIST_HEAD(&socket->cis_cache);
spin_lock_init(&socket->lock);
init_completion(&socket->thread_done);
init_waitqueue_head(&socket->thread_wait);
init_MUTEX(&socket->skt_sem);
spin_lock_init(&socket->thread_lock);
socket->socket = dead_socket;
socket->ops->init(socket);
ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
if (ret < 0)
return ret;
wait_for_completion(&socket->thread_done);
BUG_ON(!socket->thread);
pcmcia_parse_events(socket, SS_DETECT);
return 0;
}
static void pcmcia_remove_socket(struct class_device *class_dev)
static void pcmcia_release_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
client_t *client;
if (socket->thread) {
init_completion(&socket->thread_done);
socket->thread = NULL;
wake_up(&socket->thread_wait);
wait_for_completion(&socket->thread_done);
}
release_cis_mem(socket);
while (socket->clients) {
client = socket->clients;
socket->clients = socket->clients->next;
kfree(client);
}
socket->ops = NULL;
}
static void pcmcia_release_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
complete(&socket->socket_released);
}
static int pccardd(void *__skt);
/**
* pcmcia_register_socket - add a new pcmcia socket device
*/
int pcmcia_register_socket(struct pcmcia_socket *socket)
{
int ret;
if (!socket || !socket->ops || !socket->dev.dev)
return -EINVAL;
......@@ -381,15 +338,34 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
socket->dev.class = &pcmcia_socket_class;
snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
/* register with the device core */
if (class_device_register(&socket->dev)) {
down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
return -EINVAL;
}
/* base address = 0, map = 0 */
socket->cis_mem.flags = 0;
socket->cis_mem.speed = cis_speed;
socket->erase_busy.next = socket->erase_busy.prev = &socket->erase_busy;
INIT_LIST_HEAD(&socket->cis_cache);
spin_lock_init(&socket->lock);
init_completion(&socket->socket_released);
init_completion(&socket->thread_done);
init_waitqueue_head(&socket->thread_wait);
init_MUTEX(&socket->skt_sem);
spin_lock_init(&socket->thread_lock);
ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
if (ret < 0)
goto err;
wait_for_completion(&socket->thread_done);
BUG_ON(!socket->thread);
pcmcia_parse_events(socket, SS_DETECT);
return 0;
err:
down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
return ret;
} /* pcmcia_register_socket */
EXPORT_SYMBOL(pcmcia_register_socket);
......@@ -404,10 +380,13 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ops);
init_completion(&socket->socket_released);
/* remove from the device core */
class_device_unregister(&socket->dev);
if (socket->thread) {
init_completion(&socket->thread_done);
socket->thread = NULL;
wake_up(&socket->thread_wait);
wait_for_completion(&socket->thread_done);
}
release_cis_mem(socket);
/* remove from our own list */
down_write(&pcmcia_socket_list_rwsem);
......@@ -783,11 +762,22 @@ static int pccardd(void *__skt)
{
struct pcmcia_socket *skt = __skt;
DECLARE_WAITQUEUE(wait, current);
int ret;
daemonize("pccardd");
skt->thread = current;
complete(&skt->thread_done);
skt->socket = dead_socket;
skt->ops->init(skt);
/* register with the device core */
ret = class_device_register(&skt->dev);
if (ret) {
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
skt);
}
add_wait_queue(&skt->thread_wait, &wait);
for (;;) {
unsigned long flags;
......@@ -823,6 +813,9 @@ static int pccardd(void *__skt)
}
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
class_device_unregister(&skt->dev);
complete_and_exit(&skt->thread_done, 0);
}
......@@ -2501,12 +2494,6 @@ struct class pcmcia_socket_class = {
};
EXPORT_SYMBOL(pcmcia_socket_class);
static struct class_interface pcmcia_socket = {
.class = &pcmcia_socket_class,
.add = &pcmcia_add_socket,
.remove = &pcmcia_remove_socket,
};
static int __init init_pcmcia_cs(void)
{
......@@ -2514,7 +2501,6 @@ static int __init init_pcmcia_cs(void)
printk(KERN_INFO " %s\n", options);
DEBUG(0, "%s\n", version);
class_register(&pcmcia_socket_class);
class_interface_register(&pcmcia_socket);
return 0;
}
......@@ -2523,7 +2509,6 @@ static void __exit exit_pcmcia_cs(void)
{
printk(KERN_INFO "unloading Kernel Card Services\n");
release_resource_db();
class_interface_unregister(&pcmcia_socket);
class_unregister(&pcmcia_socket_class);
}
......
......@@ -491,7 +491,7 @@ static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s)
void validate_mem(struct pcmcia_socket *s)
{
resource_map_t *m, *n;
resource_map_t *m, mm;
static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
static int hi = 0, lo = 0;
u_long b, i, ok = 0;
......@@ -510,18 +510,18 @@ void validate_mem(struct pcmcia_socket *s)
}
if (lo++)
goto out;
for (m = mem_db.next; m != &mem_db; m = n) {
n = m->next;
for (m = mem_db.next; m != &mem_db; m = mm.next) {
mm = *m;
/* Only probe < 1 MB */
if (m->base >= 0x100000) continue;
if ((m->base | m->num) & 0xffff) {
ok += do_mem_probe(m->base, m->num, s);
if (mm.base >= 0x100000) continue;
if ((mm.base | mm.num) & 0xffff) {
ok += do_mem_probe(mm.base, mm.num, s);
continue;
}
/* Special probe for 64K-aligned block */
for (i = 0; i < 4; i++) {
b = order[i] << 12;
if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
if (ok >= mem_limit)
sub_interval(&mem_db, b, 0x10000);
else
......@@ -537,14 +537,14 @@ void validate_mem(struct pcmcia_socket *s)
void validate_mem(struct pcmcia_socket *s)
{
resource_map_t *m, *n;
resource_map_t *m, mm;
static int done = 0;
if (probe_mem && done++ == 0) {
down(&rsrc_sem);
for (m = mem_db.next; m != &mem_db; m = n) {
n = m->next;
if (do_mem_probe(m->base, m->num, s))
for (m = mem_db.next; m != &mem_db; m = mm.next) {
mm = *m;
if (do_mem_probe(mm.base, mm.num, s))
break;
}
up(&rsrc_sem);
......
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