diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 177 |
1 files changed, 27 insertions, 150 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 8eff55b6c9e9..0fc61dd1d4d0 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -203,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) | |||
203 | unsigned int i; | 203 | unsigned int i; |
204 | u32 hash; | 204 | u32 hash; |
205 | 205 | ||
206 | if (!p_drv->attach || !p_drv->event || !p_drv->remove) | 206 | if (!p_drv->probe || !p_drv->remove) |
207 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " | 207 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " |
208 | "function\n", p_drv->drv.name); | 208 | "function\n", p_drv->drv.name); |
209 | 209 | ||
@@ -361,6 +361,7 @@ static int pcmcia_device_probe(struct device * dev) | |||
361 | { | 361 | { |
362 | struct pcmcia_device *p_dev; | 362 | struct pcmcia_device *p_dev; |
363 | struct pcmcia_driver *p_drv; | 363 | struct pcmcia_driver *p_drv; |
364 | struct pcmcia_socket *s; | ||
364 | int ret = 0; | 365 | int ret = 0; |
365 | 366 | ||
366 | dev = get_device(dev); | 367 | dev = get_device(dev); |
@@ -369,25 +370,39 @@ static int pcmcia_device_probe(struct device * dev) | |||
369 | 370 | ||
370 | p_dev = to_pcmcia_dev(dev); | 371 | p_dev = to_pcmcia_dev(dev); |
371 | p_drv = to_pcmcia_drv(dev->driver); | 372 | p_drv = to_pcmcia_drv(dev->driver); |
373 | s = p_dev->socket; | ||
372 | 374 | ||
373 | if (!try_module_get(p_drv->owner)) { | 375 | if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { |
374 | ret = -EINVAL; | 376 | ret = -EINVAL; |
375 | goto put_dev; | 377 | goto put_dev; |
376 | } | 378 | } |
377 | 379 | ||
378 | if (p_drv->attach) { | 380 | p_dev->state &= ~CLIENT_UNBOUND; |
379 | p_dev->instance = p_drv->attach(); | 381 | |
380 | if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) { | 382 | /* set up the device configuration, if it hasn't been done before */ |
381 | printk(KERN_NOTICE "ds: unable to create instance " | 383 | if (!s->functions) { |
382 | "of '%s'!\n", p_drv->drv.name); | 384 | cistpl_longlink_mfc_t mfc; |
383 | ret = -EINVAL; | 385 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, |
386 | &mfc) == CS_SUCCESS) | ||
387 | s->functions = mfc.nfn; | ||
388 | else | ||
389 | s->functions = 1; | ||
390 | s->config = kmalloc(sizeof(config_t) * s->functions, | ||
391 | GFP_KERNEL); | ||
392 | if (!s->config) { | ||
393 | ret = -ENOMEM; | ||
394 | goto put_module; | ||
384 | } | 395 | } |
396 | memset(s->config, 0, sizeof(config_t) * s->functions); | ||
385 | } | 397 | } |
386 | 398 | ||
399 | ret = p_drv->probe(p_dev); | ||
400 | |||
401 | put_module: | ||
387 | if (ret) | 402 | if (ret) |
388 | module_put(p_drv->owner); | 403 | module_put(p_drv->owner); |
389 | put_dev: | 404 | put_dev: |
390 | if ((ret) || !(p_drv->attach)) | 405 | if (ret) |
391 | put_device(dev); | 406 | put_device(dev); |
392 | return (ret); | 407 | return (ret); |
393 | } | 408 | } |
@@ -418,11 +433,8 @@ static int pcmcia_device_remove(struct device * dev) | |||
418 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", | 433 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", |
419 | p_drv->drv.name); | 434 | p_drv->drv.name); |
420 | 435 | ||
421 | /* undo pcmcia_register_client */ | ||
422 | p_dev->state = CLIENT_UNBOUND; | ||
423 | pcmcia_put_dev(p_dev); | ||
424 | |||
425 | /* references from pcmcia_probe_device */ | 436 | /* references from pcmcia_probe_device */ |
437 | p_dev->state = CLIENT_UNBOUND; | ||
426 | pcmcia_put_dev(p_dev); | 438 | pcmcia_put_dev(p_dev); |
427 | module_put(p_drv->owner); | 439 | module_put(p_drv->owner); |
428 | 440 | ||
@@ -1042,49 +1054,6 @@ static int pcmcia_bus_suspend(struct pcmcia_socket *skt) | |||
1042 | 1054 | ||
1043 | ======================================================================*/ | 1055 | ======================================================================*/ |
1044 | 1056 | ||
1045 | struct send_event_data { | ||
1046 | struct pcmcia_socket *skt; | ||
1047 | event_t event; | ||
1048 | int priority; | ||
1049 | }; | ||
1050 | |||
1051 | static int send_event_callback(struct device *dev, void * _data) | ||
1052 | { | ||
1053 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
1054 | struct pcmcia_driver *p_drv; | ||
1055 | struct send_event_data *data = _data; | ||
1056 | |||
1057 | /* we get called for all sockets, but may only pass the event | ||
1058 | * for drivers _on the affected socket_ */ | ||
1059 | if (p_dev->socket != data->skt) | ||
1060 | return 0; | ||
1061 | |||
1062 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | ||
1063 | if (!p_drv) | ||
1064 | return 0; | ||
1065 | |||
1066 | if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) | ||
1067 | return 0; | ||
1068 | |||
1069 | if (p_drv->event) | ||
1070 | return p_drv->event(data->event, data->priority, | ||
1071 | &p_dev->event_callback_args); | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | ||
1077 | { | ||
1078 | struct send_event_data private; | ||
1079 | |||
1080 | private.skt = s; | ||
1081 | private.event = event; | ||
1082 | private.priority = priority; | ||
1083 | |||
1084 | return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); | ||
1085 | } /* send_event */ | ||
1086 | |||
1087 | |||
1088 | /* Normally, the event is passed to individual drivers after | 1057 | /* Normally, the event is passed to individual drivers after |
1089 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this | 1058 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this |
1090 | * is inversed to maintain historic compatibility. | 1059 | * is inversed to maintain historic compatibility. |
@@ -1093,20 +1062,17 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) | |||
1093 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | 1062 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) |
1094 | { | 1063 | { |
1095 | struct pcmcia_socket *s = pcmcia_get_socket(skt); | 1064 | struct pcmcia_socket *s = pcmcia_get_socket(skt); |
1096 | int ret = 0; | ||
1097 | 1065 | ||
1098 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | 1066 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", |
1099 | event, priority, skt); | 1067 | event, priority, skt); |
1100 | |||
1101 | switch (event) { | ||
1102 | 1068 | ||
1069 | switch (event) { | ||
1103 | case CS_EVENT_CARD_REMOVAL: | 1070 | case CS_EVENT_CARD_REMOVAL: |
1104 | s->pcmcia_state.present = 0; | 1071 | s->pcmcia_state.present = 0; |
1105 | send_event(skt, event, priority); | ||
1106 | pcmcia_card_remove(skt); | 1072 | pcmcia_card_remove(skt); |
1107 | handle_event(skt, event); | 1073 | handle_event(skt, event); |
1108 | break; | 1074 | break; |
1109 | 1075 | ||
1110 | case CS_EVENT_CARD_INSERTION: | 1076 | case CS_EVENT_CARD_INSERTION: |
1111 | s->pcmcia_state.present = 1; | 1077 | s->pcmcia_state.present = 1; |
1112 | pcmcia_card_add(skt); | 1078 | pcmcia_card_add(skt); |
@@ -1114,19 +1080,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1114 | break; | 1080 | break; |
1115 | 1081 | ||
1116 | case CS_EVENT_EJECTION_REQUEST: | 1082 | case CS_EVENT_EJECTION_REQUEST: |
1117 | ret = send_event(skt, event, priority); | ||
1118 | break; | 1083 | break; |
1119 | 1084 | ||
1120 | case CS_EVENT_PM_SUSPEND: | 1085 | case CS_EVENT_PM_SUSPEND: |
1121 | case CS_EVENT_PM_RESUME: | 1086 | case CS_EVENT_PM_RESUME: |
1122 | case CS_EVENT_RESET_PHYSICAL: | 1087 | case CS_EVENT_RESET_PHYSICAL: |
1123 | case CS_EVENT_CARD_RESET: | 1088 | case CS_EVENT_CARD_RESET: |
1124 | handle_event(skt, event); | ||
1125 | break; | ||
1126 | |||
1127 | default: | 1089 | default: |
1128 | handle_event(skt, event); | 1090 | handle_event(skt, event); |
1129 | send_event(skt, event, priority); | ||
1130 | break; | 1091 | break; |
1131 | } | 1092 | } |
1132 | 1093 | ||
@@ -1136,90 +1097,6 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1136 | } /* ds_event */ | 1097 | } /* ds_event */ |
1137 | 1098 | ||
1138 | 1099 | ||
1139 | |||
1140 | int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req) | ||
1141 | { | ||
1142 | struct pcmcia_socket *s = NULL; | ||
1143 | struct pcmcia_device *p_dev = NULL; | ||
1144 | struct pcmcia_driver *p_drv = NULL; | ||
1145 | |||
1146 | /* Look for unbound client with matching dev_info */ | ||
1147 | down_read(&pcmcia_socket_list_rwsem); | ||
1148 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
1149 | unsigned long flags; | ||
1150 | |||
1151 | if (s->state & SOCKET_CARDBUS) | ||
1152 | continue; | ||
1153 | |||
1154 | s = pcmcia_get_socket(s); | ||
1155 | if (!s) | ||
1156 | continue; | ||
1157 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1158 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
1159 | p_dev = pcmcia_get_dev(p_dev); | ||
1160 | if (!p_dev) | ||
1161 | continue; | ||
1162 | if (!(p_dev->state & CLIENT_UNBOUND) || | ||
1163 | (!p_dev->dev.driver)) { | ||
1164 | pcmcia_put_dev(p_dev); | ||
1165 | continue; | ||
1166 | } | ||
1167 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | ||
1168 | if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { | ||
1169 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1170 | goto found; | ||
1171 | } | ||
1172 | pcmcia_put_dev(p_dev); | ||
1173 | } | ||
1174 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1175 | pcmcia_put_socket(s); | ||
1176 | } | ||
1177 | found: | ||
1178 | up_read(&pcmcia_socket_list_rwsem); | ||
1179 | if (!p_dev) | ||
1180 | return -ENODEV; | ||
1181 | |||
1182 | pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ | ||
1183 | |||
1184 | *handle = p_dev; | ||
1185 | p_dev->state &= ~CLIENT_UNBOUND; | ||
1186 | p_dev->event_callback_args = req->event_callback_args; | ||
1187 | p_dev->event_callback_args.client_handle = p_dev; | ||
1188 | |||
1189 | |||
1190 | if (!s->functions) { | ||
1191 | cistpl_longlink_mfc_t mfc; | ||
1192 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc) | ||
1193 | == CS_SUCCESS) | ||
1194 | s->functions = mfc.nfn; | ||
1195 | else | ||
1196 | s->functions = 1; | ||
1197 | s->config = kmalloc(sizeof(config_t) * s->functions, | ||
1198 | GFP_KERNEL); | ||
1199 | if (!s->config) | ||
1200 | goto out_no_resource; | ||
1201 | memset(s->config, 0, sizeof(config_t) * s->functions); | ||
1202 | } | ||
1203 | |||
1204 | ds_dbg(1, "register_client(): client 0x%p, dev %s\n", | ||
1205 | p_dev, p_dev->dev.bus_id); | ||
1206 | |||
1207 | if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { | ||
1208 | if (p_drv->event) | ||
1209 | p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW, | ||
1210 | &p_dev->event_callback_args); | ||
1211 | |||
1212 | } | ||
1213 | |||
1214 | return CS_SUCCESS; | ||
1215 | |||
1216 | out_no_resource: | ||
1217 | pcmcia_put_dev(p_dev); | ||
1218 | return CS_OUT_OF_RESOURCE; | ||
1219 | } /* register_client */ | ||
1220 | EXPORT_SYMBOL(pcmcia_register_client); | ||
1221 | |||
1222 | |||
1223 | static struct pcmcia_callback pcmcia_bus_callback = { | 1100 | static struct pcmcia_callback pcmcia_bus_callback = { |
1224 | .owner = THIS_MODULE, | 1101 | .owner = THIS_MODULE, |
1225 | .event = ds_event, | 1102 | .event = ds_event, |