Commit 6179b5562d5d17c7c09b54cb11dd925ca308d7a9
Committed by
Linus Torvalds
1 parent
02c83595b8
Exists in
master
and in
20 other branches
add new_id to PCMCIA drivers
PCI drivers have the new_id file in sysfs which allows new IDs to be added at runtime. The advantage is to avoid re-compilation of a driver that works for a new device, but it's ID table doesn't contain the new device. This mechanism is only meant for testing, after the driver has been tested successfully, the ID should be added in source code so that new revisions of the kernel automatically detect the device. The implementation follows the PCI implementation. The interface is documented in Documentation/pcmcia/driver.txt. Computations should be done in userspace, so the sysfs string contains the raw structure members for matching. Signed-off-by: Bernhard Walle <bwalle@suse.de> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 148 additions and 1 deletions Inline Diff
Documentation/pcmcia/driver.txt
File was created | 1 | PCMCIA Driver | |
2 | ------------- | ||
3 | |||
4 | |||
5 | sysfs | ||
6 | ----- | ||
7 | |||
8 | New PCMCIA IDs may be added to a device driver pcmcia_device_id table at | ||
9 | runtime as shown below: | ||
10 | |||
11 | echo "match_flags manf_id card_id func_id function device_no \ | ||
12 | prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \ | ||
13 | /sys/bus/pcmcia/drivers/{driver}/new_id | ||
14 | |||
15 | All fields are passed in as hexadecimal values (no leading 0x). | ||
16 | The meaning is described in the PCMCIA specification, the match_flags is | ||
17 | a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants | ||
18 | defined in include/linux/mod_devicetable.h. | ||
19 | |||
20 | Once added, the driver probe routine will be invoked for any unclaimed | ||
21 | PCMCIA device listed in its (newly updated) pcmcia_device_id list. | ||
22 | |||
23 | A common use-case is to add a new device according to the manufacturer ID | ||
24 | and the card ID (form the manf_id and card_id file in the device tree). | ||
25 | For this, just use: | ||
26 | |||
27 | echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \ | ||
28 | /sys/bus/pcmcia/drivers/{driver}/new_id | ||
29 | |||
30 | after loading the driver. | ||
31 |
drivers/pcmcia/ds.c
1 | /* | 1 | /* |
2 | * ds.c -- 16-bit PCMCIA core support | 2 | * ds.c -- 16-bit PCMCIA core support |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * The initial developer of the original code is David A. Hinds | 8 | * The initial developer of the original code is David A. Hinds |
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | 9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds |
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | 10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. |
11 | * | 11 | * |
12 | * (C) 1999 David A. Hinds | 12 | * (C) 1999 David A. Hinds |
13 | * (C) 2003 - 2006 Dominik Brodowski | 13 | * (C) 2003 - 2006 Dominik Brodowski |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/crc32.h> | 23 | #include <linux/crc32.h> |
24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/kref.h> | 25 | #include <linux/kref.h> |
26 | 26 | ||
27 | #define IN_CARD_SERVICES | 27 | #define IN_CARD_SERVICES |
28 | #include <pcmcia/cs_types.h> | 28 | #include <pcmcia/cs_types.h> |
29 | #include <pcmcia/cs.h> | 29 | #include <pcmcia/cs.h> |
30 | #include <pcmcia/cistpl.h> | 30 | #include <pcmcia/cistpl.h> |
31 | #include <pcmcia/ds.h> | 31 | #include <pcmcia/ds.h> |
32 | #include <pcmcia/ss.h> | 32 | #include <pcmcia/ss.h> |
33 | 33 | ||
34 | #include "cs_internal.h" | 34 | #include "cs_internal.h" |
35 | #include "ds_internal.h" | 35 | #include "ds_internal.h" |
36 | 36 | ||
37 | /*====================================================================*/ | 37 | /*====================================================================*/ |
38 | 38 | ||
39 | /* Module parameters */ | 39 | /* Module parameters */ |
40 | 40 | ||
41 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | 41 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); |
42 | MODULE_DESCRIPTION("PCMCIA Driver Services"); | 42 | MODULE_DESCRIPTION("PCMCIA Driver Services"); |
43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
44 | 44 | ||
45 | #ifdef DEBUG | 45 | #ifdef DEBUG |
46 | int ds_pc_debug; | 46 | int ds_pc_debug; |
47 | 47 | ||
48 | module_param_named(pc_debug, ds_pc_debug, int, 0644); | 48 | module_param_named(pc_debug, ds_pc_debug, int, 0644); |
49 | 49 | ||
50 | #define ds_dbg(lvl, fmt, arg...) do { \ | 50 | #define ds_dbg(lvl, fmt, arg...) do { \ |
51 | if (ds_pc_debug > (lvl)) \ | 51 | if (ds_pc_debug > (lvl)) \ |
52 | printk(KERN_DEBUG "ds: " fmt , ## arg); \ | 52 | printk(KERN_DEBUG "ds: " fmt , ## arg); \ |
53 | } while (0) | 53 | } while (0) |
54 | #else | 54 | #else |
55 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) | 55 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | spinlock_t pcmcia_dev_list_lock; | 58 | spinlock_t pcmcia_dev_list_lock; |
59 | 59 | ||
60 | /*====================================================================*/ | 60 | /*====================================================================*/ |
61 | 61 | ||
62 | /* code which was in cs.c before */ | 62 | /* code which was in cs.c before */ |
63 | 63 | ||
64 | /* String tables for error messages */ | 64 | /* String tables for error messages */ |
65 | 65 | ||
66 | typedef struct lookup_t { | 66 | typedef struct lookup_t { |
67 | int key; | 67 | int key; |
68 | char *msg; | 68 | char *msg; |
69 | } lookup_t; | 69 | } lookup_t; |
70 | 70 | ||
71 | static const lookup_t error_table[] = { | 71 | static const lookup_t error_table[] = { |
72 | { CS_SUCCESS, "Operation succeeded" }, | 72 | { CS_SUCCESS, "Operation succeeded" }, |
73 | { CS_BAD_ADAPTER, "Bad adapter" }, | 73 | { CS_BAD_ADAPTER, "Bad adapter" }, |
74 | { CS_BAD_ATTRIBUTE, "Bad attribute", }, | 74 | { CS_BAD_ATTRIBUTE, "Bad attribute", }, |
75 | { CS_BAD_BASE, "Bad base address" }, | 75 | { CS_BAD_BASE, "Bad base address" }, |
76 | { CS_BAD_EDC, "Bad EDC" }, | 76 | { CS_BAD_EDC, "Bad EDC" }, |
77 | { CS_BAD_IRQ, "Bad IRQ" }, | 77 | { CS_BAD_IRQ, "Bad IRQ" }, |
78 | { CS_BAD_OFFSET, "Bad offset" }, | 78 | { CS_BAD_OFFSET, "Bad offset" }, |
79 | { CS_BAD_PAGE, "Bad page number" }, | 79 | { CS_BAD_PAGE, "Bad page number" }, |
80 | { CS_READ_FAILURE, "Read failure" }, | 80 | { CS_READ_FAILURE, "Read failure" }, |
81 | { CS_BAD_SIZE, "Bad size" }, | 81 | { CS_BAD_SIZE, "Bad size" }, |
82 | { CS_BAD_SOCKET, "Bad socket" }, | 82 | { CS_BAD_SOCKET, "Bad socket" }, |
83 | { CS_BAD_TYPE, "Bad type" }, | 83 | { CS_BAD_TYPE, "Bad type" }, |
84 | { CS_BAD_VCC, "Bad Vcc" }, | 84 | { CS_BAD_VCC, "Bad Vcc" }, |
85 | { CS_BAD_VPP, "Bad Vpp" }, | 85 | { CS_BAD_VPP, "Bad Vpp" }, |
86 | { CS_BAD_WINDOW, "Bad window" }, | 86 | { CS_BAD_WINDOW, "Bad window" }, |
87 | { CS_WRITE_FAILURE, "Write failure" }, | 87 | { CS_WRITE_FAILURE, "Write failure" }, |
88 | { CS_NO_CARD, "No card present" }, | 88 | { CS_NO_CARD, "No card present" }, |
89 | { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, | 89 | { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, |
90 | { CS_UNSUPPORTED_MODE, "Unsupported mode" }, | 90 | { CS_UNSUPPORTED_MODE, "Unsupported mode" }, |
91 | { CS_BAD_SPEED, "Bad speed" }, | 91 | { CS_BAD_SPEED, "Bad speed" }, |
92 | { CS_BUSY, "Resource busy" }, | 92 | { CS_BUSY, "Resource busy" }, |
93 | { CS_GENERAL_FAILURE, "General failure" }, | 93 | { CS_GENERAL_FAILURE, "General failure" }, |
94 | { CS_WRITE_PROTECTED, "Write protected" }, | 94 | { CS_WRITE_PROTECTED, "Write protected" }, |
95 | { CS_BAD_ARG_LENGTH, "Bad argument length" }, | 95 | { CS_BAD_ARG_LENGTH, "Bad argument length" }, |
96 | { CS_BAD_ARGS, "Bad arguments" }, | 96 | { CS_BAD_ARGS, "Bad arguments" }, |
97 | { CS_CONFIGURATION_LOCKED, "Configuration locked" }, | 97 | { CS_CONFIGURATION_LOCKED, "Configuration locked" }, |
98 | { CS_IN_USE, "Resource in use" }, | 98 | { CS_IN_USE, "Resource in use" }, |
99 | { CS_NO_MORE_ITEMS, "No more items" }, | 99 | { CS_NO_MORE_ITEMS, "No more items" }, |
100 | { CS_OUT_OF_RESOURCE, "Out of resource" }, | 100 | { CS_OUT_OF_RESOURCE, "Out of resource" }, |
101 | { CS_BAD_HANDLE, "Bad handle" }, | 101 | { CS_BAD_HANDLE, "Bad handle" }, |
102 | { CS_BAD_TUPLE, "Bad CIS tuple" } | 102 | { CS_BAD_TUPLE, "Bad CIS tuple" } |
103 | }; | 103 | }; |
104 | 104 | ||
105 | 105 | ||
106 | static const lookup_t service_table[] = { | 106 | static const lookup_t service_table[] = { |
107 | { AccessConfigurationRegister, "AccessConfigurationRegister" }, | 107 | { AccessConfigurationRegister, "AccessConfigurationRegister" }, |
108 | { AddSocketServices, "AddSocketServices" }, | 108 | { AddSocketServices, "AddSocketServices" }, |
109 | { AdjustResourceInfo, "AdjustResourceInfo" }, | 109 | { AdjustResourceInfo, "AdjustResourceInfo" }, |
110 | { CheckEraseQueue, "CheckEraseQueue" }, | 110 | { CheckEraseQueue, "CheckEraseQueue" }, |
111 | { CloseMemory, "CloseMemory" }, | 111 | { CloseMemory, "CloseMemory" }, |
112 | { DeregisterClient, "DeregisterClient" }, | 112 | { DeregisterClient, "DeregisterClient" }, |
113 | { DeregisterEraseQueue, "DeregisterEraseQueue" }, | 113 | { DeregisterEraseQueue, "DeregisterEraseQueue" }, |
114 | { GetCardServicesInfo, "GetCardServicesInfo" }, | 114 | { GetCardServicesInfo, "GetCardServicesInfo" }, |
115 | { GetClientInfo, "GetClientInfo" }, | 115 | { GetClientInfo, "GetClientInfo" }, |
116 | { GetConfigurationInfo, "GetConfigurationInfo" }, | 116 | { GetConfigurationInfo, "GetConfigurationInfo" }, |
117 | { GetEventMask, "GetEventMask" }, | 117 | { GetEventMask, "GetEventMask" }, |
118 | { GetFirstClient, "GetFirstClient" }, | 118 | { GetFirstClient, "GetFirstClient" }, |
119 | { GetFirstRegion, "GetFirstRegion" }, | 119 | { GetFirstRegion, "GetFirstRegion" }, |
120 | { GetFirstTuple, "GetFirstTuple" }, | 120 | { GetFirstTuple, "GetFirstTuple" }, |
121 | { GetNextClient, "GetNextClient" }, | 121 | { GetNextClient, "GetNextClient" }, |
122 | { GetNextRegion, "GetNextRegion" }, | 122 | { GetNextRegion, "GetNextRegion" }, |
123 | { GetNextTuple, "GetNextTuple" }, | 123 | { GetNextTuple, "GetNextTuple" }, |
124 | { GetStatus, "GetStatus" }, | 124 | { GetStatus, "GetStatus" }, |
125 | { GetTupleData, "GetTupleData" }, | 125 | { GetTupleData, "GetTupleData" }, |
126 | { MapMemPage, "MapMemPage" }, | 126 | { MapMemPage, "MapMemPage" }, |
127 | { ModifyConfiguration, "ModifyConfiguration" }, | 127 | { ModifyConfiguration, "ModifyConfiguration" }, |
128 | { ModifyWindow, "ModifyWindow" }, | 128 | { ModifyWindow, "ModifyWindow" }, |
129 | { OpenMemory, "OpenMemory" }, | 129 | { OpenMemory, "OpenMemory" }, |
130 | { ParseTuple, "ParseTuple" }, | 130 | { ParseTuple, "ParseTuple" }, |
131 | { ReadMemory, "ReadMemory" }, | 131 | { ReadMemory, "ReadMemory" }, |
132 | { RegisterClient, "RegisterClient" }, | 132 | { RegisterClient, "RegisterClient" }, |
133 | { RegisterEraseQueue, "RegisterEraseQueue" }, | 133 | { RegisterEraseQueue, "RegisterEraseQueue" }, |
134 | { RegisterMTD, "RegisterMTD" }, | 134 | { RegisterMTD, "RegisterMTD" }, |
135 | { ReleaseConfiguration, "ReleaseConfiguration" }, | 135 | { ReleaseConfiguration, "ReleaseConfiguration" }, |
136 | { ReleaseIO, "ReleaseIO" }, | 136 | { ReleaseIO, "ReleaseIO" }, |
137 | { ReleaseIRQ, "ReleaseIRQ" }, | 137 | { ReleaseIRQ, "ReleaseIRQ" }, |
138 | { ReleaseWindow, "ReleaseWindow" }, | 138 | { ReleaseWindow, "ReleaseWindow" }, |
139 | { RequestConfiguration, "RequestConfiguration" }, | 139 | { RequestConfiguration, "RequestConfiguration" }, |
140 | { RequestIO, "RequestIO" }, | 140 | { RequestIO, "RequestIO" }, |
141 | { RequestIRQ, "RequestIRQ" }, | 141 | { RequestIRQ, "RequestIRQ" }, |
142 | { RequestSocketMask, "RequestSocketMask" }, | 142 | { RequestSocketMask, "RequestSocketMask" }, |
143 | { RequestWindow, "RequestWindow" }, | 143 | { RequestWindow, "RequestWindow" }, |
144 | { ResetCard, "ResetCard" }, | 144 | { ResetCard, "ResetCard" }, |
145 | { SetEventMask, "SetEventMask" }, | 145 | { SetEventMask, "SetEventMask" }, |
146 | { ValidateCIS, "ValidateCIS" }, | 146 | { ValidateCIS, "ValidateCIS" }, |
147 | { WriteMemory, "WriteMemory" }, | 147 | { WriteMemory, "WriteMemory" }, |
148 | { BindDevice, "BindDevice" }, | 148 | { BindDevice, "BindDevice" }, |
149 | { BindMTD, "BindMTD" }, | 149 | { BindMTD, "BindMTD" }, |
150 | { ReportError, "ReportError" }, | 150 | { ReportError, "ReportError" }, |
151 | { SuspendCard, "SuspendCard" }, | 151 | { SuspendCard, "SuspendCard" }, |
152 | { ResumeCard, "ResumeCard" }, | 152 | { ResumeCard, "ResumeCard" }, |
153 | { EjectCard, "EjectCard" }, | 153 | { EjectCard, "EjectCard" }, |
154 | { InsertCard, "InsertCard" }, | 154 | { InsertCard, "InsertCard" }, |
155 | { ReplaceCIS, "ReplaceCIS" } | 155 | { ReplaceCIS, "ReplaceCIS" } |
156 | }; | 156 | }; |
157 | 157 | ||
158 | 158 | ||
159 | static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err) | 159 | static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err) |
160 | { | 160 | { |
161 | int i; | 161 | int i; |
162 | char *serv; | 162 | char *serv; |
163 | 163 | ||
164 | if (!p_dev) | 164 | if (!p_dev) |
165 | printk(KERN_NOTICE); | 165 | printk(KERN_NOTICE); |
166 | else | 166 | else |
167 | printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id); | 167 | printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id); |
168 | 168 | ||
169 | for (i = 0; i < ARRAY_SIZE(service_table); i++) | 169 | for (i = 0; i < ARRAY_SIZE(service_table); i++) |
170 | if (service_table[i].key == err->func) | 170 | if (service_table[i].key == err->func) |
171 | break; | 171 | break; |
172 | if (i < ARRAY_SIZE(service_table)) | 172 | if (i < ARRAY_SIZE(service_table)) |
173 | serv = service_table[i].msg; | 173 | serv = service_table[i].msg; |
174 | else | 174 | else |
175 | serv = "Unknown service number"; | 175 | serv = "Unknown service number"; |
176 | 176 | ||
177 | for (i = 0; i < ARRAY_SIZE(error_table); i++) | 177 | for (i = 0; i < ARRAY_SIZE(error_table); i++) |
178 | if (error_table[i].key == err->retcode) | 178 | if (error_table[i].key == err->retcode) |
179 | break; | 179 | break; |
180 | if (i < ARRAY_SIZE(error_table)) | 180 | if (i < ARRAY_SIZE(error_table)) |
181 | printk("%s: %s\n", serv, error_table[i].msg); | 181 | printk("%s: %s\n", serv, error_table[i].msg); |
182 | else | 182 | else |
183 | printk("%s: Unknown error code %#x\n", serv, err->retcode); | 183 | printk("%s: Unknown error code %#x\n", serv, err->retcode); |
184 | 184 | ||
185 | return CS_SUCCESS; | 185 | return CS_SUCCESS; |
186 | } /* report_error */ | 186 | } /* report_error */ |
187 | 187 | ||
188 | /* end of code which was in cs.c before */ | 188 | /* end of code which was in cs.c before */ |
189 | 189 | ||
190 | /*======================================================================*/ | 190 | /*======================================================================*/ |
191 | 191 | ||
192 | void cs_error(struct pcmcia_device *p_dev, int func, int ret) | 192 | void cs_error(struct pcmcia_device *p_dev, int func, int ret) |
193 | { | 193 | { |
194 | error_info_t err = { func, ret }; | 194 | error_info_t err = { func, ret }; |
195 | pcmcia_report_error(p_dev, &err); | 195 | pcmcia_report_error(p_dev, &err); |
196 | } | 196 | } |
197 | EXPORT_SYMBOL(cs_error); | 197 | EXPORT_SYMBOL(cs_error); |
198 | 198 | ||
199 | 199 | ||
200 | static void pcmcia_check_driver(struct pcmcia_driver *p_drv) | 200 | static void pcmcia_check_driver(struct pcmcia_driver *p_drv) |
201 | { | 201 | { |
202 | struct pcmcia_device_id *did = p_drv->id_table; | 202 | struct pcmcia_device_id *did = p_drv->id_table; |
203 | unsigned int i; | 203 | unsigned int i; |
204 | u32 hash; | 204 | u32 hash; |
205 | 205 | ||
206 | if (!p_drv->probe || !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 | ||
210 | while (did && did->match_flags) { | 210 | while (did && did->match_flags) { |
211 | for (i=0; i<4; i++) { | 211 | for (i=0; i<4; i++) { |
212 | if (!did->prod_id[i]) | 212 | if (!did->prod_id[i]) |
213 | continue; | 213 | continue; |
214 | 214 | ||
215 | hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i])); | 215 | hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i])); |
216 | if (hash == did->prod_id_hash[i]) | 216 | if (hash == did->prod_id_hash[i]) |
217 | continue; | 217 | continue; |
218 | 218 | ||
219 | printk(KERN_DEBUG "pcmcia: %s: invalid hash for " | 219 | printk(KERN_DEBUG "pcmcia: %s: invalid hash for " |
220 | "product string \"%s\": is 0x%x, should " | 220 | "product string \"%s\": is 0x%x, should " |
221 | "be 0x%x\n", p_drv->drv.name, did->prod_id[i], | 221 | "be 0x%x\n", p_drv->drv.name, did->prod_id[i], |
222 | did->prod_id_hash[i], hash); | 222 | did->prod_id_hash[i], hash); |
223 | printk(KERN_DEBUG "pcmcia: see " | 223 | printk(KERN_DEBUG "pcmcia: see " |
224 | "Documentation/pcmcia/devicetable.txt for " | 224 | "Documentation/pcmcia/devicetable.txt for " |
225 | "details\n"); | 225 | "details\n"); |
226 | } | 226 | } |
227 | did++; | 227 | did++; |
228 | } | 228 | } |
229 | 229 | ||
230 | return; | 230 | return; |
231 | } | 231 | } |
232 | 232 | ||
233 | 233 | ||
234 | /*======================================================================*/ | 234 | /*======================================================================*/ |
235 | 235 | ||
236 | 236 | ||
237 | struct pcmcia_dynid { | ||
238 | struct list_head node; | ||
239 | struct pcmcia_device_id id; | ||
240 | }; | ||
241 | |||
237 | /** | 242 | /** |
243 | * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices | ||
244 | * @driver: target device driver | ||
245 | * @buf: buffer for scanning device ID data | ||
246 | * @count: input size | ||
247 | * | ||
248 | * Adds a new dynamic PCMCIA device ID to this driver, | ||
249 | * and causes the driver to probe for all devices again. | ||
250 | */ | ||
251 | static ssize_t | ||
252 | pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count) | ||
253 | { | ||
254 | struct pcmcia_dynid *dynid; | ||
255 | struct pcmcia_driver *pdrv = to_pcmcia_drv(driver); | ||
256 | __u16 match_flags, manf_id, card_id; | ||
257 | __u8 func_id, function, device_no; | ||
258 | __u32 prod_id_hash[4] = {0, 0, 0, 0}; | ||
259 | int fields=0; | ||
260 | int retval = 0; | ||
261 | |||
262 | fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x", | ||
263 | &match_flags, &manf_id, &card_id, &func_id, &function, &device_no, | ||
264 | &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]); | ||
265 | if (fields < 6) | ||
266 | return -EINVAL; | ||
267 | |||
268 | dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL); | ||
269 | if (!dynid) | ||
270 | return -ENOMEM; | ||
271 | |||
272 | INIT_LIST_HEAD(&dynid->node); | ||
273 | dynid->id.match_flags = match_flags; | ||
274 | dynid->id.manf_id = manf_id; | ||
275 | dynid->id.card_id = card_id; | ||
276 | dynid->id.func_id = func_id; | ||
277 | dynid->id.function = function; | ||
278 | dynid->id.device_no = device_no; | ||
279 | memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4); | ||
280 | |||
281 | spin_lock(&pdrv->dynids.lock); | ||
282 | list_add_tail(&pdrv->dynids.list, &dynid->node); | ||
283 | spin_unlock(&pdrv->dynids.lock); | ||
284 | |||
285 | if (get_driver(&pdrv->drv)) { | ||
286 | retval = driver_attach(&pdrv->drv); | ||
287 | put_driver(&pdrv->drv); | ||
288 | } | ||
289 | |||
290 | if (retval) | ||
291 | return retval; | ||
292 | return count; | ||
293 | } | ||
294 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id); | ||
295 | |||
296 | static void | ||
297 | pcmcia_free_dynids(struct pcmcia_driver *drv) | ||
298 | { | ||
299 | struct pcmcia_dynid *dynid, *n; | ||
300 | |||
301 | spin_lock(&drv->dynids.lock); | ||
302 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { | ||
303 | list_del(&dynid->node); | ||
304 | kfree(dynid); | ||
305 | } | ||
306 | spin_unlock(&drv->dynids.lock); | ||
307 | } | ||
308 | |||
309 | static int | ||
310 | pcmcia_create_newid_file(struct pcmcia_driver *drv) | ||
311 | { | ||
312 | int error = 0; | ||
313 | if (drv->probe != NULL) | ||
314 | error = sysfs_create_file(&drv->drv.kobj, | ||
315 | &driver_attr_new_id.attr); | ||
316 | return error; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
238 | * pcmcia_register_driver - register a PCMCIA driver with the bus core | 321 | * pcmcia_register_driver - register a PCMCIA driver with the bus core |
239 | * | 322 | * |
240 | * Registers a PCMCIA driver with the PCMCIA bus core. | 323 | * Registers a PCMCIA driver with the PCMCIA bus core. |
241 | */ | 324 | */ |
242 | int pcmcia_register_driver(struct pcmcia_driver *driver) | 325 | int pcmcia_register_driver(struct pcmcia_driver *driver) |
243 | { | 326 | { |
327 | int error; | ||
328 | |||
244 | if (!driver) | 329 | if (!driver) |
245 | return -EINVAL; | 330 | return -EINVAL; |
246 | 331 | ||
247 | pcmcia_check_driver(driver); | 332 | pcmcia_check_driver(driver); |
248 | 333 | ||
249 | /* initialize common fields */ | 334 | /* initialize common fields */ |
250 | driver->drv.bus = &pcmcia_bus_type; | 335 | driver->drv.bus = &pcmcia_bus_type; |
251 | driver->drv.owner = driver->owner; | 336 | driver->drv.owner = driver->owner; |
337 | spin_lock_init(&driver->dynids.lock); | ||
338 | INIT_LIST_HEAD(&driver->dynids.list); | ||
252 | 339 | ||
253 | ds_dbg(3, "registering driver %s\n", driver->drv.name); | 340 | ds_dbg(3, "registering driver %s\n", driver->drv.name); |
254 | 341 | ||
255 | return driver_register(&driver->drv); | 342 | error = driver_register(&driver->drv); |
343 | if (error < 0) | ||
344 | return error; | ||
345 | |||
346 | error = pcmcia_create_newid_file(driver); | ||
347 | if (error) | ||
348 | driver_unregister(&driver->drv); | ||
349 | |||
350 | return error; | ||
256 | } | 351 | } |
257 | EXPORT_SYMBOL(pcmcia_register_driver); | 352 | EXPORT_SYMBOL(pcmcia_register_driver); |
258 | 353 | ||
259 | /** | 354 | /** |
260 | * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core | 355 | * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core |
261 | */ | 356 | */ |
262 | void pcmcia_unregister_driver(struct pcmcia_driver *driver) | 357 | void pcmcia_unregister_driver(struct pcmcia_driver *driver) |
263 | { | 358 | { |
264 | ds_dbg(3, "unregistering driver %s\n", driver->drv.name); | 359 | ds_dbg(3, "unregistering driver %s\n", driver->drv.name); |
265 | driver_unregister(&driver->drv); | 360 | driver_unregister(&driver->drv); |
361 | pcmcia_free_dynids(driver); | ||
266 | } | 362 | } |
267 | EXPORT_SYMBOL(pcmcia_unregister_driver); | 363 | EXPORT_SYMBOL(pcmcia_unregister_driver); |
268 | 364 | ||
269 | 365 | ||
270 | /* pcmcia_device handling */ | 366 | /* pcmcia_device handling */ |
271 | 367 | ||
272 | struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) | 368 | struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) |
273 | { | 369 | { |
274 | struct device *tmp_dev; | 370 | struct device *tmp_dev; |
275 | tmp_dev = get_device(&p_dev->dev); | 371 | tmp_dev = get_device(&p_dev->dev); |
276 | if (!tmp_dev) | 372 | if (!tmp_dev) |
277 | return NULL; | 373 | return NULL; |
278 | return to_pcmcia_dev(tmp_dev); | 374 | return to_pcmcia_dev(tmp_dev); |
279 | } | 375 | } |
280 | 376 | ||
281 | void pcmcia_put_dev(struct pcmcia_device *p_dev) | 377 | void pcmcia_put_dev(struct pcmcia_device *p_dev) |
282 | { | 378 | { |
283 | if (p_dev) | 379 | if (p_dev) |
284 | put_device(&p_dev->dev); | 380 | put_device(&p_dev->dev); |
285 | } | 381 | } |
286 | 382 | ||
287 | static void pcmcia_release_function(struct kref *ref) | 383 | static void pcmcia_release_function(struct kref *ref) |
288 | { | 384 | { |
289 | struct config_t *c = container_of(ref, struct config_t, ref); | 385 | struct config_t *c = container_of(ref, struct config_t, ref); |
290 | ds_dbg(1, "releasing config_t\n"); | 386 | ds_dbg(1, "releasing config_t\n"); |
291 | kfree(c); | 387 | kfree(c); |
292 | } | 388 | } |
293 | 389 | ||
294 | static void pcmcia_release_dev(struct device *dev) | 390 | static void pcmcia_release_dev(struct device *dev) |
295 | { | 391 | { |
296 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 392 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
297 | ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id); | 393 | ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id); |
298 | pcmcia_put_socket(p_dev->socket); | 394 | pcmcia_put_socket(p_dev->socket); |
299 | kfree(p_dev->devname); | 395 | kfree(p_dev->devname); |
300 | kref_put(&p_dev->function_config->ref, pcmcia_release_function); | 396 | kref_put(&p_dev->function_config->ref, pcmcia_release_function); |
301 | kfree(p_dev); | 397 | kfree(p_dev); |
302 | } | 398 | } |
303 | 399 | ||
304 | static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc) | 400 | static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc) |
305 | { | 401 | { |
306 | if (!s->pcmcia_state.device_add_pending) { | 402 | if (!s->pcmcia_state.device_add_pending) { |
307 | ds_dbg(1, "scheduling to add %s secondary" | 403 | ds_dbg(1, "scheduling to add %s secondary" |
308 | " device to %d\n", mfc ? "mfc" : "pfc", s->sock); | 404 | " device to %d\n", mfc ? "mfc" : "pfc", s->sock); |
309 | s->pcmcia_state.device_add_pending = 1; | 405 | s->pcmcia_state.device_add_pending = 1; |
310 | s->pcmcia_state.mfc_pfc = mfc; | 406 | s->pcmcia_state.mfc_pfc = mfc; |
311 | schedule_work(&s->device_add); | 407 | schedule_work(&s->device_add); |
312 | } | 408 | } |
313 | return; | 409 | return; |
314 | } | 410 | } |
315 | 411 | ||
316 | static int pcmcia_device_probe(struct device * dev) | 412 | static int pcmcia_device_probe(struct device * dev) |
317 | { | 413 | { |
318 | struct pcmcia_device *p_dev; | 414 | struct pcmcia_device *p_dev; |
319 | struct pcmcia_driver *p_drv; | 415 | struct pcmcia_driver *p_drv; |
320 | struct pcmcia_device_id *did; | 416 | struct pcmcia_device_id *did; |
321 | struct pcmcia_socket *s; | 417 | struct pcmcia_socket *s; |
322 | cistpl_config_t cis_config; | 418 | cistpl_config_t cis_config; |
323 | int ret = 0; | 419 | int ret = 0; |
324 | 420 | ||
325 | dev = get_device(dev); | 421 | dev = get_device(dev); |
326 | if (!dev) | 422 | if (!dev) |
327 | return -ENODEV; | 423 | return -ENODEV; |
328 | 424 | ||
329 | p_dev = to_pcmcia_dev(dev); | 425 | p_dev = to_pcmcia_dev(dev); |
330 | p_drv = to_pcmcia_drv(dev->driver); | 426 | p_drv = to_pcmcia_drv(dev->driver); |
331 | s = p_dev->socket; | 427 | s = p_dev->socket; |
332 | 428 | ||
333 | ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id, | 429 | ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id, |
334 | p_drv->drv.name); | 430 | p_drv->drv.name); |
335 | 431 | ||
336 | if ((!p_drv->probe) || (!p_dev->function_config) || | 432 | if ((!p_drv->probe) || (!p_dev->function_config) || |
337 | (!try_module_get(p_drv->owner))) { | 433 | (!try_module_get(p_drv->owner))) { |
338 | ret = -EINVAL; | 434 | ret = -EINVAL; |
339 | goto put_dev; | 435 | goto put_dev; |
340 | } | 436 | } |
341 | 437 | ||
342 | /* set up some more device information */ | 438 | /* set up some more device information */ |
343 | ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG, | 439 | ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG, |
344 | &cis_config); | 440 | &cis_config); |
345 | if (!ret) { | 441 | if (!ret) { |
346 | p_dev->conf.ConfigBase = cis_config.base; | 442 | p_dev->conf.ConfigBase = cis_config.base; |
347 | p_dev->conf.Present = cis_config.rmask[0]; | 443 | p_dev->conf.Present = cis_config.rmask[0]; |
348 | } else { | 444 | } else { |
349 | printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n"); | 445 | printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n"); |
350 | p_dev->conf.ConfigBase = 0; | 446 | p_dev->conf.ConfigBase = 0; |
351 | p_dev->conf.Present = 0; | 447 | p_dev->conf.Present = 0; |
352 | } | 448 | } |
353 | 449 | ||
354 | ret = p_drv->probe(p_dev); | 450 | ret = p_drv->probe(p_dev); |
355 | if (ret) { | 451 | if (ret) { |
356 | ds_dbg(1, "binding %s to %s failed with %d\n", | 452 | ds_dbg(1, "binding %s to %s failed with %d\n", |
357 | p_dev->dev.bus_id, p_drv->drv.name, ret); | 453 | p_dev->dev.bus_id, p_drv->drv.name, ret); |
358 | goto put_module; | 454 | goto put_module; |
359 | } | 455 | } |
360 | 456 | ||
361 | /* handle pseudo multifunction devices: | 457 | /* handle pseudo multifunction devices: |
362 | * there are at most two pseudo multifunction devices. | 458 | * there are at most two pseudo multifunction devices. |
363 | * if we're matching against the first, schedule a | 459 | * if we're matching against the first, schedule a |
364 | * call which will then check whether there are two | 460 | * call which will then check whether there are two |
365 | * pseudo devices, and if not, add the second one. | 461 | * pseudo devices, and if not, add the second one. |
366 | */ | 462 | */ |
367 | did = p_dev->dev.driver_data; | 463 | did = p_dev->dev.driver_data; |
368 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && | 464 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && |
369 | (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) | 465 | (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) |
370 | pcmcia_add_device_later(p_dev->socket, 0); | 466 | pcmcia_add_device_later(p_dev->socket, 0); |
371 | 467 | ||
372 | put_module: | 468 | put_module: |
373 | if (ret) | 469 | if (ret) |
374 | module_put(p_drv->owner); | 470 | module_put(p_drv->owner); |
375 | put_dev: | 471 | put_dev: |
376 | if (ret) | 472 | if (ret) |
377 | put_device(dev); | 473 | put_device(dev); |
378 | return (ret); | 474 | return (ret); |
379 | } | 475 | } |
380 | 476 | ||
381 | 477 | ||
382 | /* | 478 | /* |
383 | * Removes a PCMCIA card from the device tree and socket list. | 479 | * Removes a PCMCIA card from the device tree and socket list. |
384 | */ | 480 | */ |
385 | static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover) | 481 | static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover) |
386 | { | 482 | { |
387 | struct pcmcia_device *p_dev; | 483 | struct pcmcia_device *p_dev; |
388 | struct pcmcia_device *tmp; | 484 | struct pcmcia_device *tmp; |
389 | unsigned long flags; | 485 | unsigned long flags; |
390 | 486 | ||
391 | ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock, | 487 | ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock, |
392 | leftover ? leftover->devname : ""); | 488 | leftover ? leftover->devname : ""); |
393 | 489 | ||
394 | if (!leftover) | 490 | if (!leftover) |
395 | s->device_count = 0; | 491 | s->device_count = 0; |
396 | else | 492 | else |
397 | s->device_count = 1; | 493 | s->device_count = 1; |
398 | 494 | ||
399 | /* unregister all pcmcia_devices registered with this socket, except leftover */ | 495 | /* unregister all pcmcia_devices registered with this socket, except leftover */ |
400 | list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { | 496 | list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { |
401 | if (p_dev == leftover) | 497 | if (p_dev == leftover) |
402 | continue; | 498 | continue; |
403 | 499 | ||
404 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 500 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
405 | list_del(&p_dev->socket_device_list); | 501 | list_del(&p_dev->socket_device_list); |
406 | p_dev->_removed=1; | 502 | p_dev->_removed=1; |
407 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 503 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
408 | 504 | ||
409 | ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id); | 505 | ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id); |
410 | device_unregister(&p_dev->dev); | 506 | device_unregister(&p_dev->dev); |
411 | } | 507 | } |
412 | 508 | ||
413 | return; | 509 | return; |
414 | } | 510 | } |
415 | 511 | ||
416 | static int pcmcia_device_remove(struct device * dev) | 512 | static int pcmcia_device_remove(struct device * dev) |
417 | { | 513 | { |
418 | struct pcmcia_device *p_dev; | 514 | struct pcmcia_device *p_dev; |
419 | struct pcmcia_driver *p_drv; | 515 | struct pcmcia_driver *p_drv; |
420 | struct pcmcia_device_id *did; | 516 | struct pcmcia_device_id *did; |
421 | int i; | 517 | int i; |
422 | 518 | ||
423 | p_dev = to_pcmcia_dev(dev); | 519 | p_dev = to_pcmcia_dev(dev); |
424 | p_drv = to_pcmcia_drv(dev->driver); | 520 | p_drv = to_pcmcia_drv(dev->driver); |
425 | 521 | ||
426 | ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id); | 522 | ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id); |
427 | 523 | ||
428 | /* If we're removing the primary module driving a | 524 | /* If we're removing the primary module driving a |
429 | * pseudo multi-function card, we need to unbind | 525 | * pseudo multi-function card, we need to unbind |
430 | * all devices | 526 | * all devices |
431 | */ | 527 | */ |
432 | did = p_dev->dev.driver_data; | 528 | did = p_dev->dev.driver_data; |
433 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && | 529 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && |
434 | (p_dev->socket->device_count != 0) && | 530 | (p_dev->socket->device_count != 0) && |
435 | (p_dev->device_no == 0)) | 531 | (p_dev->device_no == 0)) |
436 | pcmcia_card_remove(p_dev->socket, p_dev); | 532 | pcmcia_card_remove(p_dev->socket, p_dev); |
437 | 533 | ||
438 | /* detach the "instance" */ | 534 | /* detach the "instance" */ |
439 | if (!p_drv) | 535 | if (!p_drv) |
440 | return 0; | 536 | return 0; |
441 | 537 | ||
442 | if (p_drv->remove) | 538 | if (p_drv->remove) |
443 | p_drv->remove(p_dev); | 539 | p_drv->remove(p_dev); |
444 | 540 | ||
445 | p_dev->dev_node = NULL; | 541 | p_dev->dev_node = NULL; |
446 | 542 | ||
447 | /* check for proper unloading */ | 543 | /* check for proper unloading */ |
448 | if (p_dev->_irq || p_dev->_io || p_dev->_locked) | 544 | if (p_dev->_irq || p_dev->_io || p_dev->_locked) |
449 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", | 545 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", |
450 | p_drv->drv.name); | 546 | p_drv->drv.name); |
451 | 547 | ||
452 | for (i = 0; i < MAX_WIN; i++) | 548 | for (i = 0; i < MAX_WIN; i++) |
453 | if (p_dev->_win & CLIENT_WIN_REQ(i)) | 549 | if (p_dev->_win & CLIENT_WIN_REQ(i)) |
454 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", | 550 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", |
455 | p_drv->drv.name); | 551 | p_drv->drv.name); |
456 | 552 | ||
457 | /* references from pcmcia_probe_device */ | 553 | /* references from pcmcia_probe_device */ |
458 | pcmcia_put_dev(p_dev); | 554 | pcmcia_put_dev(p_dev); |
459 | module_put(p_drv->owner); | 555 | module_put(p_drv->owner); |
460 | 556 | ||
461 | return 0; | 557 | return 0; |
462 | } | 558 | } |
463 | 559 | ||
464 | 560 | ||
465 | /* | 561 | /* |
466 | * pcmcia_device_query -- determine information about a pcmcia device | 562 | * pcmcia_device_query -- determine information about a pcmcia device |
467 | */ | 563 | */ |
468 | static int pcmcia_device_query(struct pcmcia_device *p_dev) | 564 | static int pcmcia_device_query(struct pcmcia_device *p_dev) |
469 | { | 565 | { |
470 | cistpl_manfid_t manf_id; | 566 | cistpl_manfid_t manf_id; |
471 | cistpl_funcid_t func_id; | 567 | cistpl_funcid_t func_id; |
472 | cistpl_vers_1_t *vers1; | 568 | cistpl_vers_1_t *vers1; |
473 | unsigned int i; | 569 | unsigned int i; |
474 | 570 | ||
475 | vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL); | 571 | vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL); |
476 | if (!vers1) | 572 | if (!vers1) |
477 | return -ENOMEM; | 573 | return -ENOMEM; |
478 | 574 | ||
479 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | 575 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, |
480 | CISTPL_MANFID, &manf_id)) { | 576 | CISTPL_MANFID, &manf_id)) { |
481 | p_dev->manf_id = manf_id.manf; | 577 | p_dev->manf_id = manf_id.manf; |
482 | p_dev->card_id = manf_id.card; | 578 | p_dev->card_id = manf_id.card; |
483 | p_dev->has_manf_id = 1; | 579 | p_dev->has_manf_id = 1; |
484 | p_dev->has_card_id = 1; | 580 | p_dev->has_card_id = 1; |
485 | } | 581 | } |
486 | 582 | ||
487 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | 583 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, |
488 | CISTPL_FUNCID, &func_id)) { | 584 | CISTPL_FUNCID, &func_id)) { |
489 | p_dev->func_id = func_id.func; | 585 | p_dev->func_id = func_id.func; |
490 | p_dev->has_func_id = 1; | 586 | p_dev->has_func_id = 1; |
491 | } else { | 587 | } else { |
492 | /* rule of thumb: cards with no FUNCID, but with | 588 | /* rule of thumb: cards with no FUNCID, but with |
493 | * common memory device geometry information, are | 589 | * common memory device geometry information, are |
494 | * probably memory cards (from pcmcia-cs) */ | 590 | * probably memory cards (from pcmcia-cs) */ |
495 | cistpl_device_geo_t *devgeo; | 591 | cistpl_device_geo_t *devgeo; |
496 | 592 | ||
497 | devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL); | 593 | devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL); |
498 | if (!devgeo) { | 594 | if (!devgeo) { |
499 | kfree(vers1); | 595 | kfree(vers1); |
500 | return -ENOMEM; | 596 | return -ENOMEM; |
501 | } | 597 | } |
502 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | 598 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, |
503 | CISTPL_DEVICE_GEO, devgeo)) { | 599 | CISTPL_DEVICE_GEO, devgeo)) { |
504 | ds_dbg(0, "mem device geometry probably means " | 600 | ds_dbg(0, "mem device geometry probably means " |
505 | "FUNCID_MEMORY\n"); | 601 | "FUNCID_MEMORY\n"); |
506 | p_dev->func_id = CISTPL_FUNCID_MEMORY; | 602 | p_dev->func_id = CISTPL_FUNCID_MEMORY; |
507 | p_dev->has_func_id = 1; | 603 | p_dev->has_func_id = 1; |
508 | } | 604 | } |
509 | kfree(devgeo); | 605 | kfree(devgeo); |
510 | } | 606 | } |
511 | 607 | ||
512 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, | 608 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, |
513 | vers1)) { | 609 | vers1)) { |
514 | for (i=0; i < vers1->ns; i++) { | 610 | for (i=0; i < vers1->ns; i++) { |
515 | char *tmp; | 611 | char *tmp; |
516 | unsigned int length; | 612 | unsigned int length; |
517 | 613 | ||
518 | tmp = vers1->str + vers1->ofs[i]; | 614 | tmp = vers1->str + vers1->ofs[i]; |
519 | 615 | ||
520 | length = strlen(tmp) + 1; | 616 | length = strlen(tmp) + 1; |
521 | if ((length < 2) || (length > 255)) | 617 | if ((length < 2) || (length > 255)) |
522 | continue; | 618 | continue; |
523 | 619 | ||
524 | p_dev->prod_id[i] = kmalloc(sizeof(char) * length, | 620 | p_dev->prod_id[i] = kmalloc(sizeof(char) * length, |
525 | GFP_KERNEL); | 621 | GFP_KERNEL); |
526 | if (!p_dev->prod_id[i]) | 622 | if (!p_dev->prod_id[i]) |
527 | continue; | 623 | continue; |
528 | 624 | ||
529 | p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], | 625 | p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], |
530 | tmp, length); | 626 | tmp, length); |
531 | } | 627 | } |
532 | } | 628 | } |
533 | 629 | ||
534 | kfree(vers1); | 630 | kfree(vers1); |
535 | return 0; | 631 | return 0; |
536 | } | 632 | } |
537 | 633 | ||
538 | 634 | ||
539 | /* device_add_lock is needed to avoid double registration by cardmgr and kernel. | 635 | /* device_add_lock is needed to avoid double registration by cardmgr and kernel. |
540 | * Serializes pcmcia_device_add; will most likely be removed in future. | 636 | * Serializes pcmcia_device_add; will most likely be removed in future. |
541 | * | 637 | * |
542 | * While it has the caveat that adding new PCMCIA devices inside(!) device_register() | 638 | * While it has the caveat that adding new PCMCIA devices inside(!) device_register() |
543 | * won't work, this doesn't matter much at the moment: the driver core doesn't | 639 | * won't work, this doesn't matter much at the moment: the driver core doesn't |
544 | * support it either. | 640 | * support it either. |
545 | */ | 641 | */ |
546 | static DEFINE_MUTEX(device_add_lock); | 642 | static DEFINE_MUTEX(device_add_lock); |
547 | 643 | ||
548 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) | 644 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) |
549 | { | 645 | { |
550 | struct pcmcia_device *p_dev, *tmp_dev; | 646 | struct pcmcia_device *p_dev, *tmp_dev; |
551 | unsigned long flags; | 647 | unsigned long flags; |
552 | int bus_id_len; | 648 | int bus_id_len; |
553 | 649 | ||
554 | s = pcmcia_get_socket(s); | 650 | s = pcmcia_get_socket(s); |
555 | if (!s) | 651 | if (!s) |
556 | return NULL; | 652 | return NULL; |
557 | 653 | ||
558 | mutex_lock(&device_add_lock); | 654 | mutex_lock(&device_add_lock); |
559 | 655 | ||
560 | ds_dbg(3, "adding device to %d, function %d\n", s->sock, function); | 656 | ds_dbg(3, "adding device to %d, function %d\n", s->sock, function); |
561 | 657 | ||
562 | /* max of 4 devices per card */ | 658 | /* max of 4 devices per card */ |
563 | if (s->device_count == 4) | 659 | if (s->device_count == 4) |
564 | goto err_put; | 660 | goto err_put; |
565 | 661 | ||
566 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | 662 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); |
567 | if (!p_dev) | 663 | if (!p_dev) |
568 | goto err_put; | 664 | goto err_put; |
569 | 665 | ||
570 | p_dev->socket = s; | 666 | p_dev->socket = s; |
571 | p_dev->device_no = (s->device_count++); | 667 | p_dev->device_no = (s->device_count++); |
572 | p_dev->func = function; | 668 | p_dev->func = function; |
573 | 669 | ||
574 | p_dev->dev.bus = &pcmcia_bus_type; | 670 | p_dev->dev.bus = &pcmcia_bus_type; |
575 | p_dev->dev.parent = s->dev.parent; | 671 | p_dev->dev.parent = s->dev.parent; |
576 | p_dev->dev.release = pcmcia_release_dev; | 672 | p_dev->dev.release = pcmcia_release_dev; |
577 | bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); | 673 | bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); |
578 | 674 | ||
579 | p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); | 675 | p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); |
580 | if (!p_dev->devname) | 676 | if (!p_dev->devname) |
581 | goto err_free; | 677 | goto err_free; |
582 | sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); | 678 | sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); |
583 | ds_dbg(3, "devname is %s\n", p_dev->devname); | 679 | ds_dbg(3, "devname is %s\n", p_dev->devname); |
584 | 680 | ||
585 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 681 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
586 | 682 | ||
587 | /* | 683 | /* |
588 | * p_dev->function_config must be the same for all card functions. | 684 | * p_dev->function_config must be the same for all card functions. |
589 | * Note that this is serialized by the device_add_lock, so that | 685 | * Note that this is serialized by the device_add_lock, so that |
590 | * only one such struct will be created. | 686 | * only one such struct will be created. |
591 | */ | 687 | */ |
592 | list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) | 688 | list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) |
593 | if (p_dev->func == tmp_dev->func) { | 689 | if (p_dev->func == tmp_dev->func) { |
594 | p_dev->function_config = tmp_dev->function_config; | 690 | p_dev->function_config = tmp_dev->function_config; |
595 | kref_get(&p_dev->function_config->ref); | 691 | kref_get(&p_dev->function_config->ref); |
596 | } | 692 | } |
597 | 693 | ||
598 | /* Add to the list in pcmcia_bus_socket */ | 694 | /* Add to the list in pcmcia_bus_socket */ |
599 | list_add(&p_dev->socket_device_list, &s->devices_list); | 695 | list_add(&p_dev->socket_device_list, &s->devices_list); |
600 | 696 | ||
601 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 697 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
602 | 698 | ||
603 | if (!p_dev->function_config) { | 699 | if (!p_dev->function_config) { |
604 | ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id); | 700 | ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id); |
605 | p_dev->function_config = kzalloc(sizeof(struct config_t), | 701 | p_dev->function_config = kzalloc(sizeof(struct config_t), |
606 | GFP_KERNEL); | 702 | GFP_KERNEL); |
607 | if (!p_dev->function_config) | 703 | if (!p_dev->function_config) |
608 | goto err_unreg; | 704 | goto err_unreg; |
609 | kref_init(&p_dev->function_config->ref); | 705 | kref_init(&p_dev->function_config->ref); |
610 | } | 706 | } |
611 | 707 | ||
612 | printk(KERN_NOTICE "pcmcia: registering new device %s\n", | 708 | printk(KERN_NOTICE "pcmcia: registering new device %s\n", |
613 | p_dev->devname); | 709 | p_dev->devname); |
614 | 710 | ||
615 | pcmcia_device_query(p_dev); | 711 | pcmcia_device_query(p_dev); |
616 | 712 | ||
617 | if (device_register(&p_dev->dev)) | 713 | if (device_register(&p_dev->dev)) |
618 | goto err_unreg; | 714 | goto err_unreg; |
619 | 715 | ||
620 | mutex_unlock(&device_add_lock); | 716 | mutex_unlock(&device_add_lock); |
621 | 717 | ||
622 | return p_dev; | 718 | return p_dev; |
623 | 719 | ||
624 | err_unreg: | 720 | err_unreg: |
625 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 721 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
626 | list_del(&p_dev->socket_device_list); | 722 | list_del(&p_dev->socket_device_list); |
627 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 723 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
628 | 724 | ||
629 | err_free: | 725 | err_free: |
630 | kfree(p_dev->devname); | 726 | kfree(p_dev->devname); |
631 | kfree(p_dev); | 727 | kfree(p_dev); |
632 | s->device_count--; | 728 | s->device_count--; |
633 | err_put: | 729 | err_put: |
634 | mutex_unlock(&device_add_lock); | 730 | mutex_unlock(&device_add_lock); |
635 | pcmcia_put_socket(s); | 731 | pcmcia_put_socket(s); |
636 | 732 | ||
637 | return NULL; | 733 | return NULL; |
638 | } | 734 | } |
639 | 735 | ||
640 | 736 | ||
641 | static int pcmcia_card_add(struct pcmcia_socket *s) | 737 | static int pcmcia_card_add(struct pcmcia_socket *s) |
642 | { | 738 | { |
643 | cisinfo_t cisinfo; | 739 | cisinfo_t cisinfo; |
644 | cistpl_longlink_mfc_t mfc; | 740 | cistpl_longlink_mfc_t mfc; |
645 | unsigned int no_funcs, i; | 741 | unsigned int no_funcs, i; |
646 | int ret = 0; | 742 | int ret = 0; |
647 | 743 | ||
648 | if (!(s->resource_setup_done)) { | 744 | if (!(s->resource_setup_done)) { |
649 | ds_dbg(3, "no resources available, delaying card_add\n"); | 745 | ds_dbg(3, "no resources available, delaying card_add\n"); |
650 | return -EAGAIN; /* try again, but later... */ | 746 | return -EAGAIN; /* try again, but later... */ |
651 | } | 747 | } |
652 | 748 | ||
653 | if (pcmcia_validate_mem(s)) { | 749 | if (pcmcia_validate_mem(s)) { |
654 | ds_dbg(3, "validating mem resources failed, " | 750 | ds_dbg(3, "validating mem resources failed, " |
655 | "delaying card_add\n"); | 751 | "delaying card_add\n"); |
656 | return -EAGAIN; /* try again, but later... */ | 752 | return -EAGAIN; /* try again, but later... */ |
657 | } | 753 | } |
658 | 754 | ||
659 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); | 755 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); |
660 | if (ret || !cisinfo.Chains) { | 756 | if (ret || !cisinfo.Chains) { |
661 | ds_dbg(0, "invalid CIS or invalid resources\n"); | 757 | ds_dbg(0, "invalid CIS or invalid resources\n"); |
662 | return -ENODEV; | 758 | return -ENODEV; |
663 | } | 759 | } |
664 | 760 | ||
665 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) | 761 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) |
666 | no_funcs = mfc.nfn; | 762 | no_funcs = mfc.nfn; |
667 | else | 763 | else |
668 | no_funcs = 1; | 764 | no_funcs = 1; |
669 | s->functions = no_funcs; | 765 | s->functions = no_funcs; |
670 | 766 | ||
671 | for (i=0; i < no_funcs; i++) | 767 | for (i=0; i < no_funcs; i++) |
672 | pcmcia_device_add(s, i); | 768 | pcmcia_device_add(s, i); |
673 | 769 | ||
674 | return (ret); | 770 | return (ret); |
675 | } | 771 | } |
676 | 772 | ||
677 | 773 | ||
678 | static void pcmcia_delayed_add_device(struct work_struct *work) | 774 | static void pcmcia_delayed_add_device(struct work_struct *work) |
679 | { | 775 | { |
680 | struct pcmcia_socket *s = | 776 | struct pcmcia_socket *s = |
681 | container_of(work, struct pcmcia_socket, device_add); | 777 | container_of(work, struct pcmcia_socket, device_add); |
682 | ds_dbg(1, "adding additional device to %d\n", s->sock); | 778 | ds_dbg(1, "adding additional device to %d\n", s->sock); |
683 | pcmcia_device_add(s, s->pcmcia_state.mfc_pfc); | 779 | pcmcia_device_add(s, s->pcmcia_state.mfc_pfc); |
684 | s->pcmcia_state.device_add_pending = 0; | 780 | s->pcmcia_state.device_add_pending = 0; |
685 | s->pcmcia_state.mfc_pfc = 0; | 781 | s->pcmcia_state.mfc_pfc = 0; |
686 | } | 782 | } |
687 | 783 | ||
688 | static int pcmcia_requery(struct device *dev, void * _data) | 784 | static int pcmcia_requery(struct device *dev, void * _data) |
689 | { | 785 | { |
690 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 786 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
691 | if (!p_dev->dev.driver) { | 787 | if (!p_dev->dev.driver) { |
692 | ds_dbg(1, "update device information for %s\n", | 788 | ds_dbg(1, "update device information for %s\n", |
693 | p_dev->dev.bus_id); | 789 | p_dev->dev.bus_id); |
694 | pcmcia_device_query(p_dev); | 790 | pcmcia_device_query(p_dev); |
695 | } | 791 | } |
696 | 792 | ||
697 | return 0; | 793 | return 0; |
698 | } | 794 | } |
699 | 795 | ||
700 | static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis) | 796 | static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis) |
701 | { | 797 | { |
702 | int no_devices = 0; | 798 | int no_devices = 0; |
703 | int ret = 0; | 799 | int ret = 0; |
704 | unsigned long flags; | 800 | unsigned long flags; |
705 | 801 | ||
706 | /* must be called with skt_mutex held */ | 802 | /* must be called with skt_mutex held */ |
707 | ds_dbg(0, "re-scanning socket %d\n", skt->sock); | 803 | ds_dbg(0, "re-scanning socket %d\n", skt->sock); |
708 | 804 | ||
709 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 805 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
710 | if (list_empty(&skt->devices_list)) | 806 | if (list_empty(&skt->devices_list)) |
711 | no_devices = 1; | 807 | no_devices = 1; |
712 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 808 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
713 | 809 | ||
714 | /* If this is because of a CIS override, start over */ | 810 | /* If this is because of a CIS override, start over */ |
715 | if (new_cis && !no_devices) | 811 | if (new_cis && !no_devices) |
716 | pcmcia_card_remove(skt, NULL); | 812 | pcmcia_card_remove(skt, NULL); |
717 | 813 | ||
718 | /* if no devices were added for this socket yet because of | 814 | /* if no devices were added for this socket yet because of |
719 | * missing resource information or other trouble, we need to | 815 | * missing resource information or other trouble, we need to |
720 | * do this now. */ | 816 | * do this now. */ |
721 | if (no_devices || new_cis) { | 817 | if (no_devices || new_cis) { |
722 | ret = pcmcia_card_add(skt); | 818 | ret = pcmcia_card_add(skt); |
723 | if (ret) | 819 | if (ret) |
724 | return; | 820 | return; |
725 | } | 821 | } |
726 | 822 | ||
727 | /* some device information might have changed because of a CIS | 823 | /* some device information might have changed because of a CIS |
728 | * update or because we can finally read it correctly... so | 824 | * update or because we can finally read it correctly... so |
729 | * determine it again, overwriting old values if necessary. */ | 825 | * determine it again, overwriting old values if necessary. */ |
730 | bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery); | 826 | bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery); |
731 | 827 | ||
732 | /* we re-scan all devices, not just the ones connected to this | 828 | /* we re-scan all devices, not just the ones connected to this |
733 | * socket. This does not matter, though. */ | 829 | * socket. This does not matter, though. */ |
734 | ret = bus_rescan_devices(&pcmcia_bus_type); | 830 | ret = bus_rescan_devices(&pcmcia_bus_type); |
735 | if (ret) | 831 | if (ret) |
736 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); | 832 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); |
737 | } | 833 | } |
738 | 834 | ||
739 | #ifdef CONFIG_PCMCIA_LOAD_CIS | 835 | #ifdef CONFIG_PCMCIA_LOAD_CIS |
740 | 836 | ||
741 | /** | 837 | /** |
742 | * pcmcia_load_firmware - load CIS from userspace if device-provided is broken | 838 | * pcmcia_load_firmware - load CIS from userspace if device-provided is broken |
743 | * @dev - the pcmcia device which needs a CIS override | 839 | * @dev - the pcmcia device which needs a CIS override |
744 | * @filename - requested filename in /lib/firmware/ | 840 | * @filename - requested filename in /lib/firmware/ |
745 | * | 841 | * |
746 | * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if | 842 | * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if |
747 | * the one provided by the card is broken. The firmware files reside in | 843 | * the one provided by the card is broken. The firmware files reside in |
748 | * /lib/firmware/ in userspace. | 844 | * /lib/firmware/ in userspace. |
749 | */ | 845 | */ |
750 | static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | 846 | static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) |
751 | { | 847 | { |
752 | struct pcmcia_socket *s = dev->socket; | 848 | struct pcmcia_socket *s = dev->socket; |
753 | const struct firmware *fw; | 849 | const struct firmware *fw; |
754 | char path[20]; | 850 | char path[20]; |
755 | int ret = -ENOMEM; | 851 | int ret = -ENOMEM; |
756 | int no_funcs; | 852 | int no_funcs; |
757 | int old_funcs; | 853 | int old_funcs; |
758 | cisdump_t *cis; | 854 | cisdump_t *cis; |
759 | cistpl_longlink_mfc_t mfc; | 855 | cistpl_longlink_mfc_t mfc; |
760 | 856 | ||
761 | if (!filename) | 857 | if (!filename) |
762 | return -EINVAL; | 858 | return -EINVAL; |
763 | 859 | ||
764 | ds_dbg(1, "trying to load CIS file %s\n", filename); | 860 | ds_dbg(1, "trying to load CIS file %s\n", filename); |
765 | 861 | ||
766 | if (strlen(filename) > 14) { | 862 | if (strlen(filename) > 14) { |
767 | printk(KERN_WARNING "pcmcia: CIS filename is too long\n"); | 863 | printk(KERN_WARNING "pcmcia: CIS filename is too long\n"); |
768 | return -EINVAL; | 864 | return -EINVAL; |
769 | } | 865 | } |
770 | 866 | ||
771 | snprintf(path, 20, "%s", filename); | 867 | snprintf(path, 20, "%s", filename); |
772 | 868 | ||
773 | if (request_firmware(&fw, path, &dev->dev) == 0) { | 869 | if (request_firmware(&fw, path, &dev->dev) == 0) { |
774 | if (fw->size >= CISTPL_MAX_CIS_SIZE) { | 870 | if (fw->size >= CISTPL_MAX_CIS_SIZE) { |
775 | ret = -EINVAL; | 871 | ret = -EINVAL; |
776 | printk(KERN_ERR "pcmcia: CIS override is too big\n"); | 872 | printk(KERN_ERR "pcmcia: CIS override is too big\n"); |
777 | goto release; | 873 | goto release; |
778 | } | 874 | } |
779 | 875 | ||
780 | cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); | 876 | cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); |
781 | if (!cis) { | 877 | if (!cis) { |
782 | ret = -ENOMEM; | 878 | ret = -ENOMEM; |
783 | goto release; | 879 | goto release; |
784 | } | 880 | } |
785 | 881 | ||
786 | cis->Length = fw->size + 1; | 882 | cis->Length = fw->size + 1; |
787 | memcpy(cis->Data, fw->data, fw->size); | 883 | memcpy(cis->Data, fw->data, fw->size); |
788 | 884 | ||
789 | if (!pcmcia_replace_cis(s, cis)) | 885 | if (!pcmcia_replace_cis(s, cis)) |
790 | ret = 0; | 886 | ret = 0; |
791 | else { | 887 | else { |
792 | printk(KERN_ERR "pcmcia: CIS override failed\n"); | 888 | printk(KERN_ERR "pcmcia: CIS override failed\n"); |
793 | goto release; | 889 | goto release; |
794 | } | 890 | } |
795 | 891 | ||
796 | 892 | ||
797 | /* update information */ | 893 | /* update information */ |
798 | pcmcia_device_query(dev); | 894 | pcmcia_device_query(dev); |
799 | 895 | ||
800 | /* does this cis override add or remove functions? */ | 896 | /* does this cis override add or remove functions? */ |
801 | old_funcs = s->functions; | 897 | old_funcs = s->functions; |
802 | 898 | ||
803 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) | 899 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) |
804 | no_funcs = mfc.nfn; | 900 | no_funcs = mfc.nfn; |
805 | else | 901 | else |
806 | no_funcs = 1; | 902 | no_funcs = 1; |
807 | s->functions = no_funcs; | 903 | s->functions = no_funcs; |
808 | 904 | ||
809 | if (old_funcs > no_funcs) | 905 | if (old_funcs > no_funcs) |
810 | pcmcia_card_remove(s, dev); | 906 | pcmcia_card_remove(s, dev); |
811 | else if (no_funcs > old_funcs) | 907 | else if (no_funcs > old_funcs) |
812 | pcmcia_add_device_later(s, 1); | 908 | pcmcia_add_device_later(s, 1); |
813 | } | 909 | } |
814 | release: | 910 | release: |
815 | release_firmware(fw); | 911 | release_firmware(fw); |
816 | 912 | ||
817 | return (ret); | 913 | return (ret); |
818 | } | 914 | } |
819 | 915 | ||
820 | #else /* !CONFIG_PCMCIA_LOAD_CIS */ | 916 | #else /* !CONFIG_PCMCIA_LOAD_CIS */ |
821 | 917 | ||
822 | static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | 918 | static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) |
823 | { | 919 | { |
824 | return -ENODEV; | 920 | return -ENODEV; |
825 | } | 921 | } |
826 | 922 | ||
827 | #endif | 923 | #endif |
828 | 924 | ||
829 | 925 | ||
830 | static inline int pcmcia_devmatch(struct pcmcia_device *dev, | 926 | static inline int pcmcia_devmatch(struct pcmcia_device *dev, |
831 | struct pcmcia_device_id *did) | 927 | struct pcmcia_device_id *did) |
832 | { | 928 | { |
833 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) { | 929 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) { |
834 | if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id)) | 930 | if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id)) |
835 | return 0; | 931 | return 0; |
836 | } | 932 | } |
837 | 933 | ||
838 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) { | 934 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) { |
839 | if ((!dev->has_card_id) || (dev->card_id != did->card_id)) | 935 | if ((!dev->has_card_id) || (dev->card_id != did->card_id)) |
840 | return 0; | 936 | return 0; |
841 | } | 937 | } |
842 | 938 | ||
843 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) { | 939 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) { |
844 | if (dev->func != did->function) | 940 | if (dev->func != did->function) |
845 | return 0; | 941 | return 0; |
846 | } | 942 | } |
847 | 943 | ||
848 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) { | 944 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) { |
849 | if (!dev->prod_id[0]) | 945 | if (!dev->prod_id[0]) |
850 | return 0; | 946 | return 0; |
851 | if (strcmp(did->prod_id[0], dev->prod_id[0])) | 947 | if (strcmp(did->prod_id[0], dev->prod_id[0])) |
852 | return 0; | 948 | return 0; |
853 | } | 949 | } |
854 | 950 | ||
855 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) { | 951 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) { |
856 | if (!dev->prod_id[1]) | 952 | if (!dev->prod_id[1]) |
857 | return 0; | 953 | return 0; |
858 | if (strcmp(did->prod_id[1], dev->prod_id[1])) | 954 | if (strcmp(did->prod_id[1], dev->prod_id[1])) |
859 | return 0; | 955 | return 0; |
860 | } | 956 | } |
861 | 957 | ||
862 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) { | 958 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) { |
863 | if (!dev->prod_id[2]) | 959 | if (!dev->prod_id[2]) |
864 | return 0; | 960 | return 0; |
865 | if (strcmp(did->prod_id[2], dev->prod_id[2])) | 961 | if (strcmp(did->prod_id[2], dev->prod_id[2])) |
866 | return 0; | 962 | return 0; |
867 | } | 963 | } |
868 | 964 | ||
869 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) { | 965 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) { |
870 | if (!dev->prod_id[3]) | 966 | if (!dev->prod_id[3]) |
871 | return 0; | 967 | return 0; |
872 | if (strcmp(did->prod_id[3], dev->prod_id[3])) | 968 | if (strcmp(did->prod_id[3], dev->prod_id[3])) |
873 | return 0; | 969 | return 0; |
874 | } | 970 | } |
875 | 971 | ||
876 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { | 972 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { |
877 | if (dev->device_no != did->device_no) | 973 | if (dev->device_no != did->device_no) |
878 | return 0; | 974 | return 0; |
879 | } | 975 | } |
880 | 976 | ||
881 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { | 977 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { |
882 | if ((!dev->has_func_id) || (dev->func_id != did->func_id)) | 978 | if ((!dev->has_func_id) || (dev->func_id != did->func_id)) |
883 | return 0; | 979 | return 0; |
884 | 980 | ||
885 | /* if this is a pseudo-multi-function device, | 981 | /* if this is a pseudo-multi-function device, |
886 | * we need explicit matches */ | 982 | * we need explicit matches */ |
887 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) | 983 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) |
888 | return 0; | 984 | return 0; |
889 | if (dev->device_no) | 985 | if (dev->device_no) |
890 | return 0; | 986 | return 0; |
891 | 987 | ||
892 | /* also, FUNC_ID matching needs to be activated by userspace | 988 | /* also, FUNC_ID matching needs to be activated by userspace |
893 | * after it has re-checked that there is no possible module | 989 | * after it has re-checked that there is no possible module |
894 | * with a prod_id/manf_id/card_id match. | 990 | * with a prod_id/manf_id/card_id match. |
895 | */ | 991 | */ |
896 | ds_dbg(0, "skipping FUNC_ID match for %s until userspace " | 992 | ds_dbg(0, "skipping FUNC_ID match for %s until userspace " |
897 | "interaction\n", dev->dev.bus_id); | 993 | "interaction\n", dev->dev.bus_id); |
898 | if (!dev->allow_func_id_match) | 994 | if (!dev->allow_func_id_match) |
899 | return 0; | 995 | return 0; |
900 | } | 996 | } |
901 | 997 | ||
902 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { | 998 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { |
903 | ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id); | 999 | ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id); |
904 | if (!dev->socket->fake_cis) | 1000 | if (!dev->socket->fake_cis) |
905 | pcmcia_load_firmware(dev, did->cisfile); | 1001 | pcmcia_load_firmware(dev, did->cisfile); |
906 | 1002 | ||
907 | if (!dev->socket->fake_cis) | 1003 | if (!dev->socket->fake_cis) |
908 | return 0; | 1004 | return 0; |
909 | } | 1005 | } |
910 | 1006 | ||
911 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { | 1007 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { |
912 | int i; | 1008 | int i; |
913 | for (i=0; i<4; i++) | 1009 | for (i=0; i<4; i++) |
914 | if (dev->prod_id[i]) | 1010 | if (dev->prod_id[i]) |
915 | return 0; | 1011 | return 0; |
916 | if (dev->has_manf_id || dev->has_card_id || dev->has_func_id) | 1012 | if (dev->has_manf_id || dev->has_card_id || dev->has_func_id) |
917 | return 0; | 1013 | return 0; |
918 | } | 1014 | } |
919 | 1015 | ||
920 | dev->dev.driver_data = (void *) did; | 1016 | dev->dev.driver_data = (void *) did; |
921 | 1017 | ||
922 | return 1; | 1018 | return 1; |
923 | } | 1019 | } |
924 | 1020 | ||
925 | 1021 | ||
926 | static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { | 1022 | static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { |
927 | struct pcmcia_device * p_dev = to_pcmcia_dev(dev); | 1023 | struct pcmcia_device * p_dev = to_pcmcia_dev(dev); |
928 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); | 1024 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); |
929 | struct pcmcia_device_id *did = p_drv->id_table; | 1025 | struct pcmcia_device_id *did = p_drv->id_table; |
1026 | struct pcmcia_dynid *dynid; | ||
1027 | |||
1028 | /* match dynamic devices first */ | ||
1029 | spin_lock(&p_drv->dynids.lock); | ||
1030 | list_for_each_entry(dynid, &p_drv->dynids.list, node) { | ||
1031 | ds_dbg(3, "trying to match %s to %s\n", dev->bus_id, | ||
1032 | drv->name); | ||
1033 | if (pcmcia_devmatch(p_dev, &dynid->id)) { | ||
1034 | ds_dbg(0, "matched %s to %s\n", dev->bus_id, | ||
1035 | drv->name); | ||
1036 | spin_unlock(&p_drv->dynids.lock); | ||
1037 | return 1; | ||
1038 | } | ||
1039 | } | ||
1040 | spin_unlock(&p_drv->dynids.lock); | ||
930 | 1041 | ||
931 | #ifdef CONFIG_PCMCIA_IOCTL | 1042 | #ifdef CONFIG_PCMCIA_IOCTL |
932 | /* matching by cardmgr */ | 1043 | /* matching by cardmgr */ |
933 | if (p_dev->cardmgr == p_drv) { | 1044 | if (p_dev->cardmgr == p_drv) { |
934 | ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id, | 1045 | ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id, |
935 | drv->name); | 1046 | drv->name); |
936 | return 1; | 1047 | return 1; |
937 | } | 1048 | } |
938 | #endif | 1049 | #endif |
939 | 1050 | ||
940 | while (did && did->match_flags) { | 1051 | while (did && did->match_flags) { |
941 | ds_dbg(3, "trying to match %s to %s\n", dev->bus_id, | 1052 | ds_dbg(3, "trying to match %s to %s\n", dev->bus_id, |
942 | drv->name); | 1053 | drv->name); |
943 | if (pcmcia_devmatch(p_dev, did)) { | 1054 | if (pcmcia_devmatch(p_dev, did)) { |
944 | ds_dbg(0, "matched %s to %s\n", dev->bus_id, | 1055 | ds_dbg(0, "matched %s to %s\n", dev->bus_id, |
945 | drv->name); | 1056 | drv->name); |
946 | return 1; | 1057 | return 1; |
947 | } | 1058 | } |
948 | did++; | 1059 | did++; |
949 | } | 1060 | } |
950 | 1061 | ||
951 | return 0; | 1062 | return 0; |
952 | } | 1063 | } |
953 | 1064 | ||
954 | #ifdef CONFIG_HOTPLUG | 1065 | #ifdef CONFIG_HOTPLUG |
955 | 1066 | ||
956 | static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, | 1067 | static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, |
957 | char *buffer, int buffer_size) | 1068 | char *buffer, int buffer_size) |
958 | { | 1069 | { |
959 | struct pcmcia_device *p_dev; | 1070 | struct pcmcia_device *p_dev; |
960 | int i, length = 0; | 1071 | int i, length = 0; |
961 | u32 hash[4] = { 0, 0, 0, 0}; | 1072 | u32 hash[4] = { 0, 0, 0, 0}; |
962 | 1073 | ||
963 | if (!dev) | 1074 | if (!dev) |
964 | return -ENODEV; | 1075 | return -ENODEV; |
965 | 1076 | ||
966 | p_dev = to_pcmcia_dev(dev); | 1077 | p_dev = to_pcmcia_dev(dev); |
967 | 1078 | ||
968 | /* calculate hashes */ | 1079 | /* calculate hashes */ |
969 | for (i=0; i<4; i++) { | 1080 | for (i=0; i<4; i++) { |
970 | if (!p_dev->prod_id[i]) | 1081 | if (!p_dev->prod_id[i]) |
971 | continue; | 1082 | continue; |
972 | hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); | 1083 | hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); |
973 | } | 1084 | } |
974 | 1085 | ||
975 | i = 0; | 1086 | i = 0; |
976 | 1087 | ||
977 | if (add_uevent_var(envp, num_envp, &i, | 1088 | if (add_uevent_var(envp, num_envp, &i, |
978 | buffer, buffer_size, &length, | 1089 | buffer, buffer_size, &length, |
979 | "SOCKET_NO=%u", | 1090 | "SOCKET_NO=%u", |
980 | p_dev->socket->sock)) | 1091 | p_dev->socket->sock)) |
981 | return -ENOMEM; | 1092 | return -ENOMEM; |
982 | 1093 | ||
983 | if (add_uevent_var(envp, num_envp, &i, | 1094 | if (add_uevent_var(envp, num_envp, &i, |
984 | buffer, buffer_size, &length, | 1095 | buffer, buffer_size, &length, |
985 | "DEVICE_NO=%02X", | 1096 | "DEVICE_NO=%02X", |
986 | p_dev->device_no)) | 1097 | p_dev->device_no)) |
987 | return -ENOMEM; | 1098 | return -ENOMEM; |
988 | 1099 | ||
989 | if (add_uevent_var(envp, num_envp, &i, | 1100 | if (add_uevent_var(envp, num_envp, &i, |
990 | buffer, buffer_size, &length, | 1101 | buffer, buffer_size, &length, |
991 | "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" | 1102 | "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" |
992 | "pa%08Xpb%08Xpc%08Xpd%08X", | 1103 | "pa%08Xpb%08Xpc%08Xpd%08X", |
993 | p_dev->has_manf_id ? p_dev->manf_id : 0, | 1104 | p_dev->has_manf_id ? p_dev->manf_id : 0, |
994 | p_dev->has_card_id ? p_dev->card_id : 0, | 1105 | p_dev->has_card_id ? p_dev->card_id : 0, |
995 | p_dev->has_func_id ? p_dev->func_id : 0, | 1106 | p_dev->has_func_id ? p_dev->func_id : 0, |
996 | p_dev->func, | 1107 | p_dev->func, |
997 | p_dev->device_no, | 1108 | p_dev->device_no, |
998 | hash[0], | 1109 | hash[0], |
999 | hash[1], | 1110 | hash[1], |
1000 | hash[2], | 1111 | hash[2], |
1001 | hash[3])) | 1112 | hash[3])) |
1002 | return -ENOMEM; | 1113 | return -ENOMEM; |
1003 | 1114 | ||
1004 | envp[i] = NULL; | 1115 | envp[i] = NULL; |
1005 | 1116 | ||
1006 | return 0; | 1117 | return 0; |
1007 | } | 1118 | } |
1008 | 1119 | ||
1009 | #else | 1120 | #else |
1010 | 1121 | ||
1011 | static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, | 1122 | static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, |
1012 | char *buffer, int buffer_size) | 1123 | char *buffer, int buffer_size) |
1013 | { | 1124 | { |
1014 | return -ENODEV; | 1125 | return -ENODEV; |
1015 | } | 1126 | } |
1016 | 1127 | ||
1017 | #endif | 1128 | #endif |
1018 | 1129 | ||
1019 | /************************ per-device sysfs output ***************************/ | 1130 | /************************ per-device sysfs output ***************************/ |
1020 | 1131 | ||
1021 | #define pcmcia_device_attr(field, test, format) \ | 1132 | #define pcmcia_device_attr(field, test, format) \ |
1022 | static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \ | 1133 | static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \ |
1023 | { \ | 1134 | { \ |
1024 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | 1135 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ |
1025 | return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \ | 1136 | return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \ |
1026 | } | 1137 | } |
1027 | 1138 | ||
1028 | #define pcmcia_device_stringattr(name, field) \ | 1139 | #define pcmcia_device_stringattr(name, field) \ |
1029 | static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ | 1140 | static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ |
1030 | { \ | 1141 | { \ |
1031 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ | 1142 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ |
1032 | return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \ | 1143 | return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \ |
1033 | } | 1144 | } |
1034 | 1145 | ||
1035 | pcmcia_device_attr(func, socket, "0x%02x\n"); | 1146 | pcmcia_device_attr(func, socket, "0x%02x\n"); |
1036 | pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); | 1147 | pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); |
1037 | pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); | 1148 | pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); |
1038 | pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); | 1149 | pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); |
1039 | pcmcia_device_stringattr(prod_id1, prod_id[0]); | 1150 | pcmcia_device_stringattr(prod_id1, prod_id[0]); |
1040 | pcmcia_device_stringattr(prod_id2, prod_id[1]); | 1151 | pcmcia_device_stringattr(prod_id2, prod_id[1]); |
1041 | pcmcia_device_stringattr(prod_id3, prod_id[2]); | 1152 | pcmcia_device_stringattr(prod_id3, prod_id[2]); |
1042 | pcmcia_device_stringattr(prod_id4, prod_id[3]); | 1153 | pcmcia_device_stringattr(prod_id4, prod_id[3]); |
1043 | 1154 | ||
1044 | 1155 | ||
1045 | static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf) | 1156 | static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf) |
1046 | { | 1157 | { |
1047 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1158 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1048 | 1159 | ||
1049 | if (p_dev->suspended) | 1160 | if (p_dev->suspended) |
1050 | return sprintf(buf, "off\n"); | 1161 | return sprintf(buf, "off\n"); |
1051 | else | 1162 | else |
1052 | return sprintf(buf, "on\n"); | 1163 | return sprintf(buf, "on\n"); |
1053 | } | 1164 | } |
1054 | 1165 | ||
1055 | static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr, | 1166 | static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr, |
1056 | const char *buf, size_t count) | 1167 | const char *buf, size_t count) |
1057 | { | 1168 | { |
1058 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1169 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1059 | int ret = 0; | 1170 | int ret = 0; |
1060 | 1171 | ||
1061 | if (!count) | 1172 | if (!count) |
1062 | return -EINVAL; | 1173 | return -EINVAL; |
1063 | 1174 | ||
1064 | if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) | 1175 | if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) |
1065 | ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); | 1176 | ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); |
1066 | else if (p_dev->suspended && !strncmp(buf, "on", 2)) | 1177 | else if (p_dev->suspended && !strncmp(buf, "on", 2)) |
1067 | dpm_runtime_resume(dev); | 1178 | dpm_runtime_resume(dev); |
1068 | 1179 | ||
1069 | return ret ? ret : count; | 1180 | return ret ? ret : count; |
1070 | } | 1181 | } |
1071 | 1182 | ||
1072 | 1183 | ||
1073 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) | 1184 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) |
1074 | { | 1185 | { |
1075 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1186 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1076 | int i; | 1187 | int i; |
1077 | u32 hash[4] = { 0, 0, 0, 0}; | 1188 | u32 hash[4] = { 0, 0, 0, 0}; |
1078 | 1189 | ||
1079 | /* calculate hashes */ | 1190 | /* calculate hashes */ |
1080 | for (i=0; i<4; i++) { | 1191 | for (i=0; i<4; i++) { |
1081 | if (!p_dev->prod_id[i]) | 1192 | if (!p_dev->prod_id[i]) |
1082 | continue; | 1193 | continue; |
1083 | hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i])); | 1194 | hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i])); |
1084 | } | 1195 | } |
1085 | return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" | 1196 | return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" |
1086 | "pa%08Xpb%08Xpc%08Xpd%08X\n", | 1197 | "pa%08Xpb%08Xpc%08Xpd%08X\n", |
1087 | p_dev->has_manf_id ? p_dev->manf_id : 0, | 1198 | p_dev->has_manf_id ? p_dev->manf_id : 0, |
1088 | p_dev->has_card_id ? p_dev->card_id : 0, | 1199 | p_dev->has_card_id ? p_dev->card_id : 0, |
1089 | p_dev->has_func_id ? p_dev->func_id : 0, | 1200 | p_dev->has_func_id ? p_dev->func_id : 0, |
1090 | p_dev->func, p_dev->device_no, | 1201 | p_dev->func, p_dev->device_no, |
1091 | hash[0], hash[1], hash[2], hash[3]); | 1202 | hash[0], hash[1], hash[2], hash[3]); |
1092 | } | 1203 | } |
1093 | 1204 | ||
1094 | static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | 1205 | static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, |
1095 | struct device_attribute *attr, const char *buf, size_t count) | 1206 | struct device_attribute *attr, const char *buf, size_t count) |
1096 | { | 1207 | { |
1097 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1208 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1098 | int ret; | 1209 | int ret; |
1099 | 1210 | ||
1100 | if (!count) | 1211 | if (!count) |
1101 | return -EINVAL; | 1212 | return -EINVAL; |
1102 | 1213 | ||
1103 | mutex_lock(&p_dev->socket->skt_mutex); | 1214 | mutex_lock(&p_dev->socket->skt_mutex); |
1104 | p_dev->allow_func_id_match = 1; | 1215 | p_dev->allow_func_id_match = 1; |
1105 | mutex_unlock(&p_dev->socket->skt_mutex); | 1216 | mutex_unlock(&p_dev->socket->skt_mutex); |
1106 | 1217 | ||
1107 | ret = bus_rescan_devices(&pcmcia_bus_type); | 1218 | ret = bus_rescan_devices(&pcmcia_bus_type); |
1108 | if (ret) | 1219 | if (ret) |
1109 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed after " | 1220 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed after " |
1110 | "allowing func_id matches\n"); | 1221 | "allowing func_id matches\n"); |
1111 | 1222 | ||
1112 | return count; | 1223 | return count; |
1113 | } | 1224 | } |
1114 | 1225 | ||
1115 | static struct device_attribute pcmcia_dev_attrs[] = { | 1226 | static struct device_attribute pcmcia_dev_attrs[] = { |
1116 | __ATTR(function, 0444, func_show, NULL), | 1227 | __ATTR(function, 0444, func_show, NULL), |
1117 | __ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state), | 1228 | __ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state), |
1118 | __ATTR_RO(func_id), | 1229 | __ATTR_RO(func_id), |
1119 | __ATTR_RO(manf_id), | 1230 | __ATTR_RO(manf_id), |
1120 | __ATTR_RO(card_id), | 1231 | __ATTR_RO(card_id), |
1121 | __ATTR_RO(prod_id1), | 1232 | __ATTR_RO(prod_id1), |
1122 | __ATTR_RO(prod_id2), | 1233 | __ATTR_RO(prod_id2), |
1123 | __ATTR_RO(prod_id3), | 1234 | __ATTR_RO(prod_id3), |
1124 | __ATTR_RO(prod_id4), | 1235 | __ATTR_RO(prod_id4), |
1125 | __ATTR_RO(modalias), | 1236 | __ATTR_RO(modalias), |
1126 | __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match), | 1237 | __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match), |
1127 | __ATTR_NULL, | 1238 | __ATTR_NULL, |
1128 | }; | 1239 | }; |
1129 | 1240 | ||
1130 | /* PM support, also needed for reset */ | 1241 | /* PM support, also needed for reset */ |
1131 | 1242 | ||
1132 | static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) | 1243 | static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) |
1133 | { | 1244 | { |
1134 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1245 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1135 | struct pcmcia_driver *p_drv = NULL; | 1246 | struct pcmcia_driver *p_drv = NULL; |
1136 | int ret = 0; | 1247 | int ret = 0; |
1137 | 1248 | ||
1138 | ds_dbg(2, "suspending %s\n", dev->bus_id); | 1249 | ds_dbg(2, "suspending %s\n", dev->bus_id); |
1139 | 1250 | ||
1140 | if (dev->driver) | 1251 | if (dev->driver) |
1141 | p_drv = to_pcmcia_drv(dev->driver); | 1252 | p_drv = to_pcmcia_drv(dev->driver); |
1142 | 1253 | ||
1143 | if (!p_drv) | 1254 | if (!p_drv) |
1144 | goto out; | 1255 | goto out; |
1145 | 1256 | ||
1146 | if (p_drv->suspend) { | 1257 | if (p_drv->suspend) { |
1147 | ret = p_drv->suspend(p_dev); | 1258 | ret = p_drv->suspend(p_dev); |
1148 | if (ret) { | 1259 | if (ret) { |
1149 | printk(KERN_ERR "pcmcia: device %s (driver %s) did " | 1260 | printk(KERN_ERR "pcmcia: device %s (driver %s) did " |
1150 | "not want to go to sleep (%d)\n", | 1261 | "not want to go to sleep (%d)\n", |
1151 | p_dev->devname, p_drv->drv.name, ret); | 1262 | p_dev->devname, p_drv->drv.name, ret); |
1152 | goto out; | 1263 | goto out; |
1153 | } | 1264 | } |
1154 | } | 1265 | } |
1155 | 1266 | ||
1156 | if (p_dev->device_no == p_dev->func) { | 1267 | if (p_dev->device_no == p_dev->func) { |
1157 | ds_dbg(2, "releasing configuration for %s\n", dev->bus_id); | 1268 | ds_dbg(2, "releasing configuration for %s\n", dev->bus_id); |
1158 | pcmcia_release_configuration(p_dev); | 1269 | pcmcia_release_configuration(p_dev); |
1159 | } | 1270 | } |
1160 | 1271 | ||
1161 | out: | 1272 | out: |
1162 | if (!ret) | 1273 | if (!ret) |
1163 | p_dev->suspended = 1; | 1274 | p_dev->suspended = 1; |
1164 | return ret; | 1275 | return ret; |
1165 | } | 1276 | } |
1166 | 1277 | ||
1167 | 1278 | ||
1168 | static int pcmcia_dev_resume(struct device * dev) | 1279 | static int pcmcia_dev_resume(struct device * dev) |
1169 | { | 1280 | { |
1170 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1281 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1171 | struct pcmcia_driver *p_drv = NULL; | 1282 | struct pcmcia_driver *p_drv = NULL; |
1172 | int ret = 0; | 1283 | int ret = 0; |
1173 | 1284 | ||
1174 | ds_dbg(2, "resuming %s\n", dev->bus_id); | 1285 | ds_dbg(2, "resuming %s\n", dev->bus_id); |
1175 | 1286 | ||
1176 | if (dev->driver) | 1287 | if (dev->driver) |
1177 | p_drv = to_pcmcia_drv(dev->driver); | 1288 | p_drv = to_pcmcia_drv(dev->driver); |
1178 | 1289 | ||
1179 | if (!p_drv) | 1290 | if (!p_drv) |
1180 | goto out; | 1291 | goto out; |
1181 | 1292 | ||
1182 | if (p_dev->device_no == p_dev->func) { | 1293 | if (p_dev->device_no == p_dev->func) { |
1183 | ds_dbg(2, "requesting configuration for %s\n", dev->bus_id); | 1294 | ds_dbg(2, "requesting configuration for %s\n", dev->bus_id); |
1184 | ret = pcmcia_request_configuration(p_dev, &p_dev->conf); | 1295 | ret = pcmcia_request_configuration(p_dev, &p_dev->conf); |
1185 | if (ret) | 1296 | if (ret) |
1186 | goto out; | 1297 | goto out; |
1187 | } | 1298 | } |
1188 | 1299 | ||
1189 | if (p_drv->resume) | 1300 | if (p_drv->resume) |
1190 | ret = p_drv->resume(p_dev); | 1301 | ret = p_drv->resume(p_dev); |
1191 | 1302 | ||
1192 | out: | 1303 | out: |
1193 | if (!ret) | 1304 | if (!ret) |
1194 | p_dev->suspended = 0; | 1305 | p_dev->suspended = 0; |
1195 | return ret; | 1306 | return ret; |
1196 | } | 1307 | } |
1197 | 1308 | ||
1198 | 1309 | ||
1199 | static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) | 1310 | static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) |
1200 | { | 1311 | { |
1201 | struct pcmcia_socket *skt = _data; | 1312 | struct pcmcia_socket *skt = _data; |
1202 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1313 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1203 | 1314 | ||
1204 | if (p_dev->socket != skt) | 1315 | if (p_dev->socket != skt) |
1205 | return 0; | 1316 | return 0; |
1206 | 1317 | ||
1207 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); | 1318 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); |
1208 | } | 1319 | } |
1209 | 1320 | ||
1210 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | 1321 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) |
1211 | { | 1322 | { |
1212 | struct pcmcia_socket *skt = _data; | 1323 | struct pcmcia_socket *skt = _data; |
1213 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1324 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1214 | 1325 | ||
1215 | if (p_dev->socket != skt) | 1326 | if (p_dev->socket != skt) |
1216 | return 0; | 1327 | return 0; |
1217 | 1328 | ||
1218 | dpm_runtime_resume(dev); | 1329 | dpm_runtime_resume(dev); |
1219 | 1330 | ||
1220 | return 0; | 1331 | return 0; |
1221 | } | 1332 | } |
1222 | 1333 | ||
1223 | static int pcmcia_bus_resume(struct pcmcia_socket *skt) | 1334 | static int pcmcia_bus_resume(struct pcmcia_socket *skt) |
1224 | { | 1335 | { |
1225 | ds_dbg(2, "resuming socket %d\n", skt->sock); | 1336 | ds_dbg(2, "resuming socket %d\n", skt->sock); |
1226 | bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); | 1337 | bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); |
1227 | return 0; | 1338 | return 0; |
1228 | } | 1339 | } |
1229 | 1340 | ||
1230 | static int pcmcia_bus_suspend(struct pcmcia_socket *skt) | 1341 | static int pcmcia_bus_suspend(struct pcmcia_socket *skt) |
1231 | { | 1342 | { |
1232 | ds_dbg(2, "suspending socket %d\n", skt->sock); | 1343 | ds_dbg(2, "suspending socket %d\n", skt->sock); |
1233 | if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, | 1344 | if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, |
1234 | pcmcia_bus_suspend_callback)) { | 1345 | pcmcia_bus_suspend_callback)) { |
1235 | pcmcia_bus_resume(skt); | 1346 | pcmcia_bus_resume(skt); |
1236 | return -EIO; | 1347 | return -EIO; |
1237 | } | 1348 | } |
1238 | return 0; | 1349 | return 0; |
1239 | } | 1350 | } |
1240 | 1351 | ||
1241 | 1352 | ||
1242 | /*====================================================================== | 1353 | /*====================================================================== |
1243 | 1354 | ||
1244 | The card status event handler. | 1355 | The card status event handler. |
1245 | 1356 | ||
1246 | ======================================================================*/ | 1357 | ======================================================================*/ |
1247 | 1358 | ||
1248 | /* Normally, the event is passed to individual drivers after | 1359 | /* Normally, the event is passed to individual drivers after |
1249 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this | 1360 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this |
1250 | * is inversed to maintain historic compatibility. | 1361 | * is inversed to maintain historic compatibility. |
1251 | */ | 1362 | */ |
1252 | 1363 | ||
1253 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | 1364 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) |
1254 | { | 1365 | { |
1255 | struct pcmcia_socket *s = pcmcia_get_socket(skt); | 1366 | struct pcmcia_socket *s = pcmcia_get_socket(skt); |
1256 | 1367 | ||
1257 | if (!s) { | 1368 | if (!s) { |
1258 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \ | 1369 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \ |
1259 | "failed, event 0x%x lost!\n", skt, event); | 1370 | "failed, event 0x%x lost!\n", skt, event); |
1260 | return -ENODEV; | 1371 | return -ENODEV; |
1261 | } | 1372 | } |
1262 | 1373 | ||
1263 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | 1374 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", |
1264 | event, priority, skt); | 1375 | event, priority, skt); |
1265 | 1376 | ||
1266 | switch (event) { | 1377 | switch (event) { |
1267 | case CS_EVENT_CARD_REMOVAL: | 1378 | case CS_EVENT_CARD_REMOVAL: |
1268 | s->pcmcia_state.present = 0; | 1379 | s->pcmcia_state.present = 0; |
1269 | pcmcia_card_remove(skt, NULL); | 1380 | pcmcia_card_remove(skt, NULL); |
1270 | handle_event(skt, event); | 1381 | handle_event(skt, event); |
1271 | break; | 1382 | break; |
1272 | 1383 | ||
1273 | case CS_EVENT_CARD_INSERTION: | 1384 | case CS_EVENT_CARD_INSERTION: |
1274 | s->pcmcia_state.present = 1; | 1385 | s->pcmcia_state.present = 1; |
1275 | pcmcia_card_add(skt); | 1386 | pcmcia_card_add(skt); |
1276 | handle_event(skt, event); | 1387 | handle_event(skt, event); |
1277 | break; | 1388 | break; |
1278 | 1389 | ||
1279 | case CS_EVENT_EJECTION_REQUEST: | 1390 | case CS_EVENT_EJECTION_REQUEST: |
1280 | break; | 1391 | break; |
1281 | 1392 | ||
1282 | case CS_EVENT_PM_SUSPEND: | 1393 | case CS_EVENT_PM_SUSPEND: |
1283 | case CS_EVENT_PM_RESUME: | 1394 | case CS_EVENT_PM_RESUME: |
1284 | case CS_EVENT_RESET_PHYSICAL: | 1395 | case CS_EVENT_RESET_PHYSICAL: |
1285 | case CS_EVENT_CARD_RESET: | 1396 | case CS_EVENT_CARD_RESET: |
1286 | default: | 1397 | default: |
1287 | handle_event(skt, event); | 1398 | handle_event(skt, event); |
1288 | break; | 1399 | break; |
1289 | } | 1400 | } |
1290 | 1401 | ||
1291 | pcmcia_put_socket(s); | 1402 | pcmcia_put_socket(s); |
1292 | 1403 | ||
1293 | return 0; | 1404 | return 0; |
1294 | } /* ds_event */ | 1405 | } /* ds_event */ |
1295 | 1406 | ||
1296 | 1407 | ||
1297 | struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev) | 1408 | struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev) |
1298 | { | 1409 | { |
1299 | struct pcmcia_device *p_dev; | 1410 | struct pcmcia_device *p_dev; |
1300 | struct pcmcia_device *ret = NULL; | 1411 | struct pcmcia_device *ret = NULL; |
1301 | 1412 | ||
1302 | p_dev = pcmcia_get_dev(_p_dev); | 1413 | p_dev = pcmcia_get_dev(_p_dev); |
1303 | if (!p_dev) | 1414 | if (!p_dev) |
1304 | return NULL; | 1415 | return NULL; |
1305 | 1416 | ||
1306 | if (!p_dev->socket->pcmcia_state.present) | 1417 | if (!p_dev->socket->pcmcia_state.present) |
1307 | goto out; | 1418 | goto out; |
1308 | 1419 | ||
1309 | if (p_dev->_removed) | 1420 | if (p_dev->_removed) |
1310 | goto out; | 1421 | goto out; |
1311 | 1422 | ||
1312 | if (p_dev->suspended) | 1423 | if (p_dev->suspended) |
1313 | goto out; | 1424 | goto out; |
1314 | 1425 | ||
1315 | ret = p_dev; | 1426 | ret = p_dev; |
1316 | out: | 1427 | out: |
1317 | pcmcia_put_dev(p_dev); | 1428 | pcmcia_put_dev(p_dev); |
1318 | return ret; | 1429 | return ret; |
1319 | } | 1430 | } |
1320 | EXPORT_SYMBOL(pcmcia_dev_present); | 1431 | EXPORT_SYMBOL(pcmcia_dev_present); |
1321 | 1432 | ||
1322 | 1433 | ||
1323 | static struct pcmcia_callback pcmcia_bus_callback = { | 1434 | static struct pcmcia_callback pcmcia_bus_callback = { |
1324 | .owner = THIS_MODULE, | 1435 | .owner = THIS_MODULE, |
1325 | .event = ds_event, | 1436 | .event = ds_event, |
1326 | .requery = pcmcia_bus_rescan, | 1437 | .requery = pcmcia_bus_rescan, |
1327 | .suspend = pcmcia_bus_suspend, | 1438 | .suspend = pcmcia_bus_suspend, |
1328 | .resume = pcmcia_bus_resume, | 1439 | .resume = pcmcia_bus_resume, |
1329 | }; | 1440 | }; |
1330 | 1441 | ||
1331 | static int __devinit pcmcia_bus_add_socket(struct device *dev, | 1442 | static int __devinit pcmcia_bus_add_socket(struct device *dev, |
1332 | struct class_interface *class_intf) | 1443 | struct class_interface *class_intf) |
1333 | { | 1444 | { |
1334 | struct pcmcia_socket *socket = dev_get_drvdata(dev); | 1445 | struct pcmcia_socket *socket = dev_get_drvdata(dev); |
1335 | int ret; | 1446 | int ret; |
1336 | 1447 | ||
1337 | socket = pcmcia_get_socket(socket); | 1448 | socket = pcmcia_get_socket(socket); |
1338 | if (!socket) { | 1449 | if (!socket) { |
1339 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket); | 1450 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket); |
1340 | return -ENODEV; | 1451 | return -ENODEV; |
1341 | } | 1452 | } |
1342 | 1453 | ||
1343 | /* | 1454 | /* |
1344 | * Ugly. But we want to wait for the socket threads to have started up. | 1455 | * Ugly. But we want to wait for the socket threads to have started up. |
1345 | * We really should let the drivers themselves drive some of this.. | 1456 | * We really should let the drivers themselves drive some of this.. |
1346 | */ | 1457 | */ |
1347 | msleep(250); | 1458 | msleep(250); |
1348 | 1459 | ||
1349 | #ifdef CONFIG_PCMCIA_IOCTL | 1460 | #ifdef CONFIG_PCMCIA_IOCTL |
1350 | init_waitqueue_head(&socket->queue); | 1461 | init_waitqueue_head(&socket->queue); |
1351 | #endif | 1462 | #endif |
1352 | INIT_LIST_HEAD(&socket->devices_list); | 1463 | INIT_LIST_HEAD(&socket->devices_list); |
1353 | INIT_WORK(&socket->device_add, pcmcia_delayed_add_device); | 1464 | INIT_WORK(&socket->device_add, pcmcia_delayed_add_device); |
1354 | memset(&socket->pcmcia_state, 0, sizeof(u8)); | 1465 | memset(&socket->pcmcia_state, 0, sizeof(u8)); |
1355 | socket->device_count = 0; | 1466 | socket->device_count = 0; |
1356 | 1467 | ||
1357 | ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback); | 1468 | ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback); |
1358 | if (ret) { | 1469 | if (ret) { |
1359 | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); | 1470 | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); |
1360 | pcmcia_put_socket(socket); | 1471 | pcmcia_put_socket(socket); |
1361 | return (ret); | 1472 | return (ret); |
1362 | } | 1473 | } |
1363 | 1474 | ||
1364 | return 0; | 1475 | return 0; |
1365 | } | 1476 | } |
1366 | 1477 | ||
1367 | static void pcmcia_bus_remove_socket(struct device *dev, | 1478 | static void pcmcia_bus_remove_socket(struct device *dev, |
1368 | struct class_interface *class_intf) | 1479 | struct class_interface *class_intf) |
1369 | { | 1480 | { |
1370 | struct pcmcia_socket *socket = dev_get_drvdata(dev); | 1481 | struct pcmcia_socket *socket = dev_get_drvdata(dev); |
1371 | 1482 | ||
1372 | if (!socket) | 1483 | if (!socket) |
1373 | return; | 1484 | return; |
1374 | 1485 | ||
1375 | socket->pcmcia_state.dead = 1; | 1486 | socket->pcmcia_state.dead = 1; |
1376 | pccard_register_pcmcia(socket, NULL); | 1487 | pccard_register_pcmcia(socket, NULL); |
1377 | 1488 | ||
1378 | /* unregister any unbound devices */ | 1489 | /* unregister any unbound devices */ |
1379 | mutex_lock(&socket->skt_mutex); | 1490 | mutex_lock(&socket->skt_mutex); |
1380 | pcmcia_card_remove(socket, NULL); | 1491 | pcmcia_card_remove(socket, NULL); |
1381 | mutex_unlock(&socket->skt_mutex); | 1492 | mutex_unlock(&socket->skt_mutex); |
1382 | 1493 | ||
1383 | pcmcia_put_socket(socket); | 1494 | pcmcia_put_socket(socket); |
1384 | 1495 | ||
1385 | return; | 1496 | return; |
1386 | } | 1497 | } |
1387 | 1498 | ||
1388 | 1499 | ||
1389 | /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ | 1500 | /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ |
1390 | static struct class_interface pcmcia_bus_interface = { | 1501 | static struct class_interface pcmcia_bus_interface = { |
1391 | .class = &pcmcia_socket_class, | 1502 | .class = &pcmcia_socket_class, |
1392 | .add_dev = &pcmcia_bus_add_socket, | 1503 | .add_dev = &pcmcia_bus_add_socket, |
1393 | .remove_dev = &pcmcia_bus_remove_socket, | 1504 | .remove_dev = &pcmcia_bus_remove_socket, |
1394 | }; | 1505 | }; |
1395 | 1506 | ||
1396 | 1507 | ||
1397 | struct bus_type pcmcia_bus_type = { | 1508 | struct bus_type pcmcia_bus_type = { |
1398 | .name = "pcmcia", | 1509 | .name = "pcmcia", |
1399 | .uevent = pcmcia_bus_uevent, | 1510 | .uevent = pcmcia_bus_uevent, |
1400 | .match = pcmcia_bus_match, | 1511 | .match = pcmcia_bus_match, |
1401 | .dev_attrs = pcmcia_dev_attrs, | 1512 | .dev_attrs = pcmcia_dev_attrs, |
1402 | .probe = pcmcia_device_probe, | 1513 | .probe = pcmcia_device_probe, |
1403 | .remove = pcmcia_device_remove, | 1514 | .remove = pcmcia_device_remove, |
1404 | .suspend = pcmcia_dev_suspend, | 1515 | .suspend = pcmcia_dev_suspend, |
1405 | .resume = pcmcia_dev_resume, | 1516 | .resume = pcmcia_dev_resume, |
1406 | }; | 1517 | }; |
1407 | 1518 | ||
1408 | 1519 | ||
1409 | static int __init init_pcmcia_bus(void) | 1520 | static int __init init_pcmcia_bus(void) |
1410 | { | 1521 | { |
1411 | int ret; | 1522 | int ret; |
1412 | 1523 | ||
1413 | spin_lock_init(&pcmcia_dev_list_lock); | 1524 | spin_lock_init(&pcmcia_dev_list_lock); |
1414 | 1525 | ||
1415 | ret = bus_register(&pcmcia_bus_type); | 1526 | ret = bus_register(&pcmcia_bus_type); |
1416 | if (ret < 0) { | 1527 | if (ret < 0) { |
1417 | printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret); | 1528 | printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret); |
1418 | return ret; | 1529 | return ret; |
1419 | } | 1530 | } |
1420 | ret = class_interface_register(&pcmcia_bus_interface); | 1531 | ret = class_interface_register(&pcmcia_bus_interface); |
1421 | if (ret < 0) { | 1532 | if (ret < 0) { |
1422 | printk(KERN_WARNING | 1533 | printk(KERN_WARNING |
1423 | "pcmcia: class_interface_register error: %d\n", ret); | 1534 | "pcmcia: class_interface_register error: %d\n", ret); |
1424 | bus_unregister(&pcmcia_bus_type); | 1535 | bus_unregister(&pcmcia_bus_type); |
1425 | return ret; | 1536 | return ret; |
1426 | } | 1537 | } |
1427 | 1538 | ||
1428 | pcmcia_setup_ioctl(); | 1539 | pcmcia_setup_ioctl(); |
1429 | 1540 | ||
1430 | return 0; | 1541 | return 0; |
1431 | } | 1542 | } |
1432 | fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that | 1543 | fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that |
1433 | * pcmcia_socket_class is already registered */ | 1544 | * pcmcia_socket_class is already registered */ |
1434 | 1545 | ||
1435 | 1546 | ||
1436 | static void __exit exit_pcmcia_bus(void) | 1547 | static void __exit exit_pcmcia_bus(void) |
1437 | { | 1548 | { |
1438 | pcmcia_cleanup_ioctl(); | 1549 | pcmcia_cleanup_ioctl(); |
1439 | 1550 | ||
1440 | class_interface_unregister(&pcmcia_bus_interface); | 1551 | class_interface_unregister(&pcmcia_bus_interface); |
1441 | 1552 | ||
1442 | bus_unregister(&pcmcia_bus_type); | 1553 | bus_unregister(&pcmcia_bus_type); |
1443 | } | 1554 | } |
1444 | module_exit(exit_pcmcia_bus); | 1555 | module_exit(exit_pcmcia_bus); |
1445 | 1556 | ||
1446 | 1557 | ||
1447 | MODULE_ALIAS("ds"); | 1558 | MODULE_ALIAS("ds"); |
1448 | 1559 |
include/pcmcia/ds.h
1 | /* | 1 | /* |
2 | * ds.h -- 16-bit PCMCIA core support | 2 | * ds.h -- 16-bit PCMCIA core support |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * The initial developer of the original code is David A. Hinds | 8 | * The initial developer of the original code is David A. Hinds |
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | 9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds |
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | 10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. |
11 | * | 11 | * |
12 | * (C) 1999 David A. Hinds | 12 | * (C) 1999 David A. Hinds |
13 | * (C) 2003 - 2004 Dominik Brodowski | 13 | * (C) 2003 - 2004 Dominik Brodowski |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #ifndef _LINUX_DS_H | 16 | #ifndef _LINUX_DS_H |
17 | #define _LINUX_DS_H | 17 | #define _LINUX_DS_H |
18 | 18 | ||
19 | #ifdef __KERNEL__ | 19 | #ifdef __KERNEL__ |
20 | #include <linux/mod_devicetable.h> | 20 | #include <linux/mod_devicetable.h> |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | #include <pcmcia/bulkmem.h> | 23 | #include <pcmcia/bulkmem.h> |
24 | #include <pcmcia/cs_types.h> | 24 | #include <pcmcia/cs_types.h> |
25 | #include <pcmcia/device_id.h> | 25 | #include <pcmcia/device_id.h> |
26 | 26 | ||
27 | typedef struct tuple_parse_t { | 27 | typedef struct tuple_parse_t { |
28 | tuple_t tuple; | 28 | tuple_t tuple; |
29 | cisdata_t data[255]; | 29 | cisdata_t data[255]; |
30 | cisparse_t parse; | 30 | cisparse_t parse; |
31 | } tuple_parse_t; | 31 | } tuple_parse_t; |
32 | 32 | ||
33 | typedef struct win_info_t { | 33 | typedef struct win_info_t { |
34 | window_handle_t handle; | 34 | window_handle_t handle; |
35 | win_req_t window; | 35 | win_req_t window; |
36 | memreq_t map; | 36 | memreq_t map; |
37 | } win_info_t; | 37 | } win_info_t; |
38 | 38 | ||
39 | typedef struct bind_info_t { | 39 | typedef struct bind_info_t { |
40 | dev_info_t dev_info; | 40 | dev_info_t dev_info; |
41 | u_char function; | 41 | u_char function; |
42 | struct pcmcia_device *instance; | 42 | struct pcmcia_device *instance; |
43 | char name[DEV_NAME_LEN]; | 43 | char name[DEV_NAME_LEN]; |
44 | u_short major, minor; | 44 | u_short major, minor; |
45 | void *next; | 45 | void *next; |
46 | } bind_info_t; | 46 | } bind_info_t; |
47 | 47 | ||
48 | typedef struct mtd_info_t { | 48 | typedef struct mtd_info_t { |
49 | dev_info_t dev_info; | 49 | dev_info_t dev_info; |
50 | u_int Attributes; | 50 | u_int Attributes; |
51 | u_int CardOffset; | 51 | u_int CardOffset; |
52 | } mtd_info_t; | 52 | } mtd_info_t; |
53 | 53 | ||
54 | typedef union ds_ioctl_arg_t { | 54 | typedef union ds_ioctl_arg_t { |
55 | adjust_t adjust; | 55 | adjust_t adjust; |
56 | config_info_t config; | 56 | config_info_t config; |
57 | tuple_t tuple; | 57 | tuple_t tuple; |
58 | tuple_parse_t tuple_parse; | 58 | tuple_parse_t tuple_parse; |
59 | client_req_t client_req; | 59 | client_req_t client_req; |
60 | cs_status_t status; | 60 | cs_status_t status; |
61 | conf_reg_t conf_reg; | 61 | conf_reg_t conf_reg; |
62 | cisinfo_t cisinfo; | 62 | cisinfo_t cisinfo; |
63 | region_info_t region; | 63 | region_info_t region; |
64 | bind_info_t bind_info; | 64 | bind_info_t bind_info; |
65 | mtd_info_t mtd_info; | 65 | mtd_info_t mtd_info; |
66 | win_info_t win_info; | 66 | win_info_t win_info; |
67 | cisdump_t cisdump; | 67 | cisdump_t cisdump; |
68 | } ds_ioctl_arg_t; | 68 | } ds_ioctl_arg_t; |
69 | 69 | ||
70 | #define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t) | 70 | #define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t) |
71 | #define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t) | 71 | #define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t) |
72 | #define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t) | 72 | #define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t) |
73 | #define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t) | 73 | #define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t) |
74 | #define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t) | 74 | #define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t) |
75 | #define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t) | 75 | #define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t) |
76 | #define DS_RESET_CARD _IO ('d', 8) | 76 | #define DS_RESET_CARD _IO ('d', 8) |
77 | #define DS_GET_STATUS _IOWR('d', 9, cs_status_t) | 77 | #define DS_GET_STATUS _IOWR('d', 9, cs_status_t) |
78 | #define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t) | 78 | #define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t) |
79 | #define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t) | 79 | #define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t) |
80 | #define DS_SUSPEND_CARD _IO ('d', 12) | 80 | #define DS_SUSPEND_CARD _IO ('d', 12) |
81 | #define DS_RESUME_CARD _IO ('d', 13) | 81 | #define DS_RESUME_CARD _IO ('d', 13) |
82 | #define DS_EJECT_CARD _IO ('d', 14) | 82 | #define DS_EJECT_CARD _IO ('d', 14) |
83 | #define DS_INSERT_CARD _IO ('d', 15) | 83 | #define DS_INSERT_CARD _IO ('d', 15) |
84 | #define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t) | 84 | #define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t) |
85 | #define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t) | 85 | #define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t) |
86 | #define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t) | 86 | #define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t) |
87 | #define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t) | 87 | #define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t) |
88 | #define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t) | 88 | #define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t) |
89 | #define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t) | 89 | #define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t) |
90 | 90 | ||
91 | #define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t) | 91 | #define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t) |
92 | #define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t) | 92 | #define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t) |
93 | #define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t) | 93 | #define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t) |
94 | #define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t) | 94 | #define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t) |
95 | #define DS_BIND_MTD _IOWR('d', 64, mtd_info_t) | 95 | #define DS_BIND_MTD _IOWR('d', 64, mtd_info_t) |
96 | 96 | ||
97 | #ifdef __KERNEL__ | 97 | #ifdef __KERNEL__ |
98 | #include <linux/device.h> | 98 | #include <linux/device.h> |
99 | #include <pcmcia/ss.h> | 99 | #include <pcmcia/ss.h> |
100 | 100 | ||
101 | typedef struct dev_node_t { | 101 | typedef struct dev_node_t { |
102 | char dev_name[DEV_NAME_LEN]; | 102 | char dev_name[DEV_NAME_LEN]; |
103 | u_short major, minor; | 103 | u_short major, minor; |
104 | struct dev_node_t *next; | 104 | struct dev_node_t *next; |
105 | } dev_node_t; | 105 | } dev_node_t; |
106 | 106 | ||
107 | 107 | ||
108 | struct pcmcia_socket; | 108 | struct pcmcia_socket; |
109 | struct config_t; | 109 | struct config_t; |
110 | 110 | ||
111 | struct pcmcia_dynids { | ||
112 | spinlock_t lock; | ||
113 | struct list_head list; | ||
114 | }; | ||
115 | |||
111 | struct pcmcia_driver { | 116 | struct pcmcia_driver { |
112 | int (*probe) (struct pcmcia_device *dev); | 117 | int (*probe) (struct pcmcia_device *dev); |
113 | void (*remove) (struct pcmcia_device *dev); | 118 | void (*remove) (struct pcmcia_device *dev); |
114 | 119 | ||
115 | int (*suspend) (struct pcmcia_device *dev); | 120 | int (*suspend) (struct pcmcia_device *dev); |
116 | int (*resume) (struct pcmcia_device *dev); | 121 | int (*resume) (struct pcmcia_device *dev); |
117 | 122 | ||
118 | struct module *owner; | 123 | struct module *owner; |
119 | struct pcmcia_device_id *id_table; | 124 | struct pcmcia_device_id *id_table; |
120 | struct device_driver drv; | 125 | struct device_driver drv; |
126 | struct pcmcia_dynids dynids; | ||
121 | }; | 127 | }; |
122 | 128 | ||
123 | /* driver registration */ | 129 | /* driver registration */ |
124 | int pcmcia_register_driver(struct pcmcia_driver *driver); | 130 | int pcmcia_register_driver(struct pcmcia_driver *driver); |
125 | void pcmcia_unregister_driver(struct pcmcia_driver *driver); | 131 | void pcmcia_unregister_driver(struct pcmcia_driver *driver); |
126 | 132 | ||
127 | 133 | ||
128 | struct pcmcia_device { | 134 | struct pcmcia_device { |
129 | /* the socket and the device_no [for multifunction devices] | 135 | /* the socket and the device_no [for multifunction devices] |
130 | uniquely define a pcmcia_device */ | 136 | uniquely define a pcmcia_device */ |
131 | struct pcmcia_socket *socket; | 137 | struct pcmcia_socket *socket; |
132 | 138 | ||
133 | char *devname; | 139 | char *devname; |
134 | 140 | ||
135 | u8 device_no; | 141 | u8 device_no; |
136 | 142 | ||
137 | /* the hardware "function" device; certain subdevices can | 143 | /* the hardware "function" device; certain subdevices can |
138 | * share one hardware "function" device. */ | 144 | * share one hardware "function" device. */ |
139 | u8 func; | 145 | u8 func; |
140 | struct config_t* function_config; | 146 | struct config_t* function_config; |
141 | 147 | ||
142 | struct list_head socket_device_list; | 148 | struct list_head socket_device_list; |
143 | 149 | ||
144 | /* deprecated, will be cleaned up soon */ | 150 | /* deprecated, will be cleaned up soon */ |
145 | dev_node_t *dev_node; | 151 | dev_node_t *dev_node; |
146 | u_int open; | 152 | u_int open; |
147 | io_req_t io; | 153 | io_req_t io; |
148 | irq_req_t irq; | 154 | irq_req_t irq; |
149 | config_req_t conf; | 155 | config_req_t conf; |
150 | window_handle_t win; | 156 | window_handle_t win; |
151 | 157 | ||
152 | /* Is the device suspended, or in the process of | 158 | /* Is the device suspended, or in the process of |
153 | * being removed? */ | 159 | * being removed? */ |
154 | u16 suspended:1; | 160 | u16 suspended:1; |
155 | u16 _removed:1; | 161 | u16 _removed:1; |
156 | 162 | ||
157 | /* Flags whether io, irq, win configurations were | 163 | /* Flags whether io, irq, win configurations were |
158 | * requested, and whether the configuration is "locked" */ | 164 | * requested, and whether the configuration is "locked" */ |
159 | u16 _irq:1; | 165 | u16 _irq:1; |
160 | u16 _io:1; | 166 | u16 _io:1; |
161 | u16 _win:4; | 167 | u16 _win:4; |
162 | u16 _locked:1; | 168 | u16 _locked:1; |
163 | 169 | ||
164 | /* Flag whether a "fuzzy" func_id based match is | 170 | /* Flag whether a "fuzzy" func_id based match is |
165 | * allowed. */ | 171 | * allowed. */ |
166 | u16 allow_func_id_match:1; | 172 | u16 allow_func_id_match:1; |
167 | 173 | ||
168 | /* information about this device */ | 174 | /* information about this device */ |
169 | u16 has_manf_id:1; | 175 | u16 has_manf_id:1; |
170 | u16 has_card_id:1; | 176 | u16 has_card_id:1; |
171 | u16 has_func_id:1; | 177 | u16 has_func_id:1; |
172 | 178 | ||
173 | u16 reserved:3; | 179 | u16 reserved:3; |
174 | 180 | ||
175 | u8 func_id; | 181 | u8 func_id; |
176 | u16 manf_id; | 182 | u16 manf_id; |
177 | u16 card_id; | 183 | u16 card_id; |
178 | 184 | ||
179 | char * prod_id[4]; | 185 | char * prod_id[4]; |
180 | 186 | ||
181 | struct device dev; | 187 | struct device dev; |
182 | 188 | ||
183 | #ifdef CONFIG_PCMCIA_IOCTL | 189 | #ifdef CONFIG_PCMCIA_IOCTL |
184 | /* device driver wanted by cardmgr */ | 190 | /* device driver wanted by cardmgr */ |
185 | struct pcmcia_driver * cardmgr; | 191 | struct pcmcia_driver * cardmgr; |
186 | #endif | 192 | #endif |
187 | 193 | ||
188 | /* data private to drivers */ | 194 | /* data private to drivers */ |
189 | void *priv; | 195 | void *priv; |
190 | }; | 196 | }; |
191 | 197 | ||
192 | #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev) | 198 | #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev) |
193 | #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) | 199 | #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) |
194 | 200 | ||
195 | #define handle_to_dev(handle) (handle->dev) | 201 | #define handle_to_dev(handle) (handle->dev) |
196 | 202 | ||
197 | /* error reporting */ | 203 | /* error reporting */ |
198 | void cs_error(struct pcmcia_device *handle, int func, int ret); | 204 | void cs_error(struct pcmcia_device *handle, int func, int ret); |
199 | 205 | ||
200 | #endif /* __KERNEL__ */ | 206 | #endif /* __KERNEL__ */ |
201 | #endif /* _LINUX_DS_H */ | 207 | #endif /* _LINUX_DS_H */ |
202 | 208 |