diff options
Diffstat (limited to 'drivers/net/wireless/airo_cs.c')
-rw-r--r-- | drivers/net/wireless/airo_cs.c | 158 |
1 files changed, 50 insertions, 108 deletions
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index a496460ce224..af0cbb6c5c0c 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c | |||
@@ -80,8 +80,8 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); | |||
80 | event handler. | 80 | event handler. |
81 | */ | 81 | */ |
82 | 82 | ||
83 | static void airo_config(dev_link_t *link); | 83 | static int airo_config(struct pcmcia_device *link); |
84 | static void airo_release(dev_link_t *link); | 84 | static void airo_release(struct pcmcia_device *link); |
85 | 85 | ||
86 | /* | 86 | /* |
87 | The attach() and detach() entry points are used to create and destroy | 87 | The attach() and detach() entry points are used to create and destroy |
@@ -101,10 +101,10 @@ static void airo_detach(struct pcmcia_device *p_dev); | |||
101 | /* | 101 | /* |
102 | A linked list of "instances" of the aironet device. Each actual | 102 | A linked list of "instances" of the aironet device. Each actual |
103 | PCMCIA card corresponds to one device instance, and is described | 103 | PCMCIA card corresponds to one device instance, and is described |
104 | by one dev_link_t structure (defined in ds.h). | 104 | by one struct pcmcia_device structure (defined in ds.h). |
105 | 105 | ||
106 | You may not want to use a linked list for this -- for example, the | 106 | You may not want to use a linked list for this -- for example, the |
107 | memory card driver uses an array of dev_link_t pointers, where minor | 107 | memory card driver uses an array of struct pcmcia_device pointers, where minor |
108 | device numbers are used to derive the corresponding array index. | 108 | device numbers are used to derive the corresponding array index. |
109 | */ | 109 | */ |
110 | 110 | ||
@@ -114,7 +114,7 @@ static void airo_detach(struct pcmcia_device *p_dev); | |||
114 | example, ethernet cards, modems). In other cases, there may be | 114 | example, ethernet cards, modems). In other cases, there may be |
115 | many actual or logical devices (SCSI adapters, memory cards with | 115 | many actual or logical devices (SCSI adapters, memory cards with |
116 | multiple partitions). The dev_node_t structures need to be kept | 116 | multiple partitions). The dev_node_t structures need to be kept |
117 | in a linked list starting at the 'dev' field of a dev_link_t | 117 | in a linked list starting at the 'dev' field of a struct pcmcia_device |
118 | structure. We allocate them in the card's private data structure, | 118 | structure. We allocate them in the card's private data structure, |
119 | because they generally shouldn't be allocated dynamically. | 119 | because they generally shouldn't be allocated dynamically. |
120 | 120 | ||
@@ -141,24 +141,16 @@ typedef struct local_info_t { | |||
141 | 141 | ||
142 | ======================================================================*/ | 142 | ======================================================================*/ |
143 | 143 | ||
144 | static int airo_attach(struct pcmcia_device *p_dev) | 144 | static int airo_probe(struct pcmcia_device *p_dev) |
145 | { | 145 | { |
146 | dev_link_t *link; | ||
147 | local_info_t *local; | 146 | local_info_t *local; |
148 | 147 | ||
149 | DEBUG(0, "airo_attach()\n"); | 148 | DEBUG(0, "airo_attach()\n"); |
150 | 149 | ||
151 | /* Initialize the dev_link_t structure */ | ||
152 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
153 | if (!link) { | ||
154 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | ||
155 | return -ENOMEM; | ||
156 | } | ||
157 | |||
158 | /* Interrupt setup */ | 150 | /* Interrupt setup */ |
159 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | 151 | p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; |
160 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | 152 | p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; |
161 | link->irq.Handler = NULL; | 153 | p_dev->irq.Handler = NULL; |
162 | 154 | ||
163 | /* | 155 | /* |
164 | General socket configuration defaults can go here. In this | 156 | General socket configuration defaults can go here. In this |
@@ -167,26 +159,18 @@ static int airo_attach(struct pcmcia_device *p_dev) | |||
167 | and attributes of IO windows) are fixed by the nature of the | 159 | and attributes of IO windows) are fixed by the nature of the |
168 | device, and can be hard-wired here. | 160 | device, and can be hard-wired here. |
169 | */ | 161 | */ |
170 | link->conf.Attributes = 0; | 162 | p_dev->conf.Attributes = 0; |
171 | link->conf.Vcc = 50; | 163 | p_dev->conf.IntType = INT_MEMORY_AND_IO; |
172 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
173 | 164 | ||
174 | /* Allocate space for private device-specific data */ | 165 | /* Allocate space for private device-specific data */ |
175 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); | 166 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); |
176 | if (!local) { | 167 | if (!local) { |
177 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | 168 | printk(KERN_ERR "airo_cs: no memory for new device\n"); |
178 | kfree (link); | ||
179 | return -ENOMEM; | 169 | return -ENOMEM; |
180 | } | 170 | } |
181 | link->priv = local; | 171 | p_dev->priv = local; |
182 | 172 | ||
183 | link->handle = p_dev; | 173 | return airo_config(p_dev); |
184 | p_dev->instance = link; | ||
185 | |||
186 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
187 | airo_config(link); | ||
188 | |||
189 | return 0; | ||
190 | } /* airo_attach */ | 174 | } /* airo_attach */ |
191 | 175 | ||
192 | /*====================================================================== | 176 | /*====================================================================== |
@@ -198,14 +182,11 @@ static int airo_attach(struct pcmcia_device *p_dev) | |||
198 | 182 | ||
199 | ======================================================================*/ | 183 | ======================================================================*/ |
200 | 184 | ||
201 | static void airo_detach(struct pcmcia_device *p_dev) | 185 | static void airo_detach(struct pcmcia_device *link) |
202 | { | 186 | { |
203 | dev_link_t *link = dev_to_instance(p_dev); | ||
204 | |||
205 | DEBUG(0, "airo_detach(0x%p)\n", link); | 187 | DEBUG(0, "airo_detach(0x%p)\n", link); |
206 | 188 | ||
207 | if (link->state & DEV_CONFIG) | 189 | airo_release(link); |
208 | airo_release(link); | ||
209 | 190 | ||
210 | if ( ((local_info_t*)link->priv)->eth_dev ) { | 191 | if ( ((local_info_t*)link->priv)->eth_dev ) { |
211 | stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); | 192 | stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); |
@@ -213,7 +194,6 @@ static void airo_detach(struct pcmcia_device *p_dev) | |||
213 | ((local_info_t*)link->priv)->eth_dev = NULL; | 194 | ((local_info_t*)link->priv)->eth_dev = NULL; |
214 | 195 | ||
215 | kfree(link->priv); | 196 | kfree(link->priv); |
216 | kfree(link); | ||
217 | } /* airo_detach */ | 197 | } /* airo_detach */ |
218 | 198 | ||
219 | /*====================================================================== | 199 | /*====================================================================== |
@@ -227,9 +207,8 @@ static void airo_detach(struct pcmcia_device *p_dev) | |||
227 | #define CS_CHECK(fn, ret) \ | 207 | #define CS_CHECK(fn, ret) \ |
228 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 208 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
229 | 209 | ||
230 | static void airo_config(dev_link_t *link) | 210 | static int airo_config(struct pcmcia_device *link) |
231 | { | 211 | { |
232 | client_handle_t handle; | ||
233 | tuple_t tuple; | 212 | tuple_t tuple; |
234 | cisparse_t parse; | 213 | cisparse_t parse; |
235 | local_info_t *dev; | 214 | local_info_t *dev; |
@@ -237,8 +216,7 @@ static void airo_config(dev_link_t *link) | |||
237 | u_char buf[64]; | 216 | u_char buf[64]; |
238 | win_req_t req; | 217 | win_req_t req; |
239 | memreq_t map; | 218 | memreq_t map; |
240 | 219 | ||
241 | handle = link->handle; | ||
242 | dev = link->priv; | 220 | dev = link->priv; |
243 | 221 | ||
244 | DEBUG(0, "airo_config(0x%p)\n", link); | 222 | DEBUG(0, "airo_config(0x%p)\n", link); |
@@ -252,15 +230,12 @@ static void airo_config(dev_link_t *link) | |||
252 | tuple.TupleData = buf; | 230 | tuple.TupleData = buf; |
253 | tuple.TupleDataMax = sizeof(buf); | 231 | tuple.TupleDataMax = sizeof(buf); |
254 | tuple.TupleOffset = 0; | 232 | tuple.TupleOffset = 0; |
255 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | 233 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); |
256 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | 234 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); |
257 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | 235 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); |
258 | link->conf.ConfigBase = parse.config.base; | 236 | link->conf.ConfigBase = parse.config.base; |
259 | link->conf.Present = parse.config.rmask[0]; | 237 | link->conf.Present = parse.config.rmask[0]; |
260 | 238 | ||
261 | /* Configure card */ | ||
262 | link->state |= DEV_CONFIG; | ||
263 | |||
264 | /* | 239 | /* |
265 | In this loop, we scan the CIS for configuration table entries, | 240 | In this loop, we scan the CIS for configuration table entries, |
266 | each of which describes a valid card configuration, including | 241 | each of which describes a valid card configuration, including |
@@ -274,12 +249,12 @@ static void airo_config(dev_link_t *link) | |||
274 | will only use the CIS to fill in implementation-defined details. | 249 | will only use the CIS to fill in implementation-defined details. |
275 | */ | 250 | */ |
276 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | 251 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; |
277 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | 252 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); |
278 | while (1) { | 253 | while (1) { |
279 | cistpl_cftable_entry_t dflt = { 0 }; | 254 | cistpl_cftable_entry_t dflt = { 0 }; |
280 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); | 255 | cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); |
281 | if (pcmcia_get_tuple_data(handle, &tuple) != 0 || | 256 | if (pcmcia_get_tuple_data(link, &tuple) != 0 || |
282 | pcmcia_parse_tuple(handle, &tuple, &parse) != 0) | 257 | pcmcia_parse_tuple(link, &tuple, &parse) != 0) |
283 | goto next_entry; | 258 | goto next_entry; |
284 | 259 | ||
285 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; | 260 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; |
@@ -294,16 +269,11 @@ static void airo_config(dev_link_t *link) | |||
294 | 269 | ||
295 | /* Use power settings for Vcc and Vpp if present */ | 270 | /* Use power settings for Vcc and Vpp if present */ |
296 | /* Note that the CIS values need to be rescaled */ | 271 | /* Note that the CIS values need to be rescaled */ |
297 | if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
298 | link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; | ||
299 | else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) | ||
300 | link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; | ||
301 | |||
302 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) | 272 | if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) |
303 | link->conf.Vpp1 = link->conf.Vpp2 = | 273 | link->conf.Vpp = |
304 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; | 274 | cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; |
305 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) | 275 | else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) |
306 | link->conf.Vpp1 = link->conf.Vpp2 = | 276 | link->conf.Vpp = |
307 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; | 277 | dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; |
308 | 278 | ||
309 | /* Do we need to allocate an interrupt? */ | 279 | /* Do we need to allocate an interrupt? */ |
@@ -329,12 +299,12 @@ static void airo_config(dev_link_t *link) | |||
329 | } | 299 | } |
330 | 300 | ||
331 | /* This reserves IO space but doesn't actually enable it */ | 301 | /* This reserves IO space but doesn't actually enable it */ |
332 | if (pcmcia_request_io(link->handle, &link->io) != 0) | 302 | if (pcmcia_request_io(link, &link->io) != 0) |
333 | goto next_entry; | 303 | goto next_entry; |
334 | 304 | ||
335 | /* | 305 | /* |
336 | Now set up a common memory window, if needed. There is room | 306 | Now set up a common memory window, if needed. There is room |
337 | in the dev_link_t structure for one memory window handle, | 307 | in the struct pcmcia_device structure for one memory window handle, |
338 | but if the base addresses need to be saved, or if multiple | 308 | but if the base addresses need to be saved, or if multiple |
339 | windows are needed, the info should go in the private data | 309 | windows are needed, the info should go in the private data |
340 | structure for this device. | 310 | structure for this device. |
@@ -350,7 +320,7 @@ static void airo_config(dev_link_t *link) | |||
350 | req.Base = mem->win[0].host_addr; | 320 | req.Base = mem->win[0].host_addr; |
351 | req.Size = mem->win[0].len; | 321 | req.Size = mem->win[0].len; |
352 | req.AccessSpeed = 0; | 322 | req.AccessSpeed = 0; |
353 | if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) | 323 | if (pcmcia_request_window(&link, &req, &link->win) != 0) |
354 | goto next_entry; | 324 | goto next_entry; |
355 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; | 325 | map.Page = 0; map.CardOffset = mem->win[0].card_addr; |
356 | if (pcmcia_map_mem_page(link->win, &map) != 0) | 326 | if (pcmcia_map_mem_page(link->win, &map) != 0) |
@@ -360,7 +330,7 @@ static void airo_config(dev_link_t *link) | |||
360 | break; | 330 | break; |
361 | 331 | ||
362 | next_entry: | 332 | next_entry: |
363 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); | 333 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); |
364 | } | 334 | } |
365 | 335 | ||
366 | /* | 336 | /* |
@@ -369,33 +339,32 @@ static void airo_config(dev_link_t *link) | |||
369 | irq structure is initialized. | 339 | irq structure is initialized. |
370 | */ | 340 | */ |
371 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | 341 | if (link->conf.Attributes & CONF_ENABLE_IRQ) |
372 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | 342 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); |
373 | 343 | ||
374 | /* | 344 | /* |
375 | This actually configures the PCMCIA socket -- setting up | 345 | This actually configures the PCMCIA socket -- setting up |
376 | the I/O windows and the interrupt mapping, and putting the | 346 | the I/O windows and the interrupt mapping, and putting the |
377 | card and host interface into "Memory and IO" mode. | 347 | card and host interface into "Memory and IO" mode. |
378 | */ | 348 | */ |
379 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | 349 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); |
380 | ((local_info_t*)link->priv)->eth_dev = | 350 | ((local_info_t*)link->priv)->eth_dev = |
381 | init_airo_card( link->irq.AssignedIRQ, | 351 | init_airo_card( link->irq.AssignedIRQ, |
382 | link->io.BasePort1, 1, &handle_to_dev(handle) ); | 352 | link->io.BasePort1, 1, &handle_to_dev(link) ); |
383 | if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; | 353 | if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; |
384 | 354 | ||
385 | /* | 355 | /* |
386 | At this point, the dev_node_t structure(s) need to be | 356 | At this point, the dev_node_t structure(s) need to be |
387 | initialized and arranged in a linked list at link->dev. | 357 | initialized and arranged in a linked list at link->dev_node. |
388 | */ | 358 | */ |
389 | strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); | 359 | strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); |
390 | dev->node.major = dev->node.minor = 0; | 360 | dev->node.major = dev->node.minor = 0; |
391 | link->dev = &dev->node; | 361 | link->dev_node = &dev->node; |
392 | 362 | ||
393 | /* Finally, report what we've done */ | 363 | /* Finally, report what we've done */ |
394 | printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", | 364 | printk(KERN_INFO "%s: index 0x%02x: ", |
395 | dev->node.dev_name, link->conf.ConfigIndex, | 365 | dev->node.dev_name, link->conf.ConfigIndex); |
396 | link->conf.Vcc/10, link->conf.Vcc%10); | 366 | if (link->conf.Vpp) |
397 | if (link->conf.Vpp1) | 367 | printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); |
398 | printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); | ||
399 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | 368 | if (link->conf.Attributes & CONF_ENABLE_IRQ) |
400 | printk(", irq %d", link->irq.AssignedIRQ); | 369 | printk(", irq %d", link->irq.AssignedIRQ); |
401 | if (link->io.NumPorts1) | 370 | if (link->io.NumPorts1) |
@@ -408,14 +377,12 @@ static void airo_config(dev_link_t *link) | |||
408 | printk(", mem 0x%06lx-0x%06lx", req.Base, | 377 | printk(", mem 0x%06lx-0x%06lx", req.Base, |
409 | req.Base+req.Size-1); | 378 | req.Base+req.Size-1); |
410 | printk("\n"); | 379 | printk("\n"); |
411 | 380 | return 0; | |
412 | link->state &= ~DEV_CONFIG_PENDING; | 381 | |
413 | return; | ||
414 | |||
415 | cs_failed: | 382 | cs_failed: |
416 | cs_error(link->handle, last_fn, last_ret); | 383 | cs_error(link, last_fn, last_ret); |
417 | airo_release(link); | 384 | airo_release(link); |
418 | 385 | return -ENODEV; | |
419 | } /* airo_config */ | 386 | } /* airo_config */ |
420 | 387 | ||
421 | /*====================================================================== | 388 | /*====================================================================== |
@@ -426,51 +393,26 @@ static void airo_config(dev_link_t *link) | |||
426 | 393 | ||
427 | ======================================================================*/ | 394 | ======================================================================*/ |
428 | 395 | ||
429 | static void airo_release(dev_link_t *link) | 396 | static void airo_release(struct pcmcia_device *link) |
430 | { | 397 | { |
431 | DEBUG(0, "airo_release(0x%p)\n", link); | 398 | DEBUG(0, "airo_release(0x%p)\n", link); |
432 | 399 | pcmcia_disable_device(link); | |
433 | /* Unlink the device chain */ | ||
434 | link->dev = NULL; | ||
435 | |||
436 | /* | ||
437 | In a normal driver, additional code may be needed to release | ||
438 | other kernel data structures associated with this device. | ||
439 | */ | ||
440 | |||
441 | /* Don't bother checking to see if these succeed or not */ | ||
442 | if (link->win) | ||
443 | pcmcia_release_window(link->win); | ||
444 | pcmcia_release_configuration(link->handle); | ||
445 | if (link->io.NumPorts1) | ||
446 | pcmcia_release_io(link->handle, &link->io); | ||
447 | if (link->irq.AssignedIRQ) | ||
448 | pcmcia_release_irq(link->handle, &link->irq); | ||
449 | link->state &= ~DEV_CONFIG; | ||
450 | } | 400 | } |
451 | 401 | ||
452 | static int airo_suspend(struct pcmcia_device *p_dev) | 402 | static int airo_suspend(struct pcmcia_device *link) |
453 | { | 403 | { |
454 | dev_link_t *link = dev_to_instance(p_dev); | ||
455 | local_info_t *local = link->priv; | 404 | local_info_t *local = link->priv; |
456 | 405 | ||
457 | link->state |= DEV_SUSPEND; | 406 | netif_device_detach(local->eth_dev); |
458 | if (link->state & DEV_CONFIG) { | ||
459 | netif_device_detach(local->eth_dev); | ||
460 | pcmcia_release_configuration(link->handle); | ||
461 | } | ||
462 | 407 | ||
463 | return 0; | 408 | return 0; |
464 | } | 409 | } |
465 | 410 | ||
466 | static int airo_resume(struct pcmcia_device *p_dev) | 411 | static int airo_resume(struct pcmcia_device *link) |
467 | { | 412 | { |
468 | dev_link_t *link = dev_to_instance(p_dev); | ||
469 | local_info_t *local = link->priv; | 413 | local_info_t *local = link->priv; |
470 | 414 | ||
471 | link->state &= ~DEV_SUSPEND; | 415 | if (link->open) { |
472 | if (link->state & DEV_CONFIG) { | ||
473 | pcmcia_request_configuration(link->handle, &link->conf); | ||
474 | reset_airo_card(local->eth_dev); | 416 | reset_airo_card(local->eth_dev); |
475 | netif_device_attach(local->eth_dev); | 417 | netif_device_attach(local->eth_dev); |
476 | } | 418 | } |
@@ -492,7 +434,7 @@ static struct pcmcia_driver airo_driver = { | |||
492 | .drv = { | 434 | .drv = { |
493 | .name = "airo_cs", | 435 | .name = "airo_cs", |
494 | }, | 436 | }, |
495 | .probe = airo_attach, | 437 | .probe = airo_probe, |
496 | .remove = airo_detach, | 438 | .remove = airo_detach, |
497 | .id_table = airo_ids, | 439 | .id_table = airo_ids, |
498 | .suspend = airo_suspend, | 440 | .suspend = airo_suspend, |