diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 351 |
1 files changed, 147 insertions, 204 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 6fb76399547e..0252582b91cd 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -57,8 +57,6 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644); | |||
57 | 57 | ||
58 | spinlock_t pcmcia_dev_list_lock; | 58 | spinlock_t pcmcia_dev_list_lock; |
59 | 59 | ||
60 | static int unbind_request(struct pcmcia_socket *s); | ||
61 | |||
62 | /*====================================================================*/ | 60 | /*====================================================================*/ |
63 | 61 | ||
64 | /* code which was in cs.c before */ | 62 | /* code which was in cs.c before */ |
@@ -205,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) | |||
205 | unsigned int i; | 203 | unsigned int i; |
206 | u32 hash; | 204 | u32 hash; |
207 | 205 | ||
208 | if (!p_drv->attach || !p_drv->event || !p_drv->detach) | 206 | if (!p_drv->probe || !p_drv->remove) |
209 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " | 207 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " |
210 | "function\n", p_drv->drv.name); | 208 | "function\n", p_drv->drv.name); |
211 | 209 | ||
@@ -266,12 +264,10 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | |||
266 | if (fw->size >= CISTPL_MAX_CIS_SIZE) | 264 | if (fw->size >= CISTPL_MAX_CIS_SIZE) |
267 | goto release; | 265 | goto release; |
268 | 266 | ||
269 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | 267 | cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); |
270 | if (!cis) | 268 | if (!cis) |
271 | goto release; | 269 | goto release; |
272 | 270 | ||
273 | memset(cis, 0, sizeof(cisdump_t)); | ||
274 | |||
275 | cis->Length = fw->size + 1; | 271 | cis->Length = fw->size + 1; |
276 | memcpy(cis->Data, fw->data, fw->size); | 272 | memcpy(cis->Data, fw->data, fw->size); |
277 | 273 | ||
@@ -363,6 +359,7 @@ static int pcmcia_device_probe(struct device * dev) | |||
363 | { | 359 | { |
364 | struct pcmcia_device *p_dev; | 360 | struct pcmcia_device *p_dev; |
365 | struct pcmcia_driver *p_drv; | 361 | struct pcmcia_driver *p_drv; |
362 | struct pcmcia_socket *s; | ||
366 | int ret = 0; | 363 | int ret = 0; |
367 | 364 | ||
368 | dev = get_device(dev); | 365 | dev = get_device(dev); |
@@ -371,25 +368,38 @@ static int pcmcia_device_probe(struct device * dev) | |||
371 | 368 | ||
372 | p_dev = to_pcmcia_dev(dev); | 369 | p_dev = to_pcmcia_dev(dev); |
373 | p_drv = to_pcmcia_drv(dev->driver); | 370 | p_drv = to_pcmcia_drv(dev->driver); |
371 | s = p_dev->socket; | ||
374 | 372 | ||
375 | if (!try_module_get(p_drv->owner)) { | 373 | if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { |
376 | ret = -EINVAL; | 374 | ret = -EINVAL; |
377 | goto put_dev; | 375 | goto put_dev; |
378 | } | 376 | } |
379 | 377 | ||
380 | if (p_drv->attach) { | 378 | p_dev->state &= ~CLIENT_UNBOUND; |
381 | p_dev->instance = p_drv->attach(); | 379 | |
382 | if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) { | 380 | /* set up the device configuration, if it hasn't been done before */ |
383 | printk(KERN_NOTICE "ds: unable to create instance " | 381 | if (!s->functions) { |
384 | "of '%s'!\n", p_drv->drv.name); | 382 | cistpl_longlink_mfc_t mfc; |
385 | ret = -EINVAL; | 383 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, |
384 | &mfc) == CS_SUCCESS) | ||
385 | s->functions = mfc.nfn; | ||
386 | else | ||
387 | s->functions = 1; | ||
388 | s->config = kzalloc(sizeof(config_t) * s->functions, | ||
389 | GFP_KERNEL); | ||
390 | if (!s->config) { | ||
391 | ret = -ENOMEM; | ||
392 | goto put_module; | ||
386 | } | 393 | } |
387 | } | 394 | } |
388 | 395 | ||
396 | ret = p_drv->probe(p_dev); | ||
397 | |||
398 | put_module: | ||
389 | if (ret) | 399 | if (ret) |
390 | module_put(p_drv->owner); | 400 | module_put(p_drv->owner); |
391 | put_dev: | 401 | put_dev: |
392 | if ((ret) || !(p_drv->attach)) | 402 | if (ret) |
393 | put_device(dev); | 403 | put_device(dev); |
394 | return (ret); | 404 | return (ret); |
395 | } | 405 | } |
@@ -399,24 +409,66 @@ static int pcmcia_device_remove(struct device * dev) | |||
399 | { | 409 | { |
400 | struct pcmcia_device *p_dev; | 410 | struct pcmcia_device *p_dev; |
401 | struct pcmcia_driver *p_drv; | 411 | struct pcmcia_driver *p_drv; |
412 | int i; | ||
402 | 413 | ||
403 | /* detach the "instance" */ | 414 | /* detach the "instance" */ |
404 | p_dev = to_pcmcia_dev(dev); | 415 | p_dev = to_pcmcia_dev(dev); |
405 | p_drv = to_pcmcia_drv(dev->driver); | 416 | p_drv = to_pcmcia_drv(dev->driver); |
417 | if (!p_drv) | ||
418 | return 0; | ||
406 | 419 | ||
407 | if (p_drv) { | 420 | if (p_drv->remove) |
408 | if ((p_drv->detach) && (p_dev->instance)) { | 421 | p_drv->remove(p_dev); |
409 | p_drv->detach(p_dev->instance); | 422 | |
410 | /* from pcmcia_probe_device */ | 423 | /* check for proper unloading */ |
411 | put_device(&p_dev->dev); | 424 | if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) |
412 | } | 425 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", |
413 | module_put(p_drv->owner); | 426 | p_drv->drv.name); |
414 | } | 427 | |
428 | for (i = 0; i < MAX_WIN; i++) | ||
429 | if (p_dev->state & CLIENT_WIN_REQ(i)) | ||
430 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", | ||
431 | p_drv->drv.name); | ||
432 | |||
433 | /* references from pcmcia_probe_device */ | ||
434 | p_dev->state = CLIENT_UNBOUND; | ||
435 | pcmcia_put_dev(p_dev); | ||
436 | module_put(p_drv->owner); | ||
415 | 437 | ||
416 | return 0; | 438 | return 0; |
417 | } | 439 | } |
418 | 440 | ||
419 | 441 | ||
442 | /* | ||
443 | * Removes a PCMCIA card from the device tree and socket list. | ||
444 | */ | ||
445 | static void pcmcia_card_remove(struct pcmcia_socket *s) | ||
446 | { | ||
447 | struct pcmcia_device *p_dev; | ||
448 | unsigned long flags; | ||
449 | |||
450 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
451 | |||
452 | s->device_count = 0; | ||
453 | |||
454 | for (;;) { | ||
455 | /* unregister all pcmcia_devices registered with this socket*/ | ||
456 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
457 | if (list_empty(&s->devices_list)) { | ||
458 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
459 | return; | ||
460 | } | ||
461 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
462 | list_del(&p_dev->socket_device_list); | ||
463 | p_dev->state |= CLIENT_STALE; | ||
464 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
465 | |||
466 | device_unregister(&p_dev->dev); | ||
467 | } | ||
468 | |||
469 | return; | ||
470 | } /* unbind_request */ | ||
471 | |||
420 | 472 | ||
421 | /* | 473 | /* |
422 | * pcmcia_device_query -- determine information about a pcmcia device | 474 | * pcmcia_device_query -- determine information about a pcmcia device |
@@ -517,10 +569,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
517 | if (s->device_count == 2) | 569 | if (s->device_count == 2) |
518 | goto err_put; | 570 | goto err_put; |
519 | 571 | ||
520 | p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | 572 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); |
521 | if (!p_dev) | 573 | if (!p_dev) |
522 | goto err_put; | 574 | goto err_put; |
523 | memset(p_dev, 0, sizeof(struct pcmcia_device)); | ||
524 | 575 | ||
525 | p_dev->socket = s; | 576 | p_dev->socket = s; |
526 | p_dev->device_no = (s->device_count++); | 577 | p_dev->device_no = (s->device_count++); |
@@ -583,7 +634,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s) | |||
583 | if (!(s->resource_setup_done)) | 634 | if (!(s->resource_setup_done)) |
584 | return -EAGAIN; /* try again, but later... */ | 635 | return -EAGAIN; /* try again, but later... */ |
585 | 636 | ||
586 | pcmcia_validate_mem(s); | 637 | if (pcmcia_validate_mem(s)) |
638 | return -EAGAIN; /* try again, but later... */ | ||
639 | |||
587 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); | 640 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); |
588 | if (ret || !cisinfo.Chains) { | 641 | if (ret || !cisinfo.Chains) { |
589 | ds_dbg(0, "invalid CIS or invalid resources\n"); | 642 | ds_dbg(0, "invalid CIS or invalid resources\n"); |
@@ -918,55 +971,84 @@ static struct device_attribute pcmcia_dev_attrs[] = { | |||
918 | __ATTR_NULL, | 971 | __ATTR_NULL, |
919 | }; | 972 | }; |
920 | 973 | ||
974 | /* PM support, also needed for reset */ | ||
921 | 975 | ||
922 | /*====================================================================== | 976 | static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) |
977 | { | ||
978 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
979 | struct pcmcia_driver *p_drv = NULL; | ||
923 | 980 | ||
924 | The card status event handler. | 981 | if (dev->driver) |
925 | 982 | p_drv = to_pcmcia_drv(dev->driver); | |
926 | ======================================================================*/ | ||
927 | 983 | ||
928 | struct send_event_data { | 984 | if (p_drv && p_drv->suspend) |
929 | struct pcmcia_socket *skt; | 985 | return p_drv->suspend(p_dev); |
930 | event_t event; | 986 | |
931 | int priority; | 987 | return 0; |
932 | }; | 988 | } |
933 | 989 | ||
934 | static int send_event_callback(struct device *dev, void * _data) | 990 | |
991 | static int pcmcia_dev_resume(struct device * dev) | ||
935 | { | 992 | { |
936 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 993 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
937 | struct pcmcia_driver *p_drv; | 994 | struct pcmcia_driver *p_drv = NULL; |
938 | struct send_event_data *data = _data; | ||
939 | 995 | ||
940 | /* we get called for all sockets, but may only pass the event | 996 | if (dev->driver) |
941 | * for drivers _on the affected socket_ */ | 997 | p_drv = to_pcmcia_drv(dev->driver); |
942 | if (p_dev->socket != data->skt) | ||
943 | return 0; | ||
944 | 998 | ||
945 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | 999 | if (p_drv && p_drv->resume) |
946 | if (!p_drv) | 1000 | return p_drv->resume(p_dev); |
1001 | |||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) | ||
1007 | { | ||
1008 | struct pcmcia_socket *skt = _data; | ||
1009 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
1010 | |||
1011 | if (p_dev->socket != skt) | ||
947 | return 0; | 1012 | return 0; |
948 | 1013 | ||
949 | if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) | 1014 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); |
1015 | } | ||
1016 | |||
1017 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | ||
1018 | { | ||
1019 | struct pcmcia_socket *skt = _data; | ||
1020 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
1021 | |||
1022 | if (p_dev->socket != skt) | ||
950 | return 0; | 1023 | return 0; |
951 | 1024 | ||
952 | if (p_drv->event) | 1025 | dpm_runtime_resume(dev); |
953 | return p_drv->event(data->event, data->priority, | ||
954 | &p_dev->event_callback_args); | ||
955 | 1026 | ||
956 | return 0; | 1027 | return 0; |
957 | } | 1028 | } |
958 | 1029 | ||
959 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | 1030 | static int pcmcia_bus_resume(struct pcmcia_socket *skt) |
960 | { | 1031 | { |
961 | struct send_event_data private; | 1032 | bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); |
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | static int pcmcia_bus_suspend(struct pcmcia_socket *skt) | ||
1037 | { | ||
1038 | if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, | ||
1039 | pcmcia_bus_suspend_callback)) { | ||
1040 | pcmcia_bus_resume(skt); | ||
1041 | return -EIO; | ||
1042 | } | ||
1043 | return 0; | ||
1044 | } | ||
962 | 1045 | ||
963 | private.skt = s; | ||
964 | private.event = event; | ||
965 | private.priority = priority; | ||
966 | 1046 | ||
967 | return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); | 1047 | /*====================================================================== |
968 | } /* send_event */ | ||
969 | 1048 | ||
1049 | The card status event handler. | ||
1050 | |||
1051 | ======================================================================*/ | ||
970 | 1052 | ||
971 | /* Normally, the event is passed to individual drivers after | 1053 | /* Normally, the event is passed to individual drivers after |
972 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this | 1054 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this |
@@ -976,20 +1058,17 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) | |||
976 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | 1058 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) |
977 | { | 1059 | { |
978 | struct pcmcia_socket *s = pcmcia_get_socket(skt); | 1060 | struct pcmcia_socket *s = pcmcia_get_socket(skt); |
979 | int ret = 0; | ||
980 | 1061 | ||
981 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | 1062 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", |
982 | event, priority, skt); | 1063 | event, priority, skt); |
983 | |||
984 | switch (event) { | ||
985 | 1064 | ||
1065 | switch (event) { | ||
986 | case CS_EVENT_CARD_REMOVAL: | 1066 | case CS_EVENT_CARD_REMOVAL: |
987 | s->pcmcia_state.present = 0; | 1067 | s->pcmcia_state.present = 0; |
988 | send_event(skt, event, priority); | 1068 | pcmcia_card_remove(skt); |
989 | unbind_request(skt); | ||
990 | handle_event(skt, event); | 1069 | handle_event(skt, event); |
991 | break; | 1070 | break; |
992 | 1071 | ||
993 | case CS_EVENT_CARD_INSERTION: | 1072 | case CS_EVENT_CARD_INSERTION: |
994 | s->pcmcia_state.present = 1; | 1073 | s->pcmcia_state.present = 1; |
995 | pcmcia_card_add(skt); | 1074 | pcmcia_card_add(skt); |
@@ -997,12 +1076,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
997 | break; | 1076 | break; |
998 | 1077 | ||
999 | case CS_EVENT_EJECTION_REQUEST: | 1078 | case CS_EVENT_EJECTION_REQUEST: |
1000 | ret = send_event(skt, event, priority); | ||
1001 | break; | 1079 | break; |
1002 | 1080 | ||
1081 | case CS_EVENT_PM_SUSPEND: | ||
1082 | case CS_EVENT_PM_RESUME: | ||
1083 | case CS_EVENT_RESET_PHYSICAL: | ||
1084 | case CS_EVENT_CARD_RESET: | ||
1003 | default: | 1085 | default: |
1004 | handle_event(skt, event); | 1086 | handle_event(skt, event); |
1005 | send_event(skt, event, priority); | ||
1006 | break; | 1087 | break; |
1007 | } | 1088 | } |
1008 | 1089 | ||
@@ -1012,152 +1093,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1012 | } /* ds_event */ | 1093 | } /* ds_event */ |
1013 | 1094 | ||
1014 | 1095 | ||
1015 | |||
1016 | int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req) | ||
1017 | { | ||
1018 | struct pcmcia_socket *s = NULL; | ||
1019 | struct pcmcia_device *p_dev = NULL; | ||
1020 | struct pcmcia_driver *p_drv = NULL; | ||
1021 | |||
1022 | /* Look for unbound client with matching dev_info */ | ||
1023 | down_read(&pcmcia_socket_list_rwsem); | ||
1024 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
1025 | unsigned long flags; | ||
1026 | |||
1027 | if (s->state & SOCKET_CARDBUS) | ||
1028 | continue; | ||
1029 | |||
1030 | s = pcmcia_get_socket(s); | ||
1031 | if (!s) | ||
1032 | continue; | ||
1033 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1034 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
1035 | p_dev = pcmcia_get_dev(p_dev); | ||
1036 | if (!p_dev) | ||
1037 | continue; | ||
1038 | if (!(p_dev->state & CLIENT_UNBOUND) || | ||
1039 | (!p_dev->dev.driver)) { | ||
1040 | pcmcia_put_dev(p_dev); | ||
1041 | continue; | ||
1042 | } | ||
1043 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | ||
1044 | if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { | ||
1045 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1046 | goto found; | ||
1047 | } | ||
1048 | pcmcia_put_dev(p_dev); | ||
1049 | } | ||
1050 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1051 | pcmcia_put_socket(s); | ||
1052 | } | ||
1053 | found: | ||
1054 | up_read(&pcmcia_socket_list_rwsem); | ||
1055 | if (!p_dev) | ||
1056 | return -ENODEV; | ||
1057 | |||
1058 | pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ | ||
1059 | |||
1060 | *handle = p_dev; | ||
1061 | p_dev->state &= ~CLIENT_UNBOUND; | ||
1062 | p_dev->event_callback_args = req->event_callback_args; | ||
1063 | p_dev->event_callback_args.client_handle = p_dev; | ||
1064 | |||
1065 | |||
1066 | if (!s->functions) { | ||
1067 | cistpl_longlink_mfc_t mfc; | ||
1068 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc) | ||
1069 | == CS_SUCCESS) | ||
1070 | s->functions = mfc.nfn; | ||
1071 | else | ||
1072 | s->functions = 1; | ||
1073 | s->config = kmalloc(sizeof(config_t) * s->functions, | ||
1074 | GFP_KERNEL); | ||
1075 | if (!s->config) | ||
1076 | goto out_no_resource; | ||
1077 | memset(s->config, 0, sizeof(config_t) * s->functions); | ||
1078 | } | ||
1079 | |||
1080 | ds_dbg(1, "register_client(): client 0x%p, dev %s\n", | ||
1081 | p_dev, p_dev->dev.bus_id); | ||
1082 | |||
1083 | if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { | ||
1084 | if (p_drv->event) | ||
1085 | p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW, | ||
1086 | &p_dev->event_callback_args); | ||
1087 | |||
1088 | } | ||
1089 | |||
1090 | return CS_SUCCESS; | ||
1091 | |||
1092 | out_no_resource: | ||
1093 | pcmcia_put_dev(p_dev); | ||
1094 | return CS_OUT_OF_RESOURCE; | ||
1095 | } /* register_client */ | ||
1096 | EXPORT_SYMBOL(pcmcia_register_client); | ||
1097 | |||
1098 | |||
1099 | /* unbind _all_ devices attached to a given pcmcia_bus_socket. The | ||
1100 | * drivers have been called with EVENT_CARD_REMOVAL before. | ||
1101 | */ | ||
1102 | static int unbind_request(struct pcmcia_socket *s) | ||
1103 | { | ||
1104 | struct pcmcia_device *p_dev; | ||
1105 | unsigned long flags; | ||
1106 | |||
1107 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
1108 | |||
1109 | s->device_count = 0; | ||
1110 | |||
1111 | for (;;) { | ||
1112 | /* unregister all pcmcia_devices registered with this socket*/ | ||
1113 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1114 | if (list_empty(&s->devices_list)) { | ||
1115 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1116 | return 0; | ||
1117 | } | ||
1118 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
1119 | list_del(&p_dev->socket_device_list); | ||
1120 | p_dev->state |= CLIENT_STALE; | ||
1121 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1122 | |||
1123 | device_unregister(&p_dev->dev); | ||
1124 | } | ||
1125 | |||
1126 | return 0; | ||
1127 | } /* unbind_request */ | ||
1128 | |||
1129 | int pcmcia_deregister_client(struct pcmcia_device *p_dev) | ||
1130 | { | ||
1131 | struct pcmcia_socket *s; | ||
1132 | int i; | ||
1133 | |||
1134 | s = p_dev->socket; | ||
1135 | ds_dbg(1, "deregister_client(%p)\n", p_dev); | ||
1136 | |||
1137 | if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) | ||
1138 | goto warn_out; | ||
1139 | for (i = 0; i < MAX_WIN; i++) | ||
1140 | if (p_dev->state & CLIENT_WIN_REQ(i)) | ||
1141 | goto warn_out; | ||
1142 | |||
1143 | if (p_dev->state & CLIENT_STALE) { | ||
1144 | p_dev->state &= ~CLIENT_STALE; | ||
1145 | pcmcia_put_dev(p_dev); | ||
1146 | } else { | ||
1147 | p_dev->state = CLIENT_UNBOUND; | ||
1148 | } | ||
1149 | |||
1150 | return CS_SUCCESS; | ||
1151 | warn_out: | ||
1152 | printk(KERN_WARNING "ds: deregister_client was called too early.\n"); | ||
1153 | return CS_IN_USE; | ||
1154 | } /* deregister_client */ | ||
1155 | EXPORT_SYMBOL(pcmcia_deregister_client); | ||
1156 | |||
1157 | static struct pcmcia_callback pcmcia_bus_callback = { | 1096 | static struct pcmcia_callback pcmcia_bus_callback = { |
1158 | .owner = THIS_MODULE, | 1097 | .owner = THIS_MODULE, |
1159 | .event = ds_event, | 1098 | .event = ds_event, |
1160 | .requery = pcmcia_bus_rescan, | 1099 | .requery = pcmcia_bus_rescan, |
1100 | .suspend = pcmcia_bus_suspend, | ||
1101 | .resume = pcmcia_bus_resume, | ||
1161 | }; | 1102 | }; |
1162 | 1103 | ||
1163 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, | 1104 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, |
@@ -1226,6 +1167,8 @@ struct bus_type pcmcia_bus_type = { | |||
1226 | .uevent = pcmcia_bus_uevent, | 1167 | .uevent = pcmcia_bus_uevent, |
1227 | .match = pcmcia_bus_match, | 1168 | .match = pcmcia_bus_match, |
1228 | .dev_attrs = pcmcia_dev_attrs, | 1169 | .dev_attrs = pcmcia_dev_attrs, |
1170 | .suspend = pcmcia_dev_suspend, | ||
1171 | .resume = pcmcia_dev_resume, | ||
1229 | }; | 1172 | }; |
1230 | 1173 | ||
1231 | 1174 | ||