Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/pcmcia/nexus/pcmcia.c
+++ new/usr/src/uts/common/pcmcia/nexus/pcmcia.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * PCMCIA NEXUS
28 28 * The PCMCIA module is a generalized interface for
29 29 * implementing PCMCIA nexus drivers. It preserves
30 30 * the logical socket name space while allowing multiple
31 31 * instances of the hardware to be properly represented
32 32 * in the device tree.
33 33 *
34 34 * The nexus also exports events to an event manager
35 35 * driver if it has registered.
36 36 */
37 37
38 38 #include <sys/types.h>
39 39 #include <sys/systm.h>
40 40 #include <sys/user.h>
41 41 #include <sys/buf.h>
42 42 #include <sys/file.h>
43 43 #include <sys/uio.h>
44 44 #include <sys/conf.h>
45 45 #include <sys/stat.h>
46 46 #include <sys/autoconf.h>
47 47 #include <sys/vtoc.h>
48 48 #include <sys/dkio.h>
49 49 #include <sys/ddi.h>
50 50 #include <sys/debug.h>
51 51 #include <sys/sunddi.h>
52 52 #include <sys/sunndi.h>
53 53 #include <sys/cred.h>
54 54 #include <sys/kstat.h>
55 55 #include <sys/kmem.h>
56 56 #include <sys/modctl.h>
57 57 #include <sys/kobj.h>
58 58 #include <sys/callb.h>
59 59 #include <sys/param.h>
60 60 #include <sys/thread.h>
61 61 #include <sys/proc.h>
62 62
63 63 #include <sys/pctypes.h>
64 64 #include <sys/pcmcia.h>
65 65 #include <sys/sservice.h>
66 66 #include <pcmcia/sys/cs_types.h>
67 67 #include <pcmcia/sys/cis.h>
68 68 #include <pcmcia/sys/cis_handlers.h>
69 69 #include <pcmcia/sys/cs.h>
70 70 #include <pcmcia/sys/cs_priv.h>
71 71
72 72 #ifdef sparc
73 73 #include <sys/ddi_subrdefs.h>
74 74
75 75 #elif defined(__x86) || defined(__amd64)
76 76 #include <sys/mach_intr.h>
77 77 #endif
78 78
79 79 #undef SocketServices
80 80
81 81 /* some bus specific stuff */
82 82
83 83 /* need PCI regspec size for worst case at present */
84 84 #include <sys/pci.h>
85 85
86 86 typedef struct pcmcia_logical_socket {
87 87 int ls_socket; /* adapter's socket number */
88 88 uint32_t ls_flags;
89 89 struct pcmcia_adapter *ls_adapter;
90 90 pcmcia_if_t *ls_if;
91 91 dev_info_t *ls_sockdrv;
92 92 dev_info_t *ls_dip[PCMCIA_MAX_FUNCTIONS];
93 93 dev_info_t *ls_mfintr_dip;
94 94 int ls_functions;
95 95 uint32_t ls_cs_events;
96 96 uint32_t ls_intr_pri;
97 97 uint32_t ls_intr_vec;
98 98 int ls_intrrefs;
99 99 struct intrspec ls_intrspec; /* MFC intrspec */
100 100 inthandler_t *ls_inthandlers; /* for multifunction cards */
101 101 ddi_iblock_cookie_t ls_iblk;
102 102 ddi_idevice_cookie_t ls_idev;
103 103 kmutex_t ls_ilock;
104 104 int ls_error; /* error for CS return */
105 105 } pcmcia_logical_socket_t;
106 106
107 107 /*
108 108 * entry points used by the true nexus
109 109 */
110 110 int pcmcia_detach(dev_info_t *, ddi_detach_cmd_t);
111 111 int pcmcia_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
112 112 int pcmcia_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t,
113 113 int, char *, caddr_t, int *);
114 114 void pcmcia_set_assigned(dev_info_t *, int, ra_return_t *);
115 115 int pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
116 116 ddi_intr_handle_impl_t *hdlp, void *result);
117 117
118 118 /*
119 119 * prototypes used internally by the nexus and sometimes Card Services
120 120 */
121 121 int SocketServices(int function, ...);
122 122
123 123
124 124 void *CISParser(int function, ...);
125 125 extern void *(*cis_parser)(int, ...);
126 126
127 127 struct regspec *pcmcia_cons_regspec(dev_info_t *, int, uchar_t *,
128 128 ra_return_t *);
129 129
130 130 static int (*pcmcia_card_services)(int, ...) = NULL;
131 131
132 132 /*
133 133 * variables used in the logical/physical mappings
134 134 * that the nexus common code maintains.
135 135 */
136 136 struct pcmcia_adapter *pcmcia_adapters[PCMCIA_MAX_ADAPTERS];
137 137 int pcmcia_num_adapters;
138 138 pcmcia_logical_socket_t *pcmcia_sockets[PCMCIA_MAX_SOCKETS];
139 139 int pcmcia_num_sockets;
140 140 pcmcia_logical_window_t *pcmcia_windows[PCMCIA_MAX_WINDOWS];
141 141 int pcmcia_num_windows;
142 142 struct power_entry pcmcia_power_table[PCMCIA_MAX_POWER];
143 143 int pcmcia_num_power;
144 144
145 145 struct pcmcia_mif *pcmcia_mif_handlers = NULL;
146 146 pcm_dev_node_t *pcmcia_devnodes = NULL;
147 147
148 148 kmutex_t pcmcia_global_lock;
149 149 kcondvar_t pcmcia_condvar;
150 150 kmutex_t pcmcia_enum_lock;
151 151
152 152 /*
153 153 * Mapping of the device "type" to names acceptable to
154 154 * the DDI
155 155 */
156 156 static char *pcmcia_dev_type[] = {
157 157 "multifunction",
158 158 "byte",
159 159 "serial",
160 160 "parallel",
161 161 "block",
162 162 "display",
163 163 "network",
164 164 "block",
165 165 "byte"
166 166 };
167 167
168 168 char *pcmcia_default_pm_mode = "parental-suspend-resume";
169 169
170 170 /*
171 171 * generic names from the approved list:
172 172 * disk tape pci sbus scsi token-ring isa keyboard display mouse
173 173 * audio ethernet timer memory parallel serial rtc nvram scanner
174 174 * floppy(controller) fddi isdn atm ide pccard video-in video-out
175 175 * in some cases there will need to be device class dependent names.
176 176 * network -> ethernet, token-ring, etc.
177 177 * this list is a first guess and is used when all else fails.
178 178 */
179 179
180 180 char *pcmcia_generic_names[] = {
181 181 "multifunction",
182 182 "memory",
183 183 "serial",
184 184 "parallel",
185 185 "disk",
186 186 "video", /* no spec for video-out yet */
187 187 "network",
188 188 "aims",
189 189 "scsi",
190 190 "security"
191 191 };
192 192
193 193 #define PCM_GENNAME_SIZE (sizeof (pcmcia_generic_names) / \
194 194 sizeof (char *))
195 195 #define PCMCIA_MAP_IO 0x0
196 196 #define PCMCIA_MAP_MEM 0x1
197 197 #define PPB_SUBTRACTIVE ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \
198 198 (PCI_BRIDGE_PCI_IF_SUBDECODE))
199 199
200 200 /*
201 201 * The following should be 2^^n - 1
202 202 */
203 203 #define PCMCIA_SOCKET_BITS 0x7f
204 204
205 205 #ifdef PCMCIA_DEBUG
206 206 int pcmcia_debug = 0x0;
207 207 static void pcmcia_dump_minors(dev_info_t *);
208 208 #endif
209 209
210 210 static f_tt *pcmcia_cs_event = NULL;
211 211 int pcmcia_timer_id;
212 212 dev_info_t *pcmcia_dip;
213 213 /*
214 214 * XXX - See comments in cs.c
215 215 */
216 216 static f_tt *pcmcia_cis_parser = NULL;
217 217
218 218 extern struct pc_socket_services pc_socket_services;
219 219
220 220 /* some function declarations */
221 221 static int pcm_adapter_callback(dev_info_t *, int, int, int);
222 222 extern void pcmcia_init_adapter(anp_t *, dev_info_t *);
223 223 extern void pcmcia_find_cards(anp_t *);
224 224 extern void pcmcia_merge_power(struct power_entry *);
225 225 extern void pcmcia_do_resume(int, pcmcia_logical_socket_t *);
226 226 extern void pcmcia_resume(int, pcmcia_logical_socket_t *);
227 227 extern void pcmcia_do_suspend(int, pcmcia_logical_socket_t *);
228 228 extern void pcm_event_manager(int, int, void *);
229 229 static void pcmcia_create_dev_info(int);
230 230 static int pcmcia_create_device(ss_make_device_node_t *);
231 231 static void pcmcia_init_devinfo(dev_info_t *, struct pcm_device_info *);
232 232 void pcmcia_fix_string(char *str);
233 233 dev_info_t *pcmcia_number_socket(dev_info_t *, int);
234 234 static int pcmcia_merge_conf(dev_info_t *);
235 235 static uint32_t pcmcia_mfc_intr(caddr_t, caddr_t);
236 236 void pcmcia_free_resources(dev_info_t *);
237 237 static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd);
238 238 int pcmcia_get_intr(dev_info_t *, int);
239 239 int pcmcia_return_intr(dev_info_t *, int);
240 240 int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *,
241 241 dev_info_t **);
242 242 int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *);
243 243
244 244 extern int cs_init(void);
245 245 extern int cs_deinit(void);
246 246 extern void cisp_init(void);
247 247 extern void cis_deinit(void);
248 248
249 249 /*
250 250 * non-DDI compliant functions are listed here
251 251 * some will be declared while others that have
252 252 * entries in .h files. All will be commented on.
253 253 *
254 254 * with declarations:
255 255 * ddi_add_child
256 256 * ddi_binding_name
257 257 * ddi_bus_prop_op
258 258 * ddi_ctlops
259 259 * ddi_find_devinfo
260 260 * ddi_get_name_addr
261 261 * ddi_get_parent_data
262 262 * ddi_hold_installed_driver
263 263 * ddi_name_to_major
264 264 * ddi_node_name
265 265 * ddi_pathname
266 266 * ddi_rele_driver
267 267 * ddi_set_name_addr
268 268 * ddi_set_parent_data
269 269 * ddi_unorphan_devs
270 270 * i_ddi_bind_node_to_driver
271 271 * i_ddi_bind_node_to_driver
272 272 * i_ddi_bus_map
273 273 * i_ddi_map_fault
274 274 * i_ddi_mem_alloc
275 275 * i_ddi_mem_alloc
276 276 * i_ddi_mem_free
277 277 * i_ddi_mem_free
278 278 * modload
279 279 * modunload
280 280 */
281 281
282 282 extern void ddi_unorphan_devs(major_t);
283 283
284 284 /* Card&Socket Services entry points */
285 285 static int GetCookiesAndDip(sservice_t *);
286 286 static int SSGetAdapter(get_adapter_t *);
287 287 static int SSGetPage(get_page_t *);
288 288 static int SSGetSocket(get_socket_t *);
289 289 static int SSGetStatus(get_ss_status_t *);
290 290 static int SSGetWindow(get_window_t *);
291 291 static int SSInquireAdapter(inquire_adapter_t *);
292 292 static int SSInquireSocket(inquire_socket_t *);
293 293 static int SSInquireWindow(inquire_window_t *);
294 294 static int SSResetSocket(int, int);
295 295 static int SSSetPage(set_page_t *);
296 296 static int SSSetSocket(set_socket_t *);
↓ open down ↓ |
296 lines elided |
↑ open up ↑ |
297 297 static int SSSetWindow(set_window_t *);
298 298 static int SSSetIRQHandler(set_irq_handler_t *);
299 299 static int SSClearIRQHandler(clear_irq_handler_t *);
300 300
301 301 static struct modldrv modlmisc = {
302 302 &mod_miscops, /* Type of module. This one is a driver */
303 303 "PCMCIA Nexus Support", /* Name of the module. */
304 304 };
305 305
306 306 static struct modlinkage modlinkage = {
307 - MODREV_1, (void *)&modlmisc, NULL
307 + MODREV_1, { (void *)&modlmisc, NULL }
308 308 };
309 309
310 310 int
311 311 _init()
312 312 {
313 313 int ret;
314 314
315 315 cisp_init();
316 316
317 317 if (cs_init() != CS_SUCCESS) {
318 318 if (cs_deinit() != CS_SUCCESS)
319 319 cmn_err(CE_CONT, "pcmcia: _init cs_deinit error\n");
320 320 return (-1);
321 321 }
322 322
323 323 mutex_init(&pcmcia_global_lock, NULL, MUTEX_DEFAULT, NULL);
324 324 cv_init(&pcmcia_condvar, NULL, CV_DRIVER, NULL);
325 325 mutex_init(&pcmcia_enum_lock, NULL, MUTEX_DEFAULT, NULL);
326 326
327 327 if ((ret = mod_install(&modlinkage)) != 0) {
328 328 mutex_destroy(&pcmcia_global_lock);
329 329 cv_destroy(&pcmcia_condvar);
330 330 mutex_destroy(&pcmcia_enum_lock);
331 331 }
332 332 return (ret);
333 333 }
334 334
335 335 int
336 336 _fini()
337 337 {
338 338 int ret;
339 339
340 340 if ((ret = mod_remove(&modlinkage)) == 0) {
341 341 mutex_destroy(&pcmcia_global_lock);
342 342 cv_destroy(&pcmcia_condvar);
343 343 mutex_destroy(&pcmcia_enum_lock);
344 344 cis_deinit();
345 345 if (cs_deinit() != CS_SUCCESS) {
346 346 cmn_err(CE_CONT, "pcmcia: _fini cs_deinit error\n");
347 347 }
348 348 }
349 349 return (ret);
350 350 }
351 351
352 352 int
353 353 _info(struct modinfo *modinfop)
354 354 {
355 355 return (mod_info(&modlinkage, modinfop));
356 356 }
357 357
358 358 extern pri_t minclsyspri;
359 359
360 360 /*
361 361 * pcmcia_attach()
362 362 * the attach routine must make sure that everything needed is present
363 363 * including real hardware. The sequence of events is:
364 364 * attempt to load all adapter drivers
365 365 * attempt to load Card Services
366 366 * initialize logical sockets
367 367 * report the nexus exists
368 368 */
369 369
370 370 int
371 371 pcmcia_attach(dev_info_t *dip, anp_t *adapter)
372 372 {
373 373 int count, done, i;
374 374
375 375 #if defined(PCMCIA_DEBUG)
376 376 if (pcmcia_debug) {
377 377 cmn_err(CE_CONT, "pcmcia_attach: dip=0x%p adapter=0x%p\n",
378 378 (void *)dip, (void *)adapter);
379 379 }
380 380 #endif
381 381
382 382 pcmcia_dip = dip;
383 383
384 384 mutex_enter(&pcmcia_enum_lock);
385 385 mutex_enter(&pcmcia_global_lock);
386 386 if (pcmcia_num_adapters == 0) {
387 387 pcmcia_cis_parser = (f_tt *)CISParser;
388 388 cis_parser = (void *(*)(int, ...)) CISParser;
389 389 pcmcia_cs_event = (f_tt *)cs_event;
390 390 cs_socket_services = SocketServices;
391 391 /* tell CS we are up with basic init level */
392 392 (void) cs_event(PCE_SS_INIT_STATE, PCE_SS_STATE_INIT, 0);
393 393 }
394 394
395 395 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
396 396 PCM_DEVICETYPE, "pccard");
397 397
398 398 ddi_report_dev(dip); /* directory/device naming */
399 399
400 400 /*
401 401 * now setup any power management stuff necessary.
402 402 * we do it here in order to ensure that all PC Card nexi
403 403 * implement it.
404 404 */
405 405
406 406 if (pm_create_components(dip, 1) != DDI_SUCCESS) {
407 407 cmn_err(CE_WARN, "%s: not power managed\n",
408 408 ddi_get_name_addr(dip));
409 409 } else {
410 410 pm_set_normal_power(dip, 0, 1);
411 411 }
412 412
413 413 /*
414 414 * setup the info necessary for Card Services/SocketServices
415 415 * and notify CS when ready.
416 416 */
417 417
418 418 pcmcia_free_resources(dip);
419 419 pcmcia_init_adapter(adapter, dip);
420 420 /* exit mutex so CS can run for any cards found */
421 421 mutex_exit(&pcmcia_global_lock);
422 422
423 423 /*
424 424 * make sure the devices are identified before
425 425 * returning. We do this by checking each socket to see if
426 426 * a card is present. If there is one, and there isn't a dip,
427 427 * we can't be done. We scan the list of sockets doing the
428 428 * check. if we aren't done, wait for a condition variable to
429 429 * wakeup.
430 430 * Because we can miss a wakeup and because things can
431 431 * take time, we do eventually give up and have a timeout.
432 432 */
433 433
434 434 for (count = 0, done = 0;
435 435 done == 0 && count < max(pcmcia_num_sockets, 16);
436 436 count++) {
437 437 done = 1;
438 438 /* block CS while checking so we don't miss anything */
439 439 mutex_enter(&pcmcia_global_lock);
440 440 for (i = 0; i < pcmcia_num_sockets; i++) {
441 441 get_ss_status_t status;
442 442 if (pcmcia_sockets[i] == NULL)
443 443 continue;
444 444 bzero(&status, sizeof (status));
445 445 status.socket = i;
446 446 if (SSGetStatus(&status) == SUCCESS) {
447 447 if (status.CardState & SBM_CD &&
448 448 pcmcia_sockets[i]->ls_dip[0] == NULL) {
449 449 done = 0;
450 450 }
451 451 }
452 452 }
453 453 /* only wait if we aren't done with this set */
454 454 if (!done) {
455 455 mutex_exit(&pcmcia_global_lock);
456 456 delay(10); /* give up CPU for a time */
457 457 mutex_enter(&pcmcia_global_lock);
458 458 }
459 459 mutex_exit(&pcmcia_global_lock);
460 460 }
461 461
462 462 mutex_exit(&pcmcia_enum_lock);
463 463 return (DDI_SUCCESS);
464 464 }
465 465
466 466 /*
467 467 * pcmcia_detach
468 468 * unload everything and then detach the nexus
469 469 */
470 470 /* ARGSUSED */
471 471 int
472 472 pcmcia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
473 473 {
474 474 switch (cmd) {
475 475 case DDI_DETACH:
476 476 pm_destroy_components(dip);
477 477 return (DDI_SUCCESS);
478 478
479 479 /*
480 480 * resume from a checkpoint
481 481 * We don't do anything special here since the adapter
482 482 * driver will generate resume events that we intercept
483 483 * and convert to insert events.
484 484 */
485 485 case DDI_SUSPEND:
486 486 case DDI_PM_SUSPEND:
487 487 return (DDI_SUCCESS);
488 488
489 489 default:
490 490 return (DDI_FAILURE);
491 491 }
492 492 }
493 493
494 494 /*
495 495 * card_services_error()
496 496 * used to make 2.4/2.5 drivers get an error when
497 497 * they try to initialize.
498 498 */
499 499 static int
500 500 card_services_error()
501 501 {
502 502 return (CS_BAD_VERSION);
503 503 }
504 504 static int (*cs_error_ptr)() = card_services_error;
505 505
506 506 /*
507 507 * pcmcia_ctlops
508 508 * handle the nexus control operations for the cases where
509 509 * a PC Card driver gets called and we need to modify the
510 510 * devinfo structure or otherwise do bus specific operations
511 511 */
512 512 int
513 513 pcmcia_ctlops(dev_info_t *dip, dev_info_t *rdip,
514 514 ddi_ctl_enum_t ctlop, void *arg, void *result)
515 515 {
516 516 int e;
517 517 char name[64];
518 518 struct pcmcia_parent_private *ppd;
519 519 power_req_t *pm;
520 520
521 521 #if defined(PCMCIA_DEBUG)
522 522 if (pcmcia_debug) {
523 523 cmn_err(CE_CONT, "pcmcia_ctlops(%p, %p, %d, %p, %p)\n",
524 524 (void *)dip, (void *)rdip, ctlop, (void *)arg,
525 525 (void *)result);
526 526 if (rdip != NULL && ddi_get_name(rdip) != NULL)
527 527 cmn_err(CE_CONT, "\t[%s]\n", ddi_get_name(rdip));
528 528 }
529 529 #endif
530 530
531 531 switch (ctlop) {
532 532 case DDI_CTLOPS_REPORTDEV:
533 533 if (rdip == (dev_info_t *)0)
534 534 return (DDI_FAILURE);
535 535
536 536 if (strcmp("pcs", ddi_node_name(rdip)) == 0)
537 537 cmn_err(CE_CONT, "?PCCard socket %d at %s@%s\n",
538 538 ddi_get_instance(rdip),
539 539 ddi_driver_name(dip), ddi_get_name_addr(dip));
540 540 else
541 541 cmn_err(CE_CONT, "?%s%d at %s@%s in socket %d\n",
542 542 ddi_driver_name(rdip),
543 543 ddi_get_instance(rdip),
544 544 ddi_driver_name(dip),
545 545 ddi_get_name_addr(dip),
546 546 CS_GET_SOCKET_NUMBER(
547 547 ddi_getprop(DDI_DEV_T_NONE, rdip,
548 548 DDI_PROP_DONTPASS,
549 549 PCM_DEV_SOCKET, -1)));
550 550
551 551 return (DDI_SUCCESS);
552 552
553 553 case DDI_CTLOPS_INITCHILD:
554 554 /*
555 555 * we get control here before the child is called.
556 556 * we can change things if necessary. This is where
557 557 * the CardServices hook gets planted.
558 558 */
559 559 #if defined(PCMCIA_DEBUG)
560 560 if (pcmcia_debug) {
561 561 cmn_err(CE_CONT, "pcmcia: init child: %s(%d) @%p\n",
562 562 ddi_node_name(arg), ddi_get_instance(arg),
563 563 (void *)arg);
564 564 if (DEVI(arg)->devi_binding_name != NULL)
565 565 cmn_err(CE_CONT, "\tbinding_name=%s\n",
566 566 DEVI(arg)->devi_binding_name);
567 567 if (DEVI(arg)->devi_node_name != NULL)
568 568 cmn_err(CE_CONT, "\tnode_name=%s\n",
569 569 DEVI(arg)->devi_node_name);
570 570 }
571 571 #endif
572 572
573 573 ppd = (struct pcmcia_parent_private *)
574 574 ddi_get_parent_data((dev_info_t *)arg);
575 575 if (ppd == NULL)
576 576 return (DDI_FAILURE);
577 577
578 578 if (strcmp("pcs", ddi_node_name((dev_info_t *)arg)) == 0) {
579 579 if (ppd == NULL)
580 580 return (DDI_FAILURE);
581 581 (void) sprintf(name, "%x",
582 582 (int)ppd->ppd_reg[0].phys_hi);
583 583 ddi_set_name_addr((dev_info_t *)arg, name);
584 584 return (DDI_SUCCESS);
585 585 }
586 586
587 587 /*
588 588 * We don't want driver.conf files that stay in
589 589 * pseudo device form. It is acceptable to have
590 590 * .conf files add properties only.
591 591 */
592 592 if (ndi_dev_is_persistent_node((dev_info_t *)arg) == 0) {
593 593 (void) pcmcia_merge_conf((dev_info_t *)arg);
594 594 cmn_err(CE_WARN, "%s%d: %s.conf invalid",
595 595 ddi_get_name((dev_info_t *)arg),
596 596 ddi_get_instance((dev_info_t *)arg),
597 597 ddi_get_name((dev_info_t *)arg));
598 598 return (DDI_FAILURE);
599 599 }
600 600
601 601
602 602 #if defined(PCMCIA_DEBUG)
603 603 if (pcmcia_debug && ppd != NULL) {
604 604 cmn_err(CE_CONT, "\tnreg=%x, intr=%x, socket=%x,"
605 605 " function=%x, active=%x, flags=%x\n",
606 606 ppd->ppd_nreg, ppd->ppd_intr,
607 607 ppd->ppd_socket, ppd->ppd_function,
608 608 ppd->ppd_active, ppd->ppd_flags);
609 609 }
610 610 #endif
611 611
612 612 /*
613 613 * make sure names are relative to socket number
614 614 */
615 615 if (ppd->ppd_function > 0) {
616 616 int sock;
617 617 int func;
618 618 sock = ppd->ppd_socket;
619 619 func = ppd->ppd_function;
620 620 (void) sprintf(name, "%x,%x", sock, func);
621 621 } else {
622 622 (void) sprintf(name, "%x", ppd->ppd_socket);
623 623 }
624 624 ddi_set_name_addr((dev_info_t *)arg, name);
625 625
626 626 #if defined(PCMCIA_DEBUG)
627 627 if (pcmcia_debug)
628 628 cmn_err(CE_CONT, "pcmcia: system init done for %s [%s] "
629 629 "nodeid: %x @%s\n",
630 630 ddi_get_name(arg), ddi_get_name_addr(arg),
631 631 DEVI(arg)->devi_nodeid, name);
632 632 if (pcmcia_debug > 1)
633 633 pcmcia_dump_minors((dev_info_t *)arg);
634 634 #endif
635 635
636 636 return (DDI_SUCCESS);
637 637
638 638 case DDI_CTLOPS_UNINITCHILD:
639 639
640 640 #if defined(PCMCIA_DEBUG)
641 641 if (pcmcia_debug) {
642 642 cmn_err(CE_CONT, "pcmcia: uninit child: %s(%d) @%p\n",
643 643 ddi_node_name(arg), ddi_get_instance(arg),
644 644 (void *)arg);
645 645 if (DEVI(arg)->devi_binding_name != NULL)
646 646 cmn_err(CE_CONT, "\tbinding_name=%s\n",
647 647 DEVI(arg)->devi_binding_name);
648 648 if (DEVI(arg)->devi_node_name != NULL)
649 649 cmn_err(CE_CONT, "\tnode_name=%s\n",
650 650 DEVI(arg)->devi_node_name);
651 651 }
652 652 #endif
653 653
654 654 ddi_set_name_addr((dev_info_t *)arg, NULL);
655 655 ddi_remove_minor_node((dev_info_t *)arg, NULL);
656 656 return (DDI_SUCCESS);
657 657
658 658 case DDI_CTLOPS_SLAVEONLY:
659 659 /* PCMCIA devices can't ever be busmaster until CardBus */
660 660 ppd = (struct pcmcia_parent_private *)
661 661 ddi_get_parent_data(rdip);
662 662 if (ppd != NULL && ppd->ppd_flags & PPD_CB_BUSMASTER)
663 663 return (DDI_FAILURE); /* at most */
664 664 return (DDI_SUCCESS);
665 665
666 666 case DDI_CTLOPS_SIDDEV:
667 667 /* in general this is true. */
668 668 return (DDI_SUCCESS);
669 669
670 670 case DDI_CTLOPS_NREGS:
671 671 ppd = (struct pcmcia_parent_private *)
672 672 ddi_get_parent_data(rdip);
673 673 if (ppd != NULL)
674 674 *((uint32_t *)result) = (ppd->ppd_nreg);
675 675 else
676 676 *((uint32_t *)result) = 0;
677 677 return (DDI_SUCCESS);
678 678
679 679 case DDI_CTLOPS_REGSIZE:
680 680 ppd = (struct pcmcia_parent_private *)
681 681 ddi_get_parent_data(rdip);
682 682 if (ppd != NULL && ppd->ppd_nreg > 0)
683 683 *((off_t *)result) = sizeof (struct pcm_regs);
684 684 else
685 685 *((off_t *)result) = 0;
686 686 return (DDI_SUCCESS);
687 687
688 688 case DDI_CTLOPS_POWER:
689 689 ppd = (struct pcmcia_parent_private *)
690 690 ddi_get_parent_data(rdip);
691 691
692 692 if (ppd == NULL)
693 693 return (DDI_FAILURE);
694 694 /*
695 695 * if this is not present, don't bother (claim success)
696 696 * since it is already in the right state. Don't
697 697 * do any resume either since the card insertion will
698 698 * happen independently.
699 699 */
700 700 if (!ppd->ppd_active)
701 701 return (DDI_SUCCESS);
702 702 for (e = 0; e < pcmcia_num_adapters; e++)
703 703 if (pcmcia_adapters[e] ==
704 704 pcmcia_sockets[ppd->ppd_socket]->ls_adapter)
705 705 break;
706 706 if (e == pcmcia_num_adapters)
707 707 return (DDI_FAILURE);
708 708 pm = (power_req_t *)arg;
709 709 #if defined(PCMCIA_DEBUG)
710 710 if (pcmcia_debug) {
711 711 cmn_err(CE_WARN, "power: %d: %p, %d, %d [%s]\n",
712 712 pm->request_type,
713 713 (void *)pm->req.set_power_req.who,
714 714 pm->req.set_power_req.cmpt,
715 715 pm->req.set_power_req.level,
716 716 ddi_get_name_addr(rdip));
717 717 }
718 718 #endif
719 719 e = ppd->ppd_socket;
720 720 switch (pm->request_type) {
721 721 case PMR_SUSPEND:
722 722 if (!(pcmcia_sockets[e]->ls_flags &
723 723 PCS_SUSPENDED)) {
724 724 pcmcia_do_suspend(ppd->ppd_socket,
725 725 pcmcia_sockets[e]);
726 726 }
727 727 ppd->ppd_flags |= PPD_SUSPENDED;
728 728 return (DDI_SUCCESS);
729 729 case PMR_RESUME:
730 730 /* for now, we just succeed since the rest is done */
731 731 return (DDI_SUCCESS);
732 732 case PMR_SET_POWER:
733 733 /*
734 734 * not sure how to handle power control
735 735 * for now, we let the child handle it itself
736 736 */
737 737 (void) pcmcia_power(pm->req.set_power_req.who,
738 738 pm->req.set_power_req.cmpt,
739 739 pm->req.set_power_req.level);
740 740 break;
741 741 default:
742 742 break;
743 743 }
744 744 return (DDI_FAILURE);
745 745 /* These CTLOPS will need to be implemented for new form */
746 746 /* let CardServices know about this */
747 747 case DDI_CTLOPS_DETACH:
748 748 return (DDI_SUCCESS);
749 749 case DDI_CTLOPS_ATTACH:
750 750 return (DDI_SUCCESS);
751 751
752 752 default:
753 753 /* if we don't understand, pass up the tree */
754 754 /* most things default to general ops */
755 755 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
756 756 }
757 757 }
758 758
759 759 struct pcmcia_props {
760 760 char *name;
761 761 int len;
762 762 int prop;
763 763 } pcmcia_internal_props[] = {
764 764 { PCM_DEV_ACTIVE, 0, PCMCIA_PROP_ACTIVE },
765 765 { PCM_DEV_R2TYPE, 0, PCMCIA_PROP_R2TYPE },
766 766 { PCM_DEV_CARDBUS, 0, PCMCIA_PROP_CARDBUS },
767 767 { CS_PROP, sizeof (void *), PCMCIA_PROP_OLDCS },
768 768 { "reg", 0, PCMCIA_PROP_REG },
769 769 { "interrupts", sizeof (int), PCMCIA_PROP_INTR },
770 770 { "pm-hardware-state", 0, PCMCIA_PROP_DEFAULT_PM },
771 771 };
772 772
773 773 /*
774 774 * pcmcia_prop_decode(name)
775 775 * decode the name and determine if this is a property
776 776 * we construct on the fly, one we have on the prop list
777 777 * or one that requires calling the CIS code.
778 778 */
779 779 static int
780 780 pcmcia_prop_decode(char *name)
781 781 {
782 782 int i;
783 783 if (strncmp(name, "cistpl_", 7) == 0)
784 784 return (PCMCIA_PROP_CIS);
785 785
786 786 for (i = 0; i < (sizeof (pcmcia_internal_props) /
787 787 sizeof (struct pcmcia_props)); i++) {
788 788 if (strcmp(name, pcmcia_internal_props[i].name) == 0)
789 789 return (i);
790 790 }
791 791
792 792 return (PCMCIA_PROP_UNKNOWN);
793 793 }
794 794
795 795 /*
796 796 * pcmcia_prop_op()
797 797 * we don't have properties in PROM per se so look for them
798 798 * only in the devinfo node. Future may allow us to find
799 799 * certain CIS tuples via this interface if a user asks for
800 800 * a property of the form "cistpl-<tuplename>" but not yet.
801 801 *
802 802 * The addition of 1275 properties adds to the necessity.
803 803 */
804 804 int
805 805 pcmcia_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
806 806 ddi_prop_op_t prop_op, int mod_flags,
807 807 char *name, caddr_t valuep, int *lengthp)
808 808 {
809 809 int len, proplen, which, flags;
810 810 caddr_t buff, propptr;
811 811 struct pcmcia_parent_private *ppd;
812 812
813 813 len = *lengthp;
814 814 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(ch_dip);
815 815
816 816 switch (which = pcmcia_prop_decode(name)) {
817 817 default:
818 818 if (ppd == NULL)
819 819 return (DDI_PROP_NOT_FOUND);
820 820
821 821 /* note that proplen may get modified */
822 822 proplen = pcmcia_internal_props[which].len;
823 823 switch (pcmcia_internal_props[which].prop) {
824 824 case PCMCIA_PROP_DEFAULT_PM:
825 825 propptr = pcmcia_default_pm_mode;
826 826 proplen = strlen(propptr) + 1;
827 827 break;
828 828 case PCMCIA_PROP_OLDCS:
829 829 propptr = (caddr_t)&cs_error_ptr;
830 830 break;
831 831 case PCMCIA_PROP_REG:
832 832 propptr = (caddr_t)ppd->ppd_reg;
833 833 proplen = ppd->ppd_nreg * sizeof (struct pcm_regs);
834 834 break;
835 835 case PCMCIA_PROP_INTR:
836 836 propptr = (caddr_t)&ppd->ppd_intr;
837 837 break;
838 838
839 839 /* the next set are boolean values */
840 840 case PCMCIA_PROP_ACTIVE:
841 841 propptr = NULL;
842 842 if (!ppd->ppd_active) {
843 843 return (DDI_PROP_NOT_FOUND);
844 844 }
845 845 break;
846 846 case PCMCIA_PROP_R2TYPE:
847 847 propptr = NULL;
848 848 if (ppd->ppd_flags & PPD_CARD_CARDBUS)
849 849 return (DDI_PROP_NOT_FOUND);
850 850 break;
851 851 case PCMCIA_PROP_CARDBUS:
852 852 propptr = NULL;
853 853 if (!(ppd->ppd_flags * PPD_CARD_CARDBUS))
854 854 return (DDI_PROP_NOT_FOUND);
855 855 break;
856 856 }
857 857
858 858 break;
859 859
860 860 case PCMCIA_PROP_CIS:
861 861 /*
862 862 * once we have the lookup code in place
863 863 * it is sufficient to break out of the switch
864 864 * once proplen and propptr are set.
865 865 * The common prop_op code deals with the rest.
866 866 */
867 867 case PCMCIA_PROP_UNKNOWN:
868 868 return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
869 869 mod_flags | DDI_PROP_NOTPROM,
870 870 name, valuep, lengthp));
871 871 }
872 872
873 873 if (prop_op == PROP_LEN) {
874 874 /* just the length */
875 875 *lengthp = proplen;
876 876 return (DDI_PROP_SUCCESS);
877 877 }
878 878 switch (prop_op) {
879 879 case PROP_LEN_AND_VAL_ALLOC:
880 880 if (mod_flags & DDI_PROP_CANSLEEP)
881 881 flags = KM_SLEEP;
882 882 else
883 883 flags = KM_NOSLEEP;
884 884 buff = kmem_alloc((size_t)proplen, flags);
885 885 if (buff == NULL)
886 886 return (DDI_PROP_NO_MEMORY);
887 887 *(caddr_t *)valuep = (caddr_t)buff;
888 888 break;
889 889 case PROP_LEN_AND_VAL_BUF:
890 890 buff = (caddr_t)valuep;
891 891 if (len < proplen)
892 892 return (DDI_PROP_BUF_TOO_SMALL);
893 893 break;
894 894 default:
895 895 break;
896 896 }
897 897
898 898 if (proplen > 0)
899 899 bcopy(propptr, buff, proplen);
900 900 *lengthp = proplen;
901 901 return (DDI_PROP_SUCCESS);
902 902 }
903 903
904 904
905 905 struct regspec *
906 906 pcmcia_rnum_to_regspec(dev_info_t *dip, int rnumber)
907 907 {
908 908 struct pcmcia_parent_private *ppd;
909 909 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
910 910 if (ppd->ppd_nreg < rnumber)
911 911 return (NULL);
912 912 return ((struct regspec *)&ppd->ppd_reg[rnumber]);
913 913 }
914 914
915 915 struct regspec *
916 916 pcmcia_rnum_to_mapped(dev_info_t *dip, int rnumber)
917 917 {
918 918 struct pcmcia_parent_private *ppd;
919 919 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
920 920 if (ppd->ppd_nreg < rnumber)
921 921 return (NULL);
922 922 if (ppd->ppd_assigned == NULL)
923 923 return (NULL);
924 924 if (ppd->ppd_assigned[rnumber].phys_len == 0)
925 925 return (NULL);
926 926 else
927 927 return ((struct regspec *)&ppd->ppd_assigned[rnumber]);
928 928 }
929 929
930 930 int
931 931 pcmcia_find_rnum(dev_info_t *dip, struct regspec *reg)
932 932 {
933 933 struct pcmcia_parent_private *ppd;
934 934 struct regspec *regp;
935 935 int i;
936 936
937 937 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
938 938 if (ppd == NULL)
939 939 return (-1);
940 940 for (regp = (struct regspec *)ppd->ppd_reg, i = 0;
941 941 i < ppd->ppd_nreg; i++, regp++) {
942 942 if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
943 943 return (i);
944 944 }
945 945 for (regp = (struct regspec *)ppd->ppd_assigned, i = 0;
946 946 i < ppd->ppd_nreg; i++, regp++) {
947 947 if (bcmp(reg, regp, sizeof (struct regspec)) == 0)
948 948 return (i);
949 949 }
950 950
951 951 return (-1);
952 952 }
953 953
954 954 int
955 955 pcmcia_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
956 956 off_t offset, off_t len, caddr_t *vaddrp)
957 957 {
958 958 struct pcm_regs *regs, *mregs = NULL, tmp_reg;
959 959 ddi_map_req_t mr = *mp;
960 960 ra_return_t ret;
961 961 int check, rnum = -1;
962 962 uint32_t base;
963 963 uchar_t regbuf[sizeof (pci_regspec_t)];
964 964
965 965 mp = &mr; /* a copy of original request */
966 966
967 967 /* check for register number */
968 968 switch (mp->map_type) {
969 969 case DDI_MT_REGSPEC:
970 970 regs = (struct pcm_regs *)mp->map_obj.rp;
971 971 mregs = (struct pcm_regs *)mp->map_obj.rp;
972 972 /*
973 973 * when using regspec, must not be relocatable
974 974 * and should be from assigned space.
975 975 */
976 976 if (!PC_REG_RELOC(regs->phys_hi))
977 977 return (DDI_FAILURE);
978 978 rnum = pcmcia_find_rnum(rdip, (struct regspec *)mregs);
979 979 break;
980 980 case DDI_MT_RNUMBER:
981 981 regs = (struct pcm_regs *)
982 982 pcmcia_rnum_to_regspec(rdip, mp->map_obj.rnumber);
983 983 mregs = (struct pcm_regs *)
984 984 pcmcia_rnum_to_mapped(rdip, mp->map_obj.rnumber);
985 985 rnum = mp->map_obj.rnumber;
986 986 if (regs == NULL)
987 987 return (DDI_FAILURE);
988 988 mp->map_type = DDI_MT_REGSPEC;
989 989 mp->map_obj.rp = (struct regspec *)mregs;
990 990 break;
991 991 default:
992 992 return (DDI_ME_INVAL);
993 993 }
994 994
995 995 /* basic sanity checks */
996 996 switch (mp->map_op) {
997 997 default:
998 998 return (DDI_ME_UNIMPLEMENTED);
999 999 case DDI_MO_UNMAP:
1000 1000 if (mregs == NULL)
1001 1001 return (DDI_FAILURE);
1002 1002 regs = mregs;
1003 1003 break;
1004 1004 case DDI_MO_MAP_LOCKED:
1005 1005 case DDI_MO_MAP_HANDLE:
1006 1006 panic("unsupported bus operation");
1007 1007 /*NOTREACHED*/
1008 1008 }
1009 1009
1010 1010 /*
1011 1011 * we need a private copy for manipulation and
1012 1012 * calculation of the correct ranges
1013 1013 */
1014 1014 tmp_reg = *regs;
1015 1015 mp->map_obj.rp = (struct regspec *)(regs = &tmp_reg);
1016 1016 base = regs->phys_lo;
1017 1017 if (base == 0 && offset != 0) {
1018 1018 /*
1019 1019 * for now this is an error. What does it really mean
1020 1020 * to ask for an offset from an address that hasn't
1021 1021 * been allocated yet.
1022 1022 */
1023 1023 return (DDI_ME_INVAL);
1024 1024 }
1025 1025 regs->phys_lo += (uint32_t)offset;
1026 1026 if (len != 0) {
1027 1027 if (len > regs->phys_len) {
1028 1028 return (DDI_ME_INVAL);
1029 1029 }
1030 1030 regs->phys_len = len;
1031 1031 }
1032 1032
1033 1033 /*
1034 1034 * basic sanity is checked so now make sure
1035 1035 * we can actually allocate something for this
1036 1036 * request and then convert to a "standard"
1037 1037 * regspec for the next layer up (pci/isa/rootnex/etc.)
1038 1038 */
1039 1039
1040 1040 switch (PC_GET_REG_TYPE(regs->phys_hi)) {
1041 1041 case PC_REG_SPACE_IO:
1042 1042 check = PCA_RES_NEED_IO;
1043 1043 break;
1044 1044 case PC_REG_SPACE_MEMORY:
1045 1045 check = PCA_RES_NEED_MEM;
1046 1046 break;
1047 1047 default:
1048 1048 /* not a valid register type */
1049 1049 return (DDI_FAILURE);
1050 1050 }
1051 1051
1052 1052 mr.map_type = DDI_MT_REGSPEC;
1053 1053 ret.ra_addr_hi = 0;
1054 1054 ret.ra_addr_lo = regs->phys_lo;
1055 1055 ret.ra_len = regs->phys_len;
1056 1056 mr.map_obj.rp = pcmcia_cons_regspec(dip,
1057 1057 (check == PCA_RES_NEED_IO) ?
1058 1058 PCMCIA_MAP_IO : PCMCIA_MAP_MEM,
1059 1059 regbuf, &ret);
1060 1060 switch (mp->map_op) {
1061 1061 case DDI_MO_UNMAP:
1062 1062 pcmcia_set_assigned(rdip, rnum, NULL);
1063 1063 break;
1064 1064 default:
1065 1065 break;
1066 1066 }
1067 1067 return (ddi_map(dip, &mr, (off_t)0, (off_t)0, vaddrp));
1068 1068 }
1069 1069
1070 1070 /*
1071 1071 * pcmcia_cons_regspec()
1072 1072 * based on parent's bus type, construct a regspec that is usable
1073 1073 * by that parent to map the resource into the system.
1074 1074 */
1075 1075 #define PTYPE_PCI 1
1076 1076 #define PTYPE_ISA 0
1077 1077 struct regspec *
1078 1078 pcmcia_cons_regspec(dev_info_t *dip, int type, uchar_t *buff, ra_return_t *ret)
1079 1079 {
1080 1080 int ptype = -1, len, bus;
1081 1081 char device_type[MODMAXNAMELEN + 1];
1082 1082 dev_info_t *pdip;
1083 1083 struct regspec *defreg;
1084 1084 pci_regspec_t *pcireg;
1085 1085
1086 1086 pdip = ddi_get_parent(dip);
1087 1087 if (pdip != ddi_root_node()) {
1088 1088 /* we're not a child of root so find out what */
1089 1089 len = sizeof (device_type);
1090 1090 if (ddi_prop_op(DDI_DEV_T_ANY, pdip, PROP_LEN_AND_VAL_BUF, 0,
1091 1091 "device_type", (caddr_t)device_type, &len) ==
1092 1092 DDI_PROP_SUCCESS) {
1093 1093 /* check things out */
1094 1094 if (strcmp(device_type, "pci") == 0)
1095 1095 ptype = PTYPE_PCI;
1096 1096 else if (strcmp(device_type, "isa") == 0)
1097 1097 ptype = PTYPE_ISA;
1098 1098 }
1099 1099 }
1100 1100 switch (ptype) {
1101 1101 case PTYPE_PCI:
1102 1102 /* XXX need to look at carefully */
1103 1103 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1104 1104 "reg", (caddr_t)&pcireg, &len) == DDI_SUCCESS) {
1105 1105 bus = PCI_REG_BUS_G(pcireg->pci_phys_hi);
1106 1106 kmem_free(pcireg, len);
1107 1107 } else {
1108 1108 bus = 0;
1109 1109 }
1110 1110 pcireg = (pci_regspec_t *)buff;
1111 1111 pcireg->pci_phys_hi = (type == PCMCIA_MAP_IO ? PCI_ADDR_IO :
1112 1112 PCI_ADDR_MEM32) | PCI_RELOCAT_B | (bus << 16);
1113 1113 pcireg->pci_phys_mid = ret->ra_addr_hi;
1114 1114 pcireg->pci_phys_low = ret->ra_addr_lo;
1115 1115 if (type == PCMCIA_MAP_IO)
1116 1116 pcireg->pci_phys_low &= 0xFFFF;
1117 1117 pcireg->pci_size_hi = 0;
1118 1118 pcireg->pci_size_low = ret->ra_len;
1119 1119 break;
1120 1120 default:
1121 1121 /* default case is to use struct regspec */
1122 1122 defreg = (struct regspec *)buff;
1123 1123 defreg->regspec_bustype = type == PCMCIA_MAP_IO ? 1 : 0;
1124 1124 defreg->regspec_addr = ret->ra_addr_lo;
1125 1125 defreg->regspec_size = ret->ra_len;
1126 1126 break;
1127 1127 }
1128 1128 return ((struct regspec *)buff);
1129 1129 }
1130 1130
1131 1131 /*
1132 1132 * pcmcia_init_adapter
1133 1133 * Initialize the per-adapter structures and check to see if
1134 1134 * there are possible other instances coming.
1135 1135 */
1136 1136 void
1137 1137 pcmcia_init_adapter(anp_t *adapter, dev_info_t *dip)
1138 1138 {
1139 1139 int i, n;
1140 1140 pcmcia_if_t *ls_if;
1141 1141
1142 1142 i = pcmcia_num_adapters++;
1143 1143 pcmcia_adapters[i] = kmem_zalloc(sizeof (struct pcmcia_adapter),
1144 1144 KM_SLEEP);
1145 1145 pcmcia_adapters[i]->pca_dip = dip;
1146 1146 /* should this be pca_winshift??? */
1147 1147 pcmcia_adapters[i]->pca_module = ddi_driver_major(dip);
1148 1148 pcmcia_adapters[i]->pca_unit = ddi_get_instance(dip);
1149 1149 pcmcia_adapters[i]->pca_iblock = adapter->an_iblock;
1150 1150 pcmcia_adapters[i]->pca_idev = adapter->an_idev;
1151 1151 pcmcia_adapters[i]->pca_if = ls_if = adapter->an_if;
1152 1152 pcmcia_adapters[i]->pca_number = i;
1153 1153 (void) strcpy(pcmcia_adapters[i]->pca_name, ddi_get_name(dip));
1154 1154 pcmcia_adapters[i]->
1155 1155 pca_name[sizeof (pcmcia_adapters[i]->pca_name) - 1] = NULL;
1156 1156
1157 1157 if (ls_if != NULL) {
1158 1158 inquire_adapter_t conf;
1159 1159 int sock, win;
1160 1160
1161 1161 if (ls_if->pcif_inquire_adapter != NULL)
1162 1162 GET_CONFIG(ls_if, dip, &conf);
1163 1163
1164 1164 /* resources - assume worst case and fix from there */
1165 1165 pcmcia_adapters[i]->pca_flags = PCA_RES_NEED_IRQ |
1166 1166 PCA_RES_NEED_IO | PCA_RES_NEED_MEM;
1167 1167 /* indicate first socket not initialized */
1168 1168 pcmcia_adapters[i]->pca_first_socket = -1;
1169 1169
1170 1170 if (conf.ResourceFlags & RES_OWN_IRQ)
1171 1171 pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IRQ;
1172 1172 if (conf.ResourceFlags & RES_OWN_IO)
1173 1173 pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IO;
1174 1174 if (conf.ResourceFlags & RES_OWN_MEM)
1175 1175 pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_MEM;
1176 1176 if (conf.ResourceFlags & RES_IRQ_SHAREABLE)
1177 1177 pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SHAREABLE;
1178 1178 if (conf.ResourceFlags & RES_IRQ_NEXUS)
1179 1179 pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SMI_SHARE;
1180 1180
1181 1181 /* need to know interrupt limitations */
1182 1182 if (conf.ActiveLow) {
1183 1183 pcmcia_adapters[i]->pca_avail_intr = conf.ActiveLow;
1184 1184 pcmcia_adapters[i]->pca_flags |= PCA_IRQ_ISA;
1185 1185 } else
1186 1186 pcmcia_adapters[i]->pca_avail_intr = conf.ActiveHigh;
1187 1187
1188 1188 /* power entries for adapter */
1189 1189 pcmcia_adapters[i]->pca_power = conf.power_entry;
1190 1190 pcmcia_adapters[i]->pca_numpower = conf.NumPower;
1191 1191
1192 1192 for (n = 0; n < conf.NumPower; n++)
1193 1193 pcmcia_merge_power(&conf.power_entry[n]);
1194 1194
1195 1195 /* now setup the per socket info */
1196 1196 for (sock = 0; sock < conf.NumSockets;
1197 1197 sock++) {
1198 1198 dev_info_t *sockdrv = NULL;
1199 1199 sockdrv = pcmcia_number_socket(dip, sock);
1200 1200 if (sockdrv == NULL)
1201 1201 n = sock + pcmcia_num_sockets;
1202 1202 else {
1203 1203 n = ddi_get_instance(sockdrv);
1204 1204 }
1205 1205 /* make sure we know first socket on adapter */
1206 1206 if (pcmcia_adapters[i]->pca_first_socket == -1)
1207 1207 pcmcia_adapters[i]->pca_first_socket = n;
1208 1208
1209 1209 /*
1210 1210 * the number of sockets is weird.
1211 1211 * we might have only two sockets but
1212 1212 * due to persistence of instances we
1213 1213 * will need to call them something other
1214 1214 * than 0 and 1. So, we use the largest
1215 1215 * instance number as the number and
1216 1216 * have some that just don't get used.
1217 1217 */
1218 1218 if (n >= pcmcia_num_sockets)
1219 1219 pcmcia_num_sockets = n + 1;
1220 1220 #if defined(PCMCIA_DEBUG)
1221 1221 if (pcmcia_debug) {
1222 1222 cmn_err(CE_CONT,
1223 1223 "pcmcia_init: new socket added %d "
1224 1224 "(%d)\n",
1225 1225 n, pcmcia_num_sockets);
1226 1226 }
1227 1227 #endif
1228 1228
1229 1229 pcmcia_sockets[n] =
1230 1230 kmem_zalloc(sizeof (pcmcia_logical_socket_t),
1231 1231 KM_SLEEP);
1232 1232 pcmcia_sockets[n]->ls_socket = sock;
1233 1233 pcmcia_sockets[n]->ls_if = ls_if;
1234 1234 pcmcia_sockets[n]->ls_adapter =
1235 1235 pcmcia_adapters[i];
1236 1236 pcmcia_sockets[n]->ls_cs_events = 0L;
1237 1237 pcmcia_sockets[n]->ls_sockdrv = sockdrv;
1238 1238 /* Prototype of intrspec */
1239 1239 pcmcia_sockets[n]->ls_intr_pri = adapter->an_ipl;
1240 1240 #if defined(PCMCIA_DEBUG)
1241 1241 if (pcmcia_debug)
1242 1242 cmn_err(CE_CONT,
1243 1243 "phys sock %d, log sock %d\n",
1244 1244 sock, n);
1245 1245 #endif
1246 1246 mutex_init(&pcmcia_sockets[n]->ls_ilock, NULL,
1247 1247 MUTEX_DRIVER, *adapter->an_iblock);
1248 1248 }
1249 1249
1250 1250 pcmcia_adapters[i]->pca_numsockets = conf.NumSockets;
1251 1251 /* now setup the per window information */
1252 1252 for (win = 0; win < conf.NumWindows; win++) {
1253 1253 n = win + pcmcia_num_windows;
1254 1254 pcmcia_windows[n] =
1255 1255 kmem_zalloc(sizeof (pcmcia_logical_window_t),
1256 1256 KM_SLEEP);
1257 1257 pcmcia_windows[n]->lw_window = win;
1258 1258 pcmcia_windows[n]->lw_if = ls_if;
1259 1259 pcmcia_windows[n]->lw_adapter =
1260 1260 pcmcia_adapters[i];
1261 1261 }
1262 1262 pcmcia_num_windows += conf.NumWindows;
1263 1263 SET_CALLBACK(ls_if, dip,
1264 1264 pcm_adapter_callback, i);
1265 1265
1266 1266 /* now tell CS about each socket */
1267 1267 for (sock = 0; sock < pcmcia_num_sockets; sock++) {
1268 1268 #if defined(PCMCIA_DEBUG)
1269 1269 if (pcmcia_debug) {
1270 1270 cmn_err(CE_CONT,
1271 1271 "pcmcia_init: notify CS socket %d "
1272 1272 "sockp=%p\n",
1273 1273 sock, (void *)pcmcia_sockets[sock]);
1274 1274 }
1275 1275 #endif
1276 1276 if (pcmcia_sockets[sock] == NULL ||
1277 1277 (pcmcia_sockets[sock]->ls_flags &
1278 1278 PCS_SOCKET_ADDED)) {
1279 1279 /* skip the ones that are done already */
1280 1280 continue;
1281 1281 }
1282 1282 pcmcia_sockets[sock]->ls_flags |= PCS_SOCKET_ADDED;
1283 1283 if (cs_event(PCE_ADD_SOCKET, sock, 0) !=
1284 1284 CS_SUCCESS) {
1285 1285 /* flag socket as broken */
1286 1286 pcmcia_sockets[sock]->ls_flags = 0;
1287 1287 } else {
1288 1288 pcm_event_manager(PCE_ADD_SOCKET,
1289 1289 sock, NULL);
1290 1290 }
1291 1291 }
1292 1292
1293 1293 }
1294 1294 #if defined(PCMCIA_DEBUG)
1295 1295 if (pcmcia_debug) {
1296 1296 cmn_err(CE_CONT, "logical sockets:\n");
1297 1297 for (i = 0; i < pcmcia_num_sockets; i++) {
1298 1298 if (pcmcia_sockets[i] == NULL)
1299 1299 continue;
1300 1300 cmn_err(CE_CONT,
1301 1301 "\t%d: phys sock=%d, if=%p, adapt=%p\n",
1302 1302 i, pcmcia_sockets[i]->ls_socket,
1303 1303 (void *)pcmcia_sockets[i]->ls_if,
1304 1304 (void *)pcmcia_sockets[i]->ls_adapter);
1305 1305 }
1306 1306 cmn_err(CE_CONT, "logical windows:\n");
1307 1307 for (i = 0; i < pcmcia_num_windows; i++) {
1308 1308 cmn_err(CE_CONT,
1309 1309 "\t%d: phys_window=%d, if=%p, adapt=%p\n",
1310 1310 i, pcmcia_windows[i]->lw_window,
1311 1311 (void *)pcmcia_windows[i]->lw_if,
1312 1312 (void *)pcmcia_windows[i]->lw_adapter);
1313 1313 }
1314 1314 cmn_err(CE_CONT, "\tpcmcia_num_power=%d\n", pcmcia_num_power);
1315 1315 for (n = 0; n < pcmcia_num_power; n++)
1316 1316 cmn_err(CE_CONT,
1317 1317 "\t\tPowerLevel: %d\tValidSignals: %x\n",
1318 1318 pcmcia_power_table[n].PowerLevel,
1319 1319 pcmcia_power_table[n].ValidSignals);
1320 1320 }
1321 1321 #endif
1322 1322 }
1323 1323
1324 1324 /*
1325 1325 * pcmcia_find_cards()
1326 1326 * check the adapter to see if there are cards present at
1327 1327 * driver attach time. If there are, generate an artificial
1328 1328 * card insertion event to get CS running and the PC Card ultimately
1329 1329 * identified.
1330 1330 */
1331 1331 void
1332 1332 pcmcia_find_cards(anp_t *adapt)
1333 1333 {
1334 1334 int i;
1335 1335 get_ss_status_t status;
1336 1336 for (i = 0; i < pcmcia_num_sockets; i++) {
1337 1337 if (pcmcia_sockets[i] &&
1338 1338 pcmcia_sockets[i]->ls_if == adapt->an_if) {
1339 1339 /* check the status */
1340 1340 status.socket = i;
1341 1341 if (SSGetStatus(&status) == SUCCESS &&
1342 1342 status.IFType != IF_CARDBUS &&
1343 1343 status.CardState & SBM_CD &&
1344 1344 pcmcia_sockets[i]->ls_dip[0] == NULL) {
1345 1345 (void) cs_event(PCE_CARD_INSERT, i, 0);
1346 1346 delay(1);
1347 1347 }
1348 1348 }
1349 1349 }
1350 1350 }
1351 1351
1352 1352 /*
1353 1353 * pcmcia_number_socket(dip, adapt)
1354 1354 * we determine socket number by creating a driver for each
1355 1355 * socket on the adapter and then forcing it to attach. This
1356 1356 * results in an instance being assigned which becomes the
1357 1357 * logical socket number. If it fails, then we are the first
1358 1358 * set of sockets and renumbering occurs later. We do this
1359 1359 * one socket at a time and return the dev_info_t so the
1360 1360 * instance number can be used.
1361 1361 */
1362 1362 dev_info_t *
1363 1363 pcmcia_number_socket(dev_info_t *dip, int localsocket)
1364 1364 {
1365 1365 dev_info_t *child = NULL;
1366 1366 struct pcmcia_parent_private *ppd;
1367 1367
1368 1368 if (ndi_devi_alloc(dip, "pcs", (pnode_t)DEVI_SID_NODEID,
1369 1369 &child) == NDI_SUCCESS) {
1370 1370 ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
1371 1371 KM_SLEEP);
1372 1372 ppd->ppd_reg = kmem_zalloc(sizeof (struct pcm_regs), KM_SLEEP);
1373 1373 ppd->ppd_nreg = 1;
1374 1374 ppd->ppd_reg[0].phys_hi = localsocket;
1375 1375 ddi_set_parent_data(child, (caddr_t)ppd);
1376 1376 if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
1377 1377 kmem_free(ppd->ppd_reg, sizeof (struct pcm_regs));
1378 1378 kmem_free(ppd, sizeof (struct pcmcia_parent_private));
1379 1379 (void) ndi_devi_free(child);
1380 1380 child = NULL;
1381 1381 }
1382 1382 }
1383 1383 return (child);
1384 1384 }
1385 1385
1386 1386 /*
1387 1387 * pcm_phys_to_log_socket()
1388 1388 * from an adapter and socket number return the logical socket
1389 1389 */
1390 1390 int
1391 1391 pcm_phys_to_log_socket(struct pcmcia_adapter *adapt, int socket)
1392 1392 {
1393 1393 register pcmcia_logical_socket_t *sockp;
1394 1394 int i;
1395 1395
1396 1396 for (i = 0, sockp = pcmcia_sockets[0];
1397 1397 i < pcmcia_num_sockets; i++, sockp = pcmcia_sockets[i]) {
1398 1398 if (sockp == NULL)
1399 1399 continue;
1400 1400 if (sockp->ls_socket == socket && sockp->ls_adapter == adapt)
1401 1401 break;
1402 1402 }
1403 1403 if (i >= pcmcia_num_sockets) {
1404 1404 #if defined(PCMCIA_DEBUG)
1405 1405 if (pcmcia_debug)
1406 1406 cmn_err(CE_CONT,
1407 1407 "\tbad socket/adapter: %x/%p != %x/%x\n",
1408 1408 socket, (void *)adapt, pcmcia_num_sockets,
1409 1409 pcmcia_num_adapters);
1410 1410 #endif
1411 1411 return (-1);
1412 1412 }
1413 1413
1414 1414 return (i); /* want logical socket */
1415 1415 }
1416 1416
1417 1417 /*
1418 1418 * pcm_adapter_callback()
1419 1419 * this function is called back by the adapter driver at interrupt time.
1420 1420 * It is here that events should get generated for the event manager if it
1421 1421 * is present. It would also be the time where a device information
1422 1422 * tree could be constructed for a card that was added in if we
1423 1423 * choose to create them dynamically.
1424 1424 */
1425 1425
1426 1426 #if defined(PCMCIA_DEBUG)
1427 1427 char *cblist[] = {
1428 1428 "removal",
1429 1429 "insert",
1430 1430 "ready",
1431 1431 "battery-warn",
1432 1432 "battery-dead",
1433 1433 "status-change",
1434 1434 "write-protect", "reset", "unlock", "client-info", "eject-complete",
1435 1435 "eject-request", "erase-complete", "exclusive-complete",
1436 1436 "exclusive-request", "insert-complete", "insert-request",
1437 1437 "reset-complete", "reset-request", "timer-expired",
1438 1438 "resume", "suspend"
1439 1439 };
1440 1440 #endif
1441 1441
1442 1442 /*ARGSUSED*/
1443 1443 static int
1444 1444 pcm_adapter_callback(dev_info_t *dip, int adapter, int event, int socket)
1445 1445 {
1446 1446 pcmcia_logical_socket_t *sockp;
1447 1447
1448 1448 #if defined(PCMCIA_DEBUG)
1449 1449 if (pcmcia_debug) {
1450 1450 cmn_err(CE_CONT, "pcm_adapter_callback: %p %x %x %x: ",
1451 1451 (void *)dip, adapter, event, socket);
1452 1452 cmn_err(CE_CONT, "[%s]\n", cblist[event]);
1453 1453 }
1454 1454 #endif
1455 1455
1456 1456 if (adapter >= pcmcia_num_adapters || adapter < 0) {
1457 1457 #if defined(PCMCIA_DEBUG)
1458 1458 if (pcmcia_debug)
1459 1459 cmn_err(CE_CONT, "\tbad adapter number: %d : %d\n",
1460 1460 adapter, pcmcia_num_adapters);
1461 1461 #endif
1462 1462 return (1);
1463 1463 }
1464 1464
1465 1465 /* get the logical socket since that is what CS knows */
1466 1466 socket = pcm_phys_to_log_socket(pcmcia_adapters[adapter], socket);
1467 1467 if (socket == -1) {
1468 1468 cmn_err(CE_WARN, "pcmcia callback - bad logical socket\n");
1469 1469 return (0);
1470 1470 }
1471 1471 sockp = pcmcia_sockets[socket];
1472 1472 switch (event) {
1473 1473 case -1: /* special case of adapter going away */
1474 1474 case PCE_CARD_INSERT:
1475 1475 sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
1476 1476 PCE_E2M(PCE_CARD_REMOVAL);
1477 1477 break;
1478 1478 case PCE_CARD_REMOVAL:
1479 1479 /* disable interrupts at this point */
1480 1480 sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) |
1481 1481 PCE_E2M(PCE_CARD_REMOVAL);
1482 1482 /* remove children that never attached */
1483 1483
1484 1484 break;
1485 1485 case PCE_PM_RESUME:
1486 1486 pcmcia_do_resume(socket, sockp);
1487 1487 /* event = PCE_CARD_INSERT; */
1488 1488 break;
1489 1489 case PCE_PM_SUSPEND:
1490 1490 pcmcia_do_suspend(socket, sockp);
1491 1491 /* event = PCE_CARD_REMOVAL; */
1492 1492 break;
1493 1493 default:
1494 1494 /* nothing to do */
1495 1495 break;
1496 1496 }
1497 1497
1498 1498 #if defined(PCMCIA_DEBUG)
1499 1499 if (pcmcia_debug) {
1500 1500 cmn_err(CE_CONT,
1501 1501 "\tevent %d, event mask=%x, match=%x (log socket=%d)\n",
1502 1502 event,
1503 1503 (int)sockp->ls_cs_events,
1504 1504 (int)(sockp->ls_cs_events & PCE_E2M(event)), socket);
1505 1505 }
1506 1506 #endif
1507 1507
1508 1508 if (pcmcia_cs_event && sockp->ls_cs_events & (1 << event)) {
1509 1509 #if defined(PCMCIA_DEBUG)
1510 1510 if (pcmcia_debug)
1511 1511 cmn_err(CE_CONT, "\tcalling CS event handler (%p) "
1512 1512 "with event=%d\n",
1513 1513 (void *)pcmcia_cs_event, event);
1514 1514 #endif
1515 1515 CS_EVENT(event, socket, 0);
1516 1516 }
1517 1517
1518 1518 /* let the event manager(s) know about the event */
1519 1519 pcm_event_manager(event, socket, NULL);
1520 1520
1521 1521 return (0);
1522 1522 }
1523 1523
1524 1524 /*
1525 1525 * pcm_event_manager()
1526 1526 * checks for registered management driver callback handlers
1527 1527 * if there are any, call them if the event warrants it
1528 1528 */
1529 1529 void
1530 1530 pcm_event_manager(int event, int socket, void *arg)
1531 1531 {
1532 1532 struct pcmcia_mif *mif;
1533 1533
1534 1534 for (mif = pcmcia_mif_handlers; mif != NULL; mif = mif->mif_next) {
1535 1535 #if defined(PCMCIA_DEBUG)
1536 1536 if (pcmcia_debug)
1537 1537 cmn_err(CE_CONT,
1538 1538 "pcm_event_manager: event=%d, mif_events=%x"
1539 1539 " (tst:%d)\n",
1540 1540 event, (int)*(uint32_t *)mif->mif_events,
1541 1541 PR_GET(mif->mif_events, event));
1542 1542 #endif
1543 1543 if (PR_GET(mif->mif_events, event)) {
1544 1544 mif->mif_function(mif->mif_id, event, socket, arg);
1545 1545 }
1546 1546 }
1547 1547
1548 1548 }
1549 1549
1550 1550 /*
1551 1551 * pcm_search_devinfo(dev_info_t *, pcm_device_info *, int)
1552 1552 * search for an immediate child node to the nexus and not siblings of nexus
1553 1553 * and not grandchildren. We follow the same sequence that name binding
1554 1554 * follows so we match same class of device (modem == modem) and don't
1555 1555 * have to depend on features that might not exist.
1556 1556 */
1557 1557 dev_info_t *
1558 1558 pcm_search_devinfo(dev_info_t *self, struct pcm_device_info *info, int socket)
1559 1559 {
1560 1560 char bf[256];
1561 1561 struct pcmcia_parent_private *ppd;
1562 1562 dev_info_t *dip;
1563 1563 int circ;
1564 1564
1565 1565 #if defined(PCMCIA_DEBUG)
1566 1566 if (pcmcia_debug)
1567 1567 cmn_err(CE_CONT,
1568 1568 "pcm_search_devinfo: socket=%x [%s|%s|%s] pd_flags=%x\n",
1569 1569 socket, info->pd_bind_name, info->pd_generic_name,
1570 1570 info->pd_vers1_name, info->pd_flags);
1571 1571 #endif
1572 1572
1573 1573 ndi_devi_enter(self, &circ);
1574 1574 /* do searches in compatible property order */
1575 1575 for (dip = (dev_info_t *)DEVI(self)->devi_child;
1576 1576 dip != NULL;
1577 1577 dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
1578 1578 int ppd_socket;
1579 1579 ppd = (struct pcmcia_parent_private *)
1580 1580 ddi_get_parent_data(dip);
1581 1581 if (ppd == NULL) {
1582 1582 #if defined(PCMCIA_DEBUG)
1583 1583 cmn_err(CE_WARN, "No parent private data\n");
1584 1584 #endif
1585 1585 continue;
1586 1586 }
1587 1587 ppd_socket = CS_MAKE_SOCKET_NUMBER(ppd->ppd_socket,
1588 1588 ppd->ppd_function);
1589 1589 #if defined(PCMCIA_DEBUG)
1590 1590 if (pcmcia_debug) {
1591 1591 cmn_err(CE_CONT, "\tbind=[%s], node=[%s]\n",
1592 1592 DEVI(dip)->devi_binding_name,
1593 1593 DEVI(dip)->devi_node_name);
1594 1594 }
1595 1595 #endif
1596 1596 if (info->pd_flags & PCM_NAME_VERS1) {
1597 1597 (void) strcpy(bf, info->pd_vers1_name);
1598 1598 pcmcia_fix_string(bf);
1599 1599 if (DEVI(dip)->devi_binding_name &&
1600 1600 strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
1601 1601 socket == ppd_socket)
1602 1602 break;
1603 1603 }
1604 1604 if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
1605 1605 (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
1606 1606 (void) sprintf(bf, "%s,%x", info->pd_bind_name,
1607 1607 info->pd_function);
1608 1608 if (strcmp(bf, DEVI(dip)->devi_binding_name) == 0 &&
1609 1609 socket == ppd->ppd_socket)
1610 1610 break;
1611 1611 }
1612 1612 if (info->pd_flags & PCM_NAME_1275) {
1613 1613 if (DEVI(dip)->devi_binding_name &&
1614 1614 strcmp(DEVI(dip)->devi_binding_name,
1615 1615 info->pd_bind_name) == 0 &&
1616 1616 socket == ppd_socket)
1617 1617 break;
1618 1618 }
1619 1619 if (info->pd_flags & PCM_NAME_GENERIC) {
1620 1620 (void) sprintf(bf, "%s,%s", PCMDEV_NAMEPREF,
1621 1621 info->pd_generic_name);
1622 1622 if (DEVI(dip)->devi_binding_name &&
1623 1623 strcmp(DEVI(dip)->devi_binding_name, bf) == 0 &&
1624 1624 socket == ppd_socket)
1625 1625 break;
1626 1626 }
1627 1627 if (info->pd_flags & PCM_NAME_GENERIC) {
1628 1628 if (DEVI(dip)->devi_binding_name &&
1629 1629 strcmp(DEVI(dip)->devi_binding_name,
1630 1630 info->pd_generic_name) == 0 &&
1631 1631 socket == ppd_socket)
1632 1632 break;
1633 1633 }
1634 1634 if (info->pd_flags & PCM_NO_CONFIG) {
1635 1635 if (DEVI(dip)->devi_binding_name &&
1636 1636 strcmp(DEVI(dip)->devi_binding_name,
1637 1637 "pccard,memory") == 0 &&
1638 1638 socket == ppd_socket)
1639 1639 break;
1640 1640 }
1641 1641 }
1642 1642 ndi_devi_exit(self, circ);
1643 1643 return (dip);
1644 1644 }
1645 1645
1646 1646 /*
1647 1647 * pcm_find_devinfo()
1648 1648 * this is a wrapper around DDI calls to "find" any
1649 1649 * devinfo node and then from there find the one associated
1650 1650 * with the socket
1651 1651 */
1652 1652 dev_info_t *
1653 1653 pcm_find_devinfo(dev_info_t *pdip, struct pcm_device_info *info, int socket)
1654 1654 {
1655 1655 dev_info_t *dip;
1656 1656
1657 1657 dip = pcm_search_devinfo(pdip, info, socket);
1658 1658 if (dip == NULL)
1659 1659 return (NULL);
1660 1660 /*
1661 1661 * we have at least a base level dip
1662 1662 * see if there is one (this or a sibling)
1663 1663 * that has the correct socket number
1664 1664 * if there is, return that one else
1665 1665 * NULL so a new one is created
1666 1666 */
1667 1667 #if defined(PCMCIA_DEBUG)
1668 1668 if (pcmcia_debug)
1669 1669 cmn_err(CE_CONT, "find: initial dip = %p, socket=%d, name=%s "
1670 1670 "(instance=%d, socket=%d, name=%s)\n",
1671 1671 (void *)dip, socket, info->pd_bind_name,
1672 1672 ddi_get_instance(dip),
1673 1673 ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1674 1674 PCM_DEV_SOCKET, -1),
1675 1675 ddi_get_name(dip));
1676 1676 #endif
1677 1677
1678 1678 #if defined(PCMCIA_DEBUG)
1679 1679 if (pcmcia_debug && dip != NULL)
1680 1680 cmn_err(CE_CONT, "\treturning non-NULL dip (%s)\n",
1681 1681 ddi_get_name(dip));
1682 1682 #endif
1683 1683 return (dip);
1684 1684 }
1685 1685
1686 1686 /*
1687 1687 * pcm_find_parent_dip(socket)
1688 1688 * find the correct parent dip for this logical socket
1689 1689 */
1690 1690 dev_info_t *
1691 1691 pcm_find_parent_dip(int socket)
1692 1692 {
1693 1693 if ((socket < 0 || socket >= pcmcia_num_sockets) ||
1694 1694 pcmcia_sockets[socket] == NULL)
1695 1695 return (NULL);
1696 1696 return (pcmcia_sockets[socket]->ls_adapter->pca_dip);
1697 1697 }
1698 1698
1699 1699 /*
1700 1700 * pcmcia_set_em_handler()
1701 1701 * This is called by the management and event driver to tell
1702 1702 * the nexus what to call. Multiple drivers are allowed
1703 1703 * but normally only one will exist.
1704 1704 */
1705 1705 int
1706 1706 pcmcia_set_em_handler(int (*handler)(), caddr_t events, int elen,
1707 1707 uint32_t id, void **cs, void **ss)
1708 1708 {
1709 1709 struct pcmcia_mif *mif, *tmp;
1710 1710
1711 1711 if (handler == NULL) {
1712 1712 /* NULL means remove the handler based on the ID */
1713 1713 if (pcmcia_mif_handlers == NULL)
1714 1714 return (0);
1715 1715 mutex_enter(&pcmcia_global_lock);
1716 1716 if (pcmcia_mif_handlers->mif_id == id) {
1717 1717 mif = pcmcia_mif_handlers;
1718 1718 pcmcia_mif_handlers = mif->mif_next;
1719 1719 kmem_free(mif, sizeof (struct pcmcia_mif));
1720 1720 } else {
1721 1721 for (mif = pcmcia_mif_handlers;
1722 1722 mif->mif_next != NULL &&
1723 1723 mif->mif_next->mif_id != id;
1724 1724 mif = mif->mif_next)
1725 1725 ;
1726 1726 if (mif->mif_next != NULL &&
1727 1727 mif->mif_next->mif_id == id) {
1728 1728 tmp = mif->mif_next;
1729 1729 mif->mif_next = tmp->mif_next;
1730 1730 kmem_free(tmp, sizeof (struct pcmcia_mif));
1731 1731 }
1732 1732 }
1733 1733 mutex_exit(&pcmcia_global_lock);
1734 1734 } else {
1735 1735
1736 1736 if (pcmcia_num_adapters == 0) {
1737 1737 return (ENXIO);
1738 1738 }
1739 1739 if (elen > EM_EVENTSIZE)
1740 1740 return (EINVAL);
1741 1741
1742 1742 mif = (struct pcmcia_mif *)
1743 1743 kmem_zalloc(sizeof (struct pcmcia_mif), KM_NOSLEEP);
1744 1744 if (mif == NULL)
1745 1745 return (ENOSPC);
1746 1746
1747 1747 mif->mif_function = (void (*)())handler;
1748 1748 bcopy(events, mif->mif_events, elen);
1749 1749 mif->mif_id = id;
1750 1750 mutex_enter(&pcmcia_global_lock);
1751 1751 mif->mif_next = pcmcia_mif_handlers;
1752 1752 pcmcia_mif_handlers = mif;
1753 1753 if (cs != NULL)
1754 1754 *cs = (void *)pcmcia_card_services;
1755 1755 if (ss != NULL) {
1756 1756 *ss = (void *)SocketServices;
1757 1757 }
1758 1758
1759 1759 mutex_exit(&pcmcia_global_lock);
1760 1760 }
1761 1761 return (0);
1762 1762 }
1763 1763
1764 1764 /*
1765 1765 * pcm_fix_bits(uchar_t *data, int num, int dir)
1766 1766 * shift socket bits left(0) or right(0)
1767 1767 * This is used when mapping logical and physical
1768 1768 */
1769 1769 void
1770 1770 pcm_fix_bits(socket_enum_t src, socket_enum_t dst, int num, int dir)
1771 1771 {
1772 1772 int i;
1773 1773
1774 1774 PR_ZERO(dst);
1775 1775
1776 1776 if (dir == 0) {
1777 1777 /* LEFT */
1778 1778 for (i = 0; i <= (sizeof (dst) * PR_WORDSIZE) - num; i++) {
1779 1779 if (PR_GET(src, i))
1780 1780 PR_SET(dst, i + num);
1781 1781 }
1782 1782 } else {
1783 1783 /* RIGHT */
1784 1784 for (i = num; i < sizeof (dst) * PR_WORDSIZE; i++) {
1785 1785 if (PR_GET(src, i))
1786 1786 PR_SET(dst, i - num);
1787 1787 }
1788 1788 }
1789 1789 }
1790 1790
1791 1791 uint32_t
1792 1792 genmask(int len)
1793 1793 {
1794 1794 uint32_t mask;
1795 1795 for (mask = 0; len > 0; len--) {
1796 1796 mask |= 1 << (len - 1);
1797 1797 }
1798 1798 return (mask);
1799 1799 }
1800 1800
1801 1801 int
1802 1802 genp2(int val)
1803 1803 {
1804 1804 int i;
1805 1805 if (val == 0)
1806 1806 return (0);
1807 1807 for (i = 0; i < 32; i++)
1808 1808 if (val > (1 << i))
1809 1809 return (i);
1810 1810 return (0);
1811 1811 }
1812 1812
1813 1813 #if defined(PCMCIA_DEBUG)
1814 1814 char *ssfuncs[128] = {
1815 1815 "GetAdapter", "GetPage", "GetSocket", "GetStatus", "GetWindow",
1816 1816 "InquireAdapter", "InquireSocket", "InquireWindow", "ResetSocket",
1817 1817 "SetPage", "SetAdapter", "SetSocket", "SetWindow", "SetIRQHandler",
1818 1818 "ClearIRQHandler",
1819 1819 /* 15 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1820 1820 /* 25 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1821 1821 /* 35 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1822 1822 /* 45 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1823 1823 /* 55 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1824 1824 /* 65 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1825 1825 /* 75 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1826 1826 /* 85 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1827 1827 /* 95 */ NULL, NULL, NULL,
1828 1828 "CSIsActiveDip",
1829 1829 "CSInitDev", "CSRegister", "CSCISInit", "CSUnregister",
1830 1830 "CISGetAddress", "CISSetAddress", "CSCardRemoved", "CSGetCookiesAndDip"
1831 1831 };
1832 1832 #endif
1833 1833
1834 1834 /*
1835 1835 * SocketServices
1836 1836 * general entrypoint for Card Services to find
1837 1837 * Socket Services. Finding the entry requires
1838 1838 * a _depends_on[] relationship.
1839 1839 *
1840 1840 * In some cases, the work is done locally but usually
1841 1841 * the parameters are adjusted and the adapter driver
1842 1842 * code asked to do the work.
1843 1843 */
1844 1844 int
1845 1845 SocketServices(int function, ...)
1846 1846 {
1847 1847 va_list arglist;
1848 1848 uint32_t args[16];
1849 1849 csregister_t *reg;
1850 1850 sservice_t *serv;
1851 1851 dev_info_t *dip;
1852 1852 int socket, func;
1853 1853 int error = SUCCESS;
1854 1854 pcmcia_logical_socket_t *sockp;
1855 1855
1856 1856 va_start(arglist, function);
1857 1857
1858 1858 #if defined(PCMCIA_DEBUG)
1859 1859 if (pcmcia_debug > 1)
1860 1860 cmn_err(CE_CONT, "SocketServices called for function %d [%s]\n",
1861 1861 function,
1862 1862 ((function < 128) && ssfuncs[function] != NULL) ?
1863 1863 ssfuncs[function] : "UNKNOWN");
1864 1864 #endif
1865 1865 switch (function) {
1866 1866 case CSRegister:
1867 1867 case CISGetAddress:
1868 1868 case CISSetAddress:
1869 1869
1870 1870 reg = va_arg(arglist, csregister_t *);
1871 1871
1872 1872 if (reg->cs_magic != PCCS_MAGIC ||
1873 1873 reg->cs_version != PCCS_VERSION) {
1874 1874 cmn_err(CE_WARN,
1875 1875 "pcmcia: CSRegister (%x, %x, %p, %p) *ERROR*",
1876 1876 reg->cs_magic, reg->cs_version,
1877 1877 (void *)reg->cs_card_services,
1878 1878 (void *)reg->cs_event);
1879 1879 error = BAD_FUNCTION;
1880 1880 break;
1881 1881 }
1882 1882
1883 1883 switch (function) {
1884 1884 case CISGetAddress:
1885 1885 reg->cs_event = pcmcia_cis_parser;
1886 1886 break;
1887 1887 case CISSetAddress:
1888 1888 pcmcia_cis_parser = reg->cs_event;
1889 1889 break;
1890 1890 case CSRegister:
1891 1891 break;
1892 1892 }
1893 1893 break;
1894 1894
1895 1895 case CSUnregister:
1896 1896 break;
1897 1897
1898 1898 case CSCISInit:
1899 1899 args[0] = va_arg(arglist, int);
1900 1900 #if defined(PCMCIA_DEBUG)
1901 1901 if (pcmcia_debug)
1902 1902 cmn_err(CE_CONT,
1903 1903 "CSCISInit: CIS is initialized on socket %d\n",
1904 1904 (int)args[0]);
1905 1905 #endif
1906 1906 /*
1907 1907 * now that the CIS has been parsed (there may not
1908 1908 * be one but the work is done) we can create the
1909 1909 * device information structures.
1910 1910 *
1911 1911 * we serialize the node creation to avoid problems
1912 1912 * with initial probe/attach of nexi.
1913 1913 */
1914 1914
1915 1915 mutex_enter(&pcmcia_global_lock);
1916 1916 pcmcia_create_dev_info(args[0]);
1917 1917 cv_broadcast(&pcmcia_condvar); /* wakeup the nexus attach */
1918 1918 mutex_exit(&pcmcia_global_lock);
1919 1919 break;
1920 1920
1921 1921 case CSInitDev:
1922 1922 #if defined(PCMCIA_DEBUG)
1923 1923 if (pcmcia_debug)
1924 1924 cmn_err(CE_CONT, "CSInitDev: initialize device\n");
1925 1925 #endif
1926 1926 /*
1927 1927 * this is where we create the /devices entries
1928 1928 * that let us out into the world
1929 1929 */
1930 1930
1931 1931 (void) pcmcia_create_device(va_arg(arglist,
1932 1932 ss_make_device_node_t *));
1933 1933 break;
1934 1934
1935 1935 case CSCardRemoved:
1936 1936 args[0] = va_arg(arglist, uint32_t);
1937 1937 socket = CS_GET_SOCKET_NUMBER(args[0]);
1938 1938 func = CS_GET_FUNCTION_NUMBER(args[0]);
1939 1939 #if defined(PCMCIA_DEBUG)
1940 1940 if (pcmcia_debug)
1941 1941 cmn_err(CE_CONT,
1942 1942 "CSCardRemoved! (socket=%d)\n", (int)args[0]);
1943 1943 #endif
1944 1944 if (socket >= pcmcia_num_sockets)
1945 1945 break;
1946 1946
1947 1947 sockp = pcmcia_sockets[socket];
1948 1948 if (sockp == NULL) {
1949 1949 cmn_err(CE_WARN,
1950 1950 "pcmcia: bad socket = %x", socket);
1951 1951 break;
1952 1952 }
1953 1953
1954 1954 if (!(sockp->ls_flags & PCS_SUSPENDED)) {
1955 1955 for (func = 0; func < sockp->ls_functions; func++) {
1956 1956 /*
1957 1957 * break the association of dip and socket
1958 1958 * for all functions on that socket
1959 1959 */
1960 1960 dip = sockp->ls_dip[func];
1961 1961 sockp->ls_dip[func] = NULL;
1962 1962 if (dip != NULL) {
1963 1963 struct pcmcia_parent_private *ppd;
1964 1964 ppd = (struct pcmcia_parent_private *)
1965 1965 ddi_get_parent_data(dip);
1966 1966 ppd->ppd_active = 0;
1967 1967 (void) ndi_devi_offline(dip,
1968 1968 NDI_DEVI_REMOVE);
1969 1969
1970 1970 pcmcia_ppd_free(ppd);
1971 1971 }
1972 1972 #if defined(PCMCIA_DEBUG)
1973 1973 else {
1974 1974 if (pcmcia_debug)
1975 1975 cmn_err(CE_CONT,
1976 1976 "CardRemoved: no "
1977 1977 "dip present "
1978 1978 "on socket %d!\n",
1979 1979 (int)args[0]);
1980 1980 }
1981 1981 #endif
1982 1982 }
1983 1983 } else {
1984 1984 mutex_enter(&pcmcia_global_lock);
1985 1985 sockp->ls_flags &= ~PCS_SUSPENDED;
1986 1986 cv_broadcast(&pcmcia_condvar);
1987 1987 mutex_exit(&pcmcia_global_lock);
1988 1988 }
1989 1989 break;
1990 1990
1991 1991 case CSGetCookiesAndDip:
1992 1992 serv = va_arg(arglist, sservice_t *);
1993 1993 if (serv != NULL)
1994 1994 error = GetCookiesAndDip(serv);
1995 1995 else
1996 1996 error = BAD_SOCKET;
1997 1997 break;
1998 1998
1999 1999 case CSGetActiveDip:
2000 2000 /*
2001 2001 * get the dip associated with the card currently
2002 2002 * in the specified socket
2003 2003 */
2004 2004 args[0] = va_arg(arglist, uint32_t);
2005 2005 socket = CS_GET_SOCKET_NUMBER(args[0]);
2006 2006 func = CS_GET_FUNCTION_NUMBER(args[0]);
2007 2007 error = (long)pcmcia_sockets[socket]->ls_dip[func];
2008 2008 break;
2009 2009
2010 2010 /*
2011 2011 * the remaining entries are SocketServices calls
2012 2012 */
2013 2013 case SS_GetAdapter:
2014 2014 error = SSGetAdapter(va_arg(arglist, get_adapter_t *));
2015 2015 break;
2016 2016 case SS_GetPage:
2017 2017 error = SSGetPage(va_arg(arglist, get_page_t *));
2018 2018 break;
2019 2019 case SS_GetSocket:
2020 2020 error = SSGetSocket(va_arg(arglist, get_socket_t *));
2021 2021 break;
2022 2022 case SS_GetStatus:
2023 2023 error = SSGetStatus(va_arg(arglist, get_ss_status_t *));
2024 2024 break;
2025 2025 case SS_GetWindow:
2026 2026 error = SSGetWindow(va_arg(arglist, get_window_t *));
2027 2027 break;
2028 2028 case SS_InquireAdapter:
2029 2029 error = SSInquireAdapter(va_arg(arglist, inquire_adapter_t *));
2030 2030 break;
2031 2031 case SS_InquireSocket:
2032 2032 error = SSInquireSocket(va_arg(arglist, inquire_socket_t *));
2033 2033 break;
2034 2034 case SS_InquireWindow:
2035 2035 error = SSInquireWindow(va_arg(arglist, inquire_window_t *));
2036 2036 break;
2037 2037 case SS_ResetSocket:
2038 2038 args[0] = va_arg(arglist, uint32_t);
2039 2039 args[1] = va_arg(arglist, int);
2040 2040 error = SSResetSocket(args[0], args[1]);
2041 2041 break;
2042 2042 case SS_SetPage:
2043 2043 error = SSSetPage(va_arg(arglist, set_page_t *));
2044 2044 break;
2045 2045 case SS_SetSocket:
2046 2046 error = SSSetSocket(va_arg(arglist, set_socket_t *));
2047 2047 break;
2048 2048 case SS_SetWindow:
2049 2049 error = SSSetWindow(va_arg(arglist, set_window_t *));
2050 2050 break;
2051 2051 case SS_SetIRQHandler:
2052 2052 error = SSSetIRQHandler(va_arg(arglist, set_irq_handler_t *));
2053 2053 break;
2054 2054 case SS_ClearIRQHandler:
2055 2055 error = SSClearIRQHandler(va_arg(arglist,
2056 2056 clear_irq_handler_t *));
2057 2057 break;
2058 2058 default:
2059 2059 error = BAD_FUNCTION;
2060 2060 break;
2061 2061 }
2062 2062 va_end(arglist);
2063 2063 return (error);
2064 2064 }
2065 2065
2066 2066 /*
2067 2067 * pcmcia_merge_power()
2068 2068 * The adapters may have different power tables so it
2069 2069 * is necessary to construct a single power table that
2070 2070 * can be used throughout the system. The result is
2071 2071 * a merger of all capabilities. The nexus adds
2072 2072 * power table entries one at a time.
2073 2073 */
2074 2074 void
2075 2075 pcmcia_merge_power(struct power_entry *power)
2076 2076 {
2077 2077 int i;
2078 2078 struct power_entry pwr;
2079 2079
2080 2080 pwr = *power;
2081 2081
2082 2082 for (i = 0; i < pcmcia_num_power; i++) {
2083 2083 if (pwr.PowerLevel == pcmcia_power_table[i].PowerLevel) {
2084 2084 if (pwr.ValidSignals ==
2085 2085 pcmcia_power_table[i].ValidSignals) {
2086 2086 return;
2087 2087 } else {
2088 2088 /* partial match */
2089 2089 pwr.ValidSignals &=
2090 2090 ~pcmcia_power_table[i].ValidSignals;
2091 2091 }
2092 2092 }
2093 2093 }
2094 2094 /* what's left becomes a new entry */
2095 2095 if (pcmcia_num_power == PCMCIA_MAX_POWER)
2096 2096 return;
2097 2097 pcmcia_power_table[pcmcia_num_power++] = pwr;
2098 2098 }
2099 2099
2100 2100 /*
2101 2101 * pcmcia_do_suspend()
2102 2102 * tell CS that a suspend has happened by passing a
2103 2103 * card removal event. Then cleanup the socket state
2104 2104 * to fake the cards being removed so resume works
2105 2105 */
2106 2106 void
2107 2107 pcmcia_do_suspend(int socket, pcmcia_logical_socket_t *sockp)
2108 2108 {
2109 2109 get_ss_status_t stat;
2110 2110 struct pcmcia_adapter *adapt;
2111 2111 pcmcia_if_t *ls_if;
2112 2112 dev_info_t *dip;
2113 2113 int i;
2114 2114
2115 2115 #ifdef XXX
2116 2116 if (pcmcia_cs_event == NULL) {
2117 2117 return;
2118 2118 }
2119 2119 #endif
2120 2120
2121 2121 ls_if = sockp->ls_if;
2122 2122 adapt = sockp->ls_adapter;
2123 2123
2124 2124 if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
2125 2125 return;
2126 2126 }
2127 2127
2128 2128 stat.socket = socket;
2129 2129 #if defined(PCMCIA_DEBUG)
2130 2130 if (pcmcia_debug) {
2131 2131 cmn_err(CE_CONT,
2132 2132 "pcmcia_do_suspend(%d, %p)\n", socket, (void *)sockp);
2133 2133 }
2134 2134 #endif
2135 2135
2136 2136 if (GET_STATUS(ls_if, adapt->pca_dip, &stat) != SUCCESS)
2137 2137 return;
2138 2138
2139 2139 /*
2140 2140 * If there is a card in the socket, then we need to send
2141 2141 * everyone a PCE_CARD_REMOVAL event, and remove the
2142 2142 * card active property.
2143 2143 */
2144 2144
2145 2145 for (i = 0; i < sockp->ls_functions; i++) {
2146 2146 struct pcmcia_parent_private *ppd;
2147 2147 dip = sockp->ls_dip[i];
2148 2148 if (dip != NULL) {
2149 2149 ppd = (struct pcmcia_parent_private *)
2150 2150 ddi_get_parent_data(dip);
2151 2151 ppd->ppd_flags |= PPD_SUSPENDED;
2152 2152 }
2153 2153 #if 0
2154 2154 sockp->ls_dip[i] = NULL;
2155 2155 #endif
2156 2156 }
2157 2157 sockp->ls_flags |= PCS_SUSPENDED;
2158 2158
2159 2159 if (pcmcia_cs_event &&
2160 2160 (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
2161 2161 CS_EVENT(PCE_PM_SUSPEND, socket, 0);
2162 2162 }
2163 2163 pcm_event_manager(PCE_PM_SUSPEND, socket, NULL);
2164 2164 }
2165 2165
2166 2166 /*
2167 2167 * pcmcia_do_resume()
2168 2168 * tell CS that a suspend has happened by passing a
2169 2169 * card removal event. Then cleanup the socket state
2170 2170 * to fake the cards being removed so resume works
2171 2171 */
2172 2172 void
2173 2173 pcmcia_do_resume(int socket, pcmcia_logical_socket_t *sockp)
2174 2174 {
2175 2175 get_ss_status_t stat;
2176 2176 struct pcmcia_adapter *adapt;
2177 2177 pcmcia_if_t *ls_if;
2178 2178
2179 2179 #ifdef XXX
2180 2180 if (pcmcia_cs_event == NULL) {
2181 2181 return;
2182 2182 }
2183 2183 #endif
2184 2184
2185 2185 ls_if = sockp->ls_if;
2186 2186 adapt = sockp->ls_adapter;
2187 2187
2188 2188 if (ls_if == NULL || ls_if->pcif_get_status == NULL) {
2189 2189 return;
2190 2190 }
2191 2191
2192 2192 stat.socket = socket;
2193 2193 #if defined(PCMCIA_DEBUG)
2194 2194 if (pcmcia_debug) {
2195 2195 cmn_err(CE_CONT,
2196 2196 "pcmcia_do_resume(%d, %p)\n", socket, (void *)sockp);
2197 2197 }
2198 2198 #endif
2199 2199 if (GET_STATUS(ls_if, adapt->pca_dip, &stat) ==
2200 2200 SUCCESS) {
2201 2201
2202 2202 #if defined(PCMCIA_DEBUG)
2203 2203 if (pcmcia_debug)
2204 2204 cmn_err(CE_CONT, "\tsocket=%x, CardState=%x\n",
2205 2205 socket, stat.CardState);
2206 2206 #endif
2207 2207 #if 0
2208 2208 /* now have socket info -- do we have events? */
2209 2209 if ((stat.CardState & SBM_CD) == SBM_CD) {
2210 2210 if (pcmcia_cs_event &&
2211 2211 (sockp->ls_cs_events & (1 << PCE_CARD_INSERT))) {
2212 2212 CS_EVENT(PCE_CARD_INSERT, socket, 0);
2213 2213 }
2214 2214
2215 2215 /* we should have card removed from CS soon */
2216 2216 pcm_event_manager(PCE_CARD_INSERT, socket, NULL);
2217 2217 }
2218 2218 #else
2219 2219 if (pcmcia_cs_event &&
2220 2220 (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) {
2221 2221 CS_EVENT(PCE_PM_RESUME, socket, 0);
2222 2222 CS_EVENT(PCE_CARD_REMOVAL, socket, 0);
2223 2223 if ((stat.CardState & SBM_CD) == SBM_CD)
2224 2224 CS_EVENT(PCE_CARD_INSERT, socket, 0);
2225 2225 }
2226 2226 #endif
2227 2227 }
2228 2228 }
2229 2229
2230 2230 /*
2231 2231 * pcmcia_map_power_set()
2232 2232 * Given a power table entry and level, find it in the
2233 2233 * master table and return the index in the adapter table.
2234 2234 */
2235 2235 static int
2236 2236 pcmcia_map_power_set(struct pcmcia_adapter *adapt, int level, int which)
2237 2237 {
2238 2238 int plevel, i;
2239 2239 struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
2240 2240 plevel = pcmcia_power_table[level].PowerLevel;
2241 2241 /* mask = pcmcia_power_table[level].ValidSignals; */
2242 2242 for (i = 0; i < adapt->pca_numpower; i++)
2243 2243 if (plevel == pwr[i].PowerLevel &&
2244 2244 pwr[i].ValidSignals & which)
2245 2245 return (i);
2246 2246 return (0);
2247 2247 }
2248 2248
2249 2249 /*
2250 2250 * pcmcia_map_power_get()
2251 2251 * Given an adapter power entry, find the appropriate index
2252 2252 * in the master table.
2253 2253 */
2254 2254 static int
2255 2255 pcmcia_map_power_get(struct pcmcia_adapter *adapt, int level, int which)
2256 2256 {
2257 2257 int plevel, i;
2258 2258 struct power_entry *pwr = (struct power_entry *)adapt->pca_power;
2259 2259 plevel = pwr[level].PowerLevel;
2260 2260 /* mask = pwr[level].ValidSignals; */
2261 2261 for (i = 0; i < pcmcia_num_power; i++)
2262 2262 if (plevel == pcmcia_power_table[i].PowerLevel &&
2263 2263 pcmcia_power_table[i].ValidSignals & which)
2264 2264 return (i);
2265 2265 return (0);
2266 2266 }
2267 2267
2268 2268 /*
2269 2269 * XXX - SS really needs a way to allow the caller to express
2270 2270 * interest in PCE_CARD_STATUS_CHANGE events.
2271 2271 */
2272 2272 static uint32_t
2273 2273 pcm_event_map[32] = {
2274 2274 PCE_E2M(PCE_CARD_WRITE_PROTECT)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2275 2275 PCE_E2M(PCE_CARD_UNLOCK)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2276 2276 PCE_E2M(PCE_EJECTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2277 2277 PCE_E2M(PCE_INSERTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2278 2278 PCE_E2M(PCE_CARD_BATTERY_WARN)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2279 2279 PCE_E2M(PCE_CARD_BATTERY_DEAD)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2280 2280 PCE_E2M(PCE_CARD_READY)|PCE_E2M(PCE_CARD_STATUS_CHANGE),
2281 2281 PCE_E2M(PCE_CARD_REMOVAL)|PCE_E2M(PCE_CARD_INSERT)|
2282 2282 PCE_E2M(PCE_CARD_STATUS_CHANGE),
2283 2283 PCE_E2M(PCE_PM_SUSPEND)|PCE_E2M(PCE_PM_RESUME),
2284 2284 };
2285 2285
2286 2286 static int
2287 2287 pcm_mapevents(uint32_t eventmask)
2288 2288 {
2289 2289 uint32_t mask;
2290 2290 int i;
2291 2291
2292 2292 for (i = 0, mask = 0; eventmask && i < 32; i++) {
2293 2293 if (eventmask & (1 << i)) {
2294 2294 mask |= pcm_event_map[i];
2295 2295 eventmask &= ~(1 << i);
2296 2296 }
2297 2297 }
2298 2298 return (mask);
2299 2299 }
2300 2300
2301 2301
2302 2302 /*
2303 2303 * PCMCIA Generic Naming Support
2304 2304 *
2305 2305 * With 2.6, PCMCIA naming moves to the 1275 and generic naming model.
2306 2306 * Consequently, the whole naming mechanism is to be changed. This is
2307 2307 * not backward compatible with the current names but that isn't a problem
2308 2308 * due to so few drivers existing.
2309 2309 *
2310 2310 * For cards with a device_id tuple, a generic name will be used.
2311 2311 * if there is no device_id, then the 1275 name will be used if possible.
2312 2312 * The 1275 name is of the form pccardNNNN,MMMM from the manfid tuple.
2313 2313 * if there is not manfid tuple, an attempt will be made to bind the
2314 2314 * node to the version_1 strings.
2315 2315 *
2316 2316 * In all cases, a "compatible" property is created with a number
2317 2317 * of names. The most generic name will be last in the list.
2318 2318 */
2319 2319
2320 2320 /*
2321 2321 * pcmcia_fix_string()
2322 2322 * want to avoid special characters in alias strings so convert
2323 2323 * to something innocuous
2324 2324 */
2325 2325
2326 2326 void
2327 2327 pcmcia_fix_string(char *str)
2328 2328 {
2329 2329 for (; str && *str; str++) {
2330 2330 switch (*str) {
2331 2331 case ' ':
2332 2332 case '\t':
2333 2333 *str = '_';
2334 2334 break;
2335 2335 }
2336 2336 }
2337 2337 }
2338 2338
2339 2339 void
2340 2340 pcmcia_1275_name(int socket, struct pcm_device_info *info,
2341 2341 client_handle_t handle)
2342 2342 {
2343 2343 cistpl_manfid_t manfid;
2344 2344 cistpl_jedec_t jedec;
2345 2345 tuple_t tuple;
2346 2346 int i;
2347 2347
2348 2348 tuple.Socket = socket;
2349 2349
2350 2350 /* get MANFID if it exists -- this is most important form */
2351 2351 tuple.DesiredTuple = CISTPL_MANFID;
2352 2352 tuple.Attributes = 0;
2353 2353 if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2354 2354 SUCCESS) {
2355 2355 i = csx_Parse_CISTPL_MANFID(handle, &tuple,
2356 2356 &manfid);
2357 2357 if (i == SUCCESS) {
2358 2358 (void) sprintf(info->pd_bind_name, "%s%x,%x",
2359 2359 PCMDEV_NAMEPREF,
2360 2360 manfid.manf, manfid.card);
2361 2361 info->pd_flags |= PCM_NAME_1275;
2362 2362 }
2363 2363 } else {
2364 2364 tuple.Attributes = 0;
2365 2365 tuple.DesiredTuple = CISTPL_JEDEC_A;
2366 2366 if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2367 2367 SUCCESS) {
2368 2368 i = csx_Parse_CISTPL_JEDEC_A(handle, &tuple,
2369 2369 &jedec);
2370 2370 if (i == SUCCESS) {
2371 2371 (void) sprintf(info->pd_bind_name, "%s%x,%x",
2372 2372 PCMDEV_NAMEPREF,
2373 2373 jedec.jid[0].id, jedec.jid[0].info);
2374 2374 info->pd_flags |= PCM_NAME_1275;
2375 2375 }
2376 2376 }
2377 2377 }
2378 2378 }
2379 2379
2380 2380 void
2381 2381 pcmcia_vers1_name(int socket, struct pcm_device_info *info,
2382 2382 client_handle_t handle)
2383 2383 {
2384 2384 cistpl_vers_1_t vers1;
2385 2385 tuple_t tuple;
2386 2386 int which = 0;
2387 2387 int i, len, space;
2388 2388
2389 2389 tuple.Socket = socket;
2390 2390 info->pd_vers1_name[0] = '\0';
2391 2391
2392 2392 /* Version 1 strings */
2393 2393 tuple.DesiredTuple = CISTPL_VERS_1;
2394 2394 tuple.Attributes = 0;
2395 2395 if (!which &&
2396 2396 (i = csx_GetFirstTuple(handle, &tuple)) == SUCCESS) {
2397 2397 i = csx_Parse_CISTPL_VERS_1(handle, &tuple, &vers1);
2398 2398 if (i == SUCCESS) {
2399 2399 /* BEGIN CSTYLED */
2400 2400 for (i = 0, len = 0, space = 0; i < vers1.ns; i++) {
2401 2401 if ((space + len + strlen(info->pd_vers1_name)) >=
2402 2402 sizeof (info->pd_vers1_name))
2403 2403 break;
2404 2404 if (space) {
2405 2405 info->pd_vers1_name[len++] = ',';
2406 2406 }
2407 2407 (void) strcpy(info->pd_vers1_name + len,
2408 2408 (char *)vers1.pi[i]);
2409 2409 len += strlen((char *)vers1.pi[i]);
2410 2410 /* strip trailing spaces off of string */
2411 2411 while (info->pd_vers1_name[len - 1] == ' ' &&
2412 2412 len > 0)
2413 2413 len--;
2414 2414 space = 1;
2415 2415 }
2416 2416 /* END CSTYLED */
2417 2417 info->pd_vers1_name[len] = '\0';
2418 2418 info->pd_flags |= PCM_NAME_VERS1;
2419 2419 }
2420 2420 }
2421 2421 }
2422 2422
2423 2423
2424 2424 int
2425 2425 pcmcia_get_funce(client_handle_t handle, tuple_t *tuple)
2426 2426 {
2427 2427 int ret = 0;
2428 2428
2429 2429 tuple->Attributes = 0;
2430 2430 while (csx_GetNextTuple(handle, tuple) == SUCCESS) {
2431 2431 if (tuple->TupleCode == CISTPL_FUNCID) {
2432 2432 break;
2433 2433 }
2434 2434 if (tuple->TupleCode == CISTPL_FUNCE) {
2435 2435 ret = 1;
2436 2436 break;
2437 2437 }
2438 2438 tuple->Attributes = 0;
2439 2439 }
2440 2440 return (ret);
2441 2441 }
2442 2442
2443 2443 char *pcmcia_lan_types[] = {
2444 2444 "arcnet",
2445 2445 "ethernet",
2446 2446 "token-ring",
2447 2447 "localtalk",
2448 2448 "fddi",
2449 2449 "atm",
2450 2450 "wireless",
2451 2451 "reserved"
2452 2452 };
2453 2453
2454 2454 void
2455 2455 pcmcia_generic_name(int socket, struct pcm_device_info *info,
2456 2456 client_handle_t handle)
2457 2457 {
2458 2458 cistpl_funcid_t funcid;
2459 2459 cistpl_funce_t funce;
2460 2460 tuple_t tuple;
2461 2461 int which = 0;
2462 2462 int i;
2463 2463
2464 2464 tuple.Socket = socket;
2465 2465
2466 2466 tuple.DesiredTuple = CISTPL_FUNCID;
2467 2467 tuple.Attributes = 0;
2468 2468 if ((i = csx_GetFirstTuple(handle, &tuple)) ==
2469 2469 SUCCESS) {
2470 2470 /*
2471 2471 * need to make sure that CISTPL_FUNCID is not
2472 2472 * present in both a global and local CIS for MF
2473 2473 * cards. 3COM seems to do this erroneously
2474 2474 */
2475 2475
2476 2476 if (info->pd_flags & PCM_MULTI_FUNCTION &&
2477 2477 tuple.Flags & CISTPLF_GLOBAL_CIS) {
2478 2478 tuple_t ltuple;
2479 2479 ltuple = tuple;
2480 2480 ltuple.DesiredTuple = CISTPL_FUNCID;
2481 2481 ltuple.Attributes = 0;
2482 2482 if ((i = csx_GetNextTuple(handle, <uple)) ==
2483 2483 SUCCESS) {
2484 2484 /* this is the per-function funcid */
2485 2485 tuple = ltuple;
2486 2486 }
2487 2487 }
2488 2488
2489 2489 i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid);
2490 2490 if (i == SUCCESS) {
2491 2491 /* in case no function extension */
2492 2492 if (funcid.function < PCM_GENNAME_SIZE)
2493 2493 (void) strcpy(info->pd_generic_name,
2494 2494 pcmcia_generic_names[funcid.function]);
2495 2495 else
2496 2496 (void) sprintf(info->pd_generic_name,
2497 2497 "class,%x",
2498 2498 funcid.function);
2499 2499 }
2500 2500 info->pd_type = funcid.function;
2501 2501 switch (funcid.function) {
2502 2502 case TPLFUNC_LAN:
2503 2503 which = pcmcia_get_funce(handle, &tuple);
2504 2504 if (which) {
2505 2505 i = csx_Parse_CISTPL_FUNCE(handle,
2506 2506 &tuple,
2507 2507 &funce, TPLFUNC_LAN);
2508 2508 if (i == SUCCESS) {
2509 2509 i = funce.data.lan.tech;
2510 2510 if (i >= sizeof (pcmcia_lan_types) /
2511 2511 sizeof (char *)) {
2512 2512 break;
2513 2513 }
2514 2514 (void) strcpy(info->pd_generic_name,
2515 2515 pcmcia_lan_types[i]);
2516 2516 }
2517 2517 }
2518 2518 break;
2519 2519 case TPLFUNC_VIDEO:
2520 2520 #ifdef future_pcmcia_spec
2521 2521 which = pcmcia_get_funce(handle, &tuple);
2522 2522 if (which) {
2523 2523 i = csx_Parse_CISTPL_FUNCE(handle,
2524 2524 &tuple,
2525 2525 &funce, TPLFUNC_VIDEO);
2526 2526 if (i == SUCCESS) {
2527 2527 i = funce.video.tech;
2528 2528 if (i > sizeof (pcmcia_lan_types) /
2529 2529 sizeof (char *)) {
2530 2530 break;
2531 2531 }
2532 2532 (void) strcpy(info->pd_generic_names,
2533 2533 pcmcia_lan_types[i]);
2534 2534 }
2535 2535 }
2536 2536 #endif
2537 2537 break;
2538 2538 }
2539 2539 info->pd_flags |= PCM_NAME_GENERIC;
2540 2540 } else {
2541 2541 /* if no FUNCID, do we have CONFIG */
2542 2542 tuple.DesiredTuple = CISTPL_CONFIG;
2543 2543 tuple.Attributes = 0;
2544 2544 if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) {
2545 2545 info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC;
2546 2546 (void) strcpy(info->pd_generic_name,
2547 2547 pcmcia_generic_names[PCM_TYPE_MEMORY]);
2548 2548 info->pd_type = PCM_TYPE_MEMORY;
2549 2549 }
2550 2550 }
2551 2551 }
2552 2552
2553 2553
2554 2554 /*
2555 2555 * pcmcia_add_compatible()
2556 2556 * add the cached compatible property list.
2557 2557 */
2558 2558 void
2559 2559 pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info)
2560 2560 {
2561 2561 int length = 0, i;
2562 2562 char buff[MAXNAMELEN];
2563 2563 char *compat_name[8];
2564 2564 int ci = 0;
2565 2565
2566 2566 bzero(compat_name, sizeof (compat_name));
2567 2567
2568 2568 if (info->pd_flags & PCM_NAME_VERS1) {
2569 2569 (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
2570 2570 info->pd_vers1_name);
2571 2571 pcmcia_fix_string(buff); /* don't want spaces */
2572 2572 length = strlen(buff) + 1;
2573 2573 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2574 2574 (void) strcpy(compat_name[ci++], buff);
2575 2575 }
2576 2576
2577 2577 if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) ==
2578 2578 (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) {
2579 2579 (void) sprintf(buff, "%s,%x", info->pd_bind_name,
2580 2580 info->pd_function);
2581 2581 length = strlen(buff) + 1;
2582 2582 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2583 2583 (void) strcpy(compat_name[ci++], buff);
2584 2584 }
2585 2585
2586 2586 if (info->pd_flags & PCM_NAME_1275) {
2587 2587 length = strlen(info->pd_bind_name) + 1;
2588 2588 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2589 2589 (void) strcpy(compat_name[ci++], info->pd_bind_name);
2590 2590 }
2591 2591
2592 2592 if (info->pd_flags & PCM_NAME_GENERIC) {
2593 2593 if (strncmp(info->pd_generic_name, "class,", 6) == 0) {
2594 2594 /* no generic without "pccard" */
2595 2595 (void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF,
2596 2596 info->pd_generic_name);
2597 2597 } else {
2598 2598 /* first pccard,generic-name */
2599 2599 (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF,
2600 2600 info->pd_generic_name);
2601 2601 }
2602 2602 length = strlen(buff) + 1;
2603 2603 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2604 2604 (void) strcpy(compat_name[ci++], buff);
2605 2605
2606 2606 /* now the simple generic name */
2607 2607 length = strlen(info->pd_generic_name) + 1;
2608 2608 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2609 2609 (void) strcpy(compat_name[ci++], info->pd_generic_name);
2610 2610 }
2611 2611
2612 2612 if (info->pd_flags & PCM_NO_CONFIG) {
2613 2613 char *mem = "pccard,memory";
2614 2614 /*
2615 2615 * I/O cards are required to have a config tuple.
2616 2616 * there are some that violate the spec and don't
2617 2617 * but it is most likely that this is a memory card
2618 2618 * so tag it as such. "memory" is more general
2619 2619 * than other things so needs to come last.
2620 2620 */
2621 2621 length = strlen(mem) + 1;
2622 2622 compat_name[ci] = kmem_alloc(length, KM_SLEEP);
2623 2623 (void) strcpy(compat_name[ci++], mem);
2624 2624 }
2625 2625
2626 2626 if (ci == 0)
2627 2627 return;
2628 2628
2629 2629 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
2630 2630 "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS)
2631 2631 cmn_err(CE_WARN, "pcmcia: unable to create compatible prop");
2632 2632
2633 2633 for (i = 0; i < ci; i++)
2634 2634 kmem_free(compat_name[i], strlen(compat_name[i]) + 1);
2635 2635 }
2636 2636 /*
2637 2637 * CIS parsing and other PC Card specific code
2638 2638 */
2639 2639
2640 2640 /*
2641 2641 * pcmcia_get_mem_regs()
2642 2642 */
2643 2643 static int
2644 2644 pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info,
2645 2645 int type, int pctype)
2646 2646 {
2647 2647 int num_regs = 0;
2648 2648 tuple_t tuple;
2649 2649 cistpl_device_t device;
2650 2650 uint32_t curr_base;
2651 2651 int ret, len;
2652 2652 int space;
2653 2653
2654 2654 /*
2655 2655 * current plan for reg spec:
2656 2656 * device_a will be accumulated to determine max size of
2657 2657 * attribute memory. device for common. Then config
2658 2658 * tuples to get a worst case I/O size.
2659 2659 */
2660 2660 bzero(&tuple, sizeof (tuple));
2661 2661 tuple.Socket = info->pd_socket;
2662 2662
2663 2663 tuple.DesiredTuple = (cisdata_t)type;
2664 2664
2665 2665 space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE :
2666 2666 PC_REG_SPACE_MEMORY;
2667 2667 if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) {
2668 2668 bzero(&device, sizeof (device));
2669 2669
2670 2670 if (type == CISTPL_DEVICE)
2671 2671 ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple,
2672 2672 &device);
2673 2673 else
2674 2674 ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple,
2675 2675 &device);
2676 2676
2677 2677 if (ret == CS_SUCCESS) {
2678 2678 curr_base = 0;
2679 2679 for (ret = 0; ret < device.num_devices; ret++) {
2680 2680 /* need to order these for real mem first */
2681 2681 if (device.devnode[ret].type !=
2682 2682 CISTPL_DEVICE_DTYPE_NULL) {
2683 2683 /* how to represent types??? */
2684 2684 regs[num_regs].phys_hi =
2685 2685 PC_REG_PHYS_HI(0, 0,
2686 2686 pctype,
2687 2687 space,
2688 2688 info->pd_socket,
2689 2689 info->pd_function,
2690 2690 0);
2691 2691 regs[num_regs].phys_lo = curr_base;
2692 2692 len = device.devnode[ret].size_in_bytes;
2693 2693 curr_base += len;
2694 2694 regs[num_regs].phys_len = len;
2695 2695 num_regs++;
2696 2696 } else {
2697 2697 /*
2698 2698 * NULL device is a "hole"
2699 2699 */
2700 2700 curr_base +=
2701 2701 device.devnode[ret].size_in_bytes;
2702 2702 }
2703 2703 }
2704 2704 }
2705 2705 }
2706 2706 return (num_regs);
2707 2707 }
2708 2708
2709 2709 /*
2710 2710 *
2711 2711 */
2712 2712 static int
2713 2713 pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info,
2714 2714 int pctype)
2715 2715 {
2716 2716 int num_regs = 0;
2717 2717 tuple_t tuple;
2718 2718 uint32_t curr_base;
2719 2719 int len, curr, i, curr_len;
2720 2720 cistpl_config_t config;
2721 2721 cistpl_cftable_entry_t cftable;
2722 2722 struct pcm_regs tmp[16];
2723 2723 int found = 0;
2724 2724
2725 2725 bzero(&tuple, sizeof (tuple));
2726 2726 tuple.DesiredTuple = CISTPL_CONFIG;
2727 2727 tuple.Socket = info->pd_socket;
2728 2728 tuple.Attributes = 0;
2729 2729 curr_base = 0;
2730 2730 len = 0;
2731 2731
2732 2732 if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) {
2733 2733 if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
2734 2734 &tuple, &config) != CS_SUCCESS) {
2735 2735 info->pd_flags |= PCM_NO_CONFIG; /* must be memory */
2736 2736 return (0);
2737 2737 }
2738 2738 curr = 0;
2739 2739
2740 2740 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
2741 2741 tuple.Socket = info->pd_socket;
2742 2742 tuple.Attributes = 0;
2743 2743 bzero(tmp, sizeof (tmp));
2744 2744
2745 2745 while (csx_GetNextTuple(info->pd_handle, &tuple) == CS_SUCCESS) {
2746 2746 bzero(&cftable, sizeof (cftable));
2747 2747
2748 2748 if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
2749 2749 &tuple, &cftable) == CS_SUCCESS) {
2750 2750
2751 2751 /* BEGIN CSTYLED */
2752 2752 if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) {
2753 2753 /* we have an I/O entry */
2754 2754 if (cftable.io.flags &
2755 2755 CISTPL_CFTABLE_TPCE_FS_IO_RANGE) {
2756 2756 len = cftable.io.addr_lines;
2757 2757 if (len != 0)
2758 2758 len = 1 << len;
2759 2759 for (i = 0; i < cftable.io.ranges && curr < 16; i++) {
2760 2760 curr_base = cftable.io.range[i].addr;
2761 2761 curr_len = cftable.io.range[i].length;
2762 2762 if (curr_len == 0)
2763 2763 curr_len = len;
2764 2764 if (len != 0 || cftable.io.addr_lines == 0) {
2765 2765 /* we have potential relocation */
2766 2766 int mask;
2767 2767 mask = cftable.io.addr_lines ?
2768 2768 cftable.io.addr_lines : genp2(len);
2769 2769 mask = genmask(mask);
2770 2770 if ((mask & curr_base) == 0) {
2771 2771 /* more accurate length */
2772 2772 regs->phys_len = curr_len;
2773 2773 regs->phys_lo = 0;
2774 2774 regs->phys_hi =
2775 2775 PC_REG_PHYS_HI(0,
2776 2776 0,
2777 2777 pctype,
2778 2778 PC_REG_SPACE_IO,
2779 2779 info->pd_socket,
2780 2780 info->pd_function,
2781 2781 0);
2782 2782 num_regs++;
2783 2783 found = 2;
2784 2784 break;
2785 2785 }
2786 2786 }
2787 2787 tmp[curr].phys_len = curr_len;
2788 2788 tmp[curr].phys_lo = curr_base;
2789 2789 curr++;
2790 2790 found = 1;
2791 2791 }
2792 2792 if (found == 2)
2793 2793 break;
2794 2794 } else {
2795 2795 /* no I/O range so just a mask */
2796 2796 regs->phys_len = 1 << cftable.io.addr_lines;
2797 2797 regs->phys_hi =
2798 2798 PC_REG_PHYS_HI(0,
2799 2799 0,
2800 2800 pctype,
2801 2801 PC_REG_SPACE_IO,
2802 2802 info->pd_socket,
2803 2803 info->pd_function,
2804 2804 0);
2805 2805 regs->phys_lo = 0;
2806 2806 num_regs++;
2807 2807 regs++;
2808 2808 /* quit on "good" entry */
2809 2809 break;
2810 2810 }
2811 2811 /* was this the last CFTABLE Entry? */
2812 2812 if (config.last == cftable.index)
2813 2813 break;
2814 2814 }
2815 2815 /* END CSTYLE */
2816 2816 }
2817 2817 }
2818 2818 if (found == 1) {
2819 2819 /*
2820 2820 * have some non-relocatable values
2821 2821 * so we include them all for now
2822 2822 */
2823 2823 for (i = 0; i < curr && num_regs < 8; i++) {
2824 2824 regs->phys_len = tmp[i].phys_len;
2825 2825 regs->phys_lo = tmp[i].phys_lo;
2826 2826 regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype,
2827 2827 PC_REG_SPACE_IO, info->pd_socket,
2828 2828 info->pd_function, 0);
2829 2829 regs++;
2830 2830 num_regs++;
2831 2831 }
2832 2832 }
2833 2833 }
2834 2834 return (num_regs);
2835 2835 }
2836 2836
2837 2837 /*
2838 2838 * pcmcia_create_regs()
2839 2839 * create a valid set of regspecs for the card
2840 2840 * The first one is always for CIS access and naming
2841 2841 */
2842 2842 /*ARGSUSED*/
2843 2843 static void
2844 2844 pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info,
2845 2845 struct pcmcia_parent_private *ppd)
2846 2846 {
2847 2847 struct pcm_regs regs[32]; /* assume worst case */
2848 2848 int num_regs = 0;
2849 2849 int len;
2850 2850 int bustype;
2851 2851
2852 2852 if (ppd->ppd_flags & PPD_CARD_CARDBUS) {
2853 2853 /* always have a CIS map */
2854 2854 regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS,
2855 2855 PC_REG_SPACE_CONFIG,
2856 2856 info->pd_socket,
2857 2857 info->pd_function, 0);
2858 2858 bustype = PC_REG_TYPE_CARDBUS;
2859 2859 } else {
2860 2860 /* always have a CIS map */
2861 2861 regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
2862 2862 PC_REG_SPACE_ATTRIBUTE,
2863 2863 info->pd_socket,
2864 2864 info->pd_function, 0);
2865 2865 bustype = PC_REG_TYPE_16BIT;
2866 2866 }
2867 2867 regs[0].phys_lo = 0; /* always starts at zero */
2868 2868 regs[0].phys_len = 0;
2869 2869 num_regs++;
2870 2870 /*
2871 2871 * need to search CIS for other memory instances
2872 2872 */
2873 2873
2874 2874 if (info->pd_flags & PCM_OTHER_NOCIS) {
2875 2875 /* special case of memory only card without CIS */
2876 2876 regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT,
2877 2877 PC_REG_SPACE_MEMORY,
2878 2878 info->pd_socket,
2879 2879 info->pd_function, 0);
2880 2880 regs[1].phys_lo = 0;
2881 2881 regs[1].phys_len = PCM_MAX_R2_MEM;
2882 2882 num_regs++;
2883 2883 } else {
2884 2884 /*
2885 2885 * want to get any other memory and/or I/O regions
2886 2886 * on the card and represent them here.
2887 2887 */
2888 2888 num_regs += pcmcia_get_mem_regs(®s[num_regs], info,
2889 2889 CISTPL_DEVICE_A, bustype);
2890 2890 num_regs += pcmcia_get_mem_regs(®s[num_regs], info,
2891 2891 CISTPL_DEVICE, bustype);
2892 2892
2893 2893 /* now look for an I/O space to configure */
2894 2894 num_regs += pcmcia_get_io_regs(®s[num_regs], info,
2895 2895 bustype);
2896 2896
2897 2897 }
2898 2898
2899 2899 len = num_regs * sizeof (uint32_t) * 3;
2900 2900 ppd->ppd_nreg = num_regs;
2901 2901 ppd->ppd_reg = kmem_alloc(len, KM_SLEEP);
2902 2902 bcopy(regs, ppd->ppd_reg, len);
2903 2903 len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
2904 2904 ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP);
2905 2905 }
2906 2906
2907 2907
2908 2908 /*
2909 2909 * pcmcia_need_intr()
2910 2910 * check to see if an interrupt tuple exists.
2911 2911 * existence means we need one in the intrspec.
2912 2912 */
2913 2913 static int
2914 2914 pcmcia_need_intr(int socket, struct pcm_device_info *info)
2915 2915 {
2916 2916 cistpl_config_t config;
2917 2917 cistpl_cftable_entry_t cftable;
2918 2918 tuple_t tuple;
2919 2919 int i;
2920 2920
2921 2921 bzero(&tuple, sizeof (tuple));
2922 2922 tuple.DesiredTuple = CISTPL_CONFIG;
2923 2923 tuple.Socket = socket;
2924 2924 tuple.Attributes = 0;
2925 2925 if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) {
2926 2926 return (0);
2927 2927 }
2928 2928 #if defined(PCMCIA_DEBUG)
2929 2929 if (pcmcia_debug) {
2930 2930 cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n");
2931 2931 }
2932 2932 #endif
2933 2933 bzero(&config, sizeof (config));
2934 2934 if (csx_Parse_CISTPL_CONFIG(info->pd_handle,
2935 2935 &tuple, &config) != CS_SUCCESS) {
2936 2936 cmn_err(CE_WARN, "pcmcia: config failed to parse\n");
2937 2937 return (0);
2938 2938 }
2939 2939
2940 2940 for (cftable.index = (int)-1, i = -1;
2941 2941 i != config.last; i = cftable.index) {
2942 2942 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
2943 2943 tuple.Attributes = 0;
2944 2944 if (csx_GetNextTuple(info->pd_handle,
2945 2945 &tuple) != CS_SUCCESS) {
2946 2946 cmn_err(CE_WARN, "pcmcia: get cftable failed\n");
2947 2947 break;
2948 2948 }
2949 2949 bzero(&cftable, sizeof (cftable));
2950 2950 if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle,
2951 2951 &tuple, &cftable) !=
2952 2952 CS_SUCCESS) {
2953 2953 cmn_err(CE_WARN, "pcmcia: parse cftable failed\n");
2954 2954 break;
2955 2955 }
2956 2956 #if defined(PCMCIA_DEBUG)
2957 2957 if (pcmcia_debug)
2958 2958 cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n",
2959 2959 i, cftable.flags,
2960 2960 cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ);
2961 2961 #endif
2962 2962 if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ)
2963 2963 return (1);
2964 2964 }
2965 2965 return (0);
2966 2966
2967 2967 }
2968 2968
2969 2969 /*
2970 2970 * pcmcia_num_funcs()
2971 2971 * look for a CISTPL_LONGLINK_MFC
2972 2972 * if there is one, return the number of functions
2973 2973 * if there isn't one, then there is one function
2974 2974 */
2975 2975 static int
2976 2976 pcmcia_num_funcs(int socket, client_handle_t handle)
2977 2977 {
2978 2978 int count = 1;
2979 2979 cistpl_longlink_mfc_t mfc;
2980 2980 tuple_t tuple;
2981 2981
2982 2982 bzero(&tuple, sizeof (tuple_t));
2983 2983 tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
2984 2984 tuple.Socket = socket;
2985 2985 tuple.Attributes = 0;
2986 2986 if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) {
2987 2987 /* this is a multifunction card */
2988 2988 if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc,
2989 2989 CISTPL_LONGLINK_MFC) == CS_SUCCESS) {
2990 2990 count = mfc.nfuncs;
2991 2991 }
2992 2992 }
2993 2993 return (count);
2994 2994 }
2995 2995
2996 2996 client_handle_t pcmcia_cs_handle;
2997 2997
2998 2998 /*
2999 2999 * pcmcia_create_dev_info(socket)
3000 3000 * either find or create the device information structure
3001 3001 * for the card(s) just inserted. We don't care about removal yet.
3002 3002 * In any case, we will only do this at CS request
3003 3003 */
3004 3004 static void
3005 3005 pcmcia_create_dev_info(int socket)
3006 3006 {
3007 3007 struct pcm_device_info card_info;
3008 3008 client_reg_t reg;
3009 3009 cisinfo_t cisinfo;
3010 3010 int i;
3011 3011 dev_info_t *pdip;
3012 3012 static int handle_def = 0;
3013 3013
3014 3014 #if defined(PCMCIA_DEBUG)
3015 3015 if (pcmcia_debug)
3016 3016 cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n",
3017 3017 socket);
3018 3018 #endif
3019 3019
3020 3020 /*
3021 3021 * before we can do anything else, we need the parent
3022 3022 * devinfo of the socket. This gets things in the right
3023 3023 * place in the device tree.
3024 3024 */
3025 3025
3026 3026 pdip = pcm_find_parent_dip(socket);
3027 3027 if (pdip == NULL)
3028 3028 return;
3029 3029
3030 3030 /* Card Services calls needed to get CIS info */
3031 3031 reg.dip = NULL;
3032 3032 reg.Attributes = INFO_SOCKET_SERVICES;
3033 3033 reg.EventMask = 0;
3034 3034 reg.event_handler = NULL;
3035 3035 reg.Version = CS_VERSION;
3036 3036
3037 3037 bzero(&card_info, sizeof (card_info));
3038 3038
3039 3039 if (handle_def == 0) {
3040 3040 if (csx_RegisterClient(&pcmcia_cs_handle,
3041 3041 ®) != CS_SUCCESS) {
3042 3042 #if defined(PCMCIA_DEBUG)
3043 3043 if (pcmcia_debug)
3044 3044 cmn_err(CE_CONT,
3045 3045 "pcmcia: RegisterClient failed\n");
3046 3046 #endif
3047 3047 return;
3048 3048 }
3049 3049 handle_def++;
3050 3050 }
3051 3051 card_info.pd_handle = pcmcia_cs_handle;
3052 3052
3053 3053 #if defined(PCMCIA_DEBUG)
3054 3054 if (pcmcia_debug)
3055 3055 cmn_err(CE_CONT,
3056 3056 "pcmcia_create_dev_info: handle = %x\n",
3057 3057 (int)card_info.pd_handle);
3058 3058 #endif
3059 3059 card_info.pd_type = -1; /* no type to start */
3060 3060 card_info.pd_socket = socket;
3061 3061 card_info.pd_function = 0;
3062 3062 pcmcia_sockets[socket]->ls_functions = 1; /* default */
3063 3063
3064 3064 cisinfo.Socket = socket;
3065 3065
3066 3066 if ((i = csx_ValidateCIS(card_info.pd_handle,
3067 3067 &cisinfo)) != SUCCESS ||
3068 3068 cisinfo.Tuples == 0) {
3069 3069 /* no CIS means memory */
3070 3070 (void) strcpy(card_info.pd_generic_name, "memory");
3071 3071 card_info.pd_flags |= PCM_NAME_GENERIC |
3072 3072 PCM_OTHER_NOCIS | PCM_NAME_1275;
3073 3073 (void) strcpy(card_info.pd_bind_name, "pccard,memory");
3074 3074 (void) strcpy(card_info.pd_generic_name, "memory");
3075 3075 card_info.pd_type = PCM_TYPE_MEMORY;
3076 3076 } else {
3077 3077 int functions, lsocket;
3078 3078 card_info.pd_tuples = cisinfo.Tuples;
3079 3079
3080 3080 /*
3081 3081 * how many functions on the card?
3082 3082 * we need to know and then we do one
3083 3083 * child node for each function using
3084 3084 * the function specific tuples.
3085 3085 */
3086 3086 lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS);
3087 3087 functions = pcmcia_num_funcs(lsocket,
3088 3088 card_info.pd_handle);
3089 3089 pcmcia_sockets[socket]->ls_functions = functions;
3090 3090 if (functions > 1) {
3091 3091 card_info.pd_flags |= PCM_MULTI_FUNCTION;
3092 3092 }
3093 3093 for (i = 0; i < functions; i++) {
3094 3094 register int flags;
3095 3095 lsocket = CS_MAKE_SOCKET_NUMBER(socket, i);
3096 3096 card_info.pd_socket = socket;
3097 3097 card_info.pd_function = i;
3098 3098 /*
3099 3099 * new name construction
3100 3100 */
3101 3101 if (functions != 1) {
3102 3102 /* need per function handle */
3103 3103 card_info.pd_function = i;
3104 3104 /* get new handle */
3105 3105 }
3106 3106 pcmcia_1275_name(lsocket, &card_info,
3107 3107 card_info.pd_handle);
3108 3108 pcmcia_vers1_name(lsocket, &card_info,
3109 3109 card_info.pd_handle);
3110 3110 pcmcia_generic_name(lsocket, &card_info,
3111 3111 card_info.pd_handle);
3112 3112 flags = card_info.pd_flags;
3113 3113 if (!(flags & PCM_NAME_1275)) {
3114 3114 if (flags & PCM_NAME_VERS1) {
3115 3115 (void) strcpy(card_info.pd_bind_name,
3116 3116 PCMDEV_NAMEPREF);
3117 3117 card_info.pd_bind_name[
3118 3118 sizeof (PCMDEV_NAMEPREF)] = ',';
3119 3119 (void) strncpy(card_info.pd_bind_name +
3120 3120 sizeof (PCMDEV_NAMEPREF),
3121 3121 card_info.pd_vers1_name,
3122 3122 MODMAXNAMELEN -
3123 3123 sizeof (PCMDEV_NAMEPREF));
3124 3124 pcmcia_fix_string(card_info.pd_bind_name);
3125 3125 } else {
3126 3126 /*
3127 3127 * have a CIS but not the right info
3128 3128 * so treat as generic "pccard"
3129 3129 */
3130 3130 (void) strcpy(card_info.pd_generic_name,
3131 3131 "pccard,memory");
3132 3132 card_info.pd_flags |= PCM_NAME_GENERIC;
3133 3133 (void) strcpy(card_info.pd_bind_name,
3134 3134 "pccard,memory");
3135 3135 }
3136 3136 }
3137 3137 pcmcia_init_devinfo(pdip, &card_info);
3138 3138 }
3139 3139 return;
3140 3140 }
3141 3141
3142 3142 pcmcia_init_devinfo(pdip, &card_info);
3143 3143 }
3144 3144
3145 3145 /*
3146 3146 * pcmcia_init_devinfo()
3147 3147 * if there isn't a device info structure, create one
3148 3148 * if there is, we don't do much.
3149 3149 *
3150 3150 * Note: this will need updating as 1275 finalizes their spec.
3151 3151 */
3152 3152 static void
3153 3153 pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info)
3154 3154 {
3155 3155 int unit;
3156 3156 dev_info_t *dip;
3157 3157 char *name;
3158 3158 struct pcmcia_parent_private *ppd;
3159 3159
3160 3160 #if defined(PCMCIA_DEBUG)
3161 3161 if (pcmcia_debug)
3162 3162 cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name,
3163 3163 info->pd_socket);
3164 3164 #endif
3165 3165
3166 3166 /*
3167 3167 * find out if there is already an instance of this
3168 3168 * device. We don't want to create a new one unnecessarily
3169 3169 */
3170 3170 unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function);
3171 3171
3172 3172 dip = pcm_find_devinfo(pdip, info, unit);
3173 3173 if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip,
3174 3174 DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) {
3175 3175 /* it already exist but isn't a .conf file */
3176 3176
3177 3177 #if defined(PCMCIA_DEBUG)
3178 3178 if (pcmcia_debug)
3179 3179 cmn_err(CE_CONT, "\tfound existing device node (%s)\n",
3180 3180 ddi_get_name(dip));
3181 3181 #endif
3182 3182 if (strlen(info->pd_vers1_name) > 0)
3183 3183 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
3184 3184 dip, PCM_DEV_MODEL, info->pd_vers1_name);
3185 3185
3186 3186 ppd = (struct pcmcia_parent_private *)
3187 3187 ddi_get_parent_data(dip);
3188 3188
3189 3189 pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
3190 3190 dip;
3191 3191
3192 3192 ppd->ppd_active = 1;
3193 3193
3194 3194 if (ndi_devi_online(dip, 0) == NDI_FAILURE) {
3195 3195 pcmcia_sockets[info->pd_socket]-> \
3196 3196 ls_dip[info->pd_function] = NULL;
3197 3197 ppd->ppd_active = 0;
3198 3198 }
3199 3199 } else {
3200 3200
3201 3201 char *dtype;
3202 3202
3203 3203 #if defined(PCMCIA_DEBUG)
3204 3204 if (pcmcia_debug)
3205 3205 cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n",
3206 3206 info->pd_bind_name, info->pd_socket,
3207 3207 info->pd_generic_name);
3208 3208 #endif
3209 3209
3210 3210 if (info->pd_flags & PCM_NAME_GENERIC)
3211 3211 name = info->pd_generic_name;
3212 3212 else
3213 3213 name = info->pd_bind_name;
3214 3214
3215 3215 if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID,
3216 3216 &dip) !=
3217 3217 NDI_SUCCESS) {
3218 3218 cmn_err(CE_WARN,
3219 3219 "pcmcia: unable to create device [%s](%d)\n",
3220 3220 name, info->pd_socket);
3221 3221 return;
3222 3222 }
3223 3223 /*
3224 3224 * construct the "compatible" property if the device
3225 3225 * has a generic name
3226 3226 */
3227 3227 pcmcia_add_compatible(dip, info);
3228 3228
3229 3229 ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private),
3230 3230 KM_SLEEP);
3231 3231
3232 3232 ppd->ppd_socket = info->pd_socket;
3233 3233 ppd->ppd_function = info->pd_function;
3234 3234
3235 3235 /*
3236 3236 * add the "socket" property
3237 3237 * the value of this property contains the logical PCMCIA
3238 3238 * socket number the device has been inserted in, along
3239 3239 * with the function # if the device is part of a
3240 3240 * multi-function device.
3241 3241 */
3242 3242 (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
3243 3243 PCM_DEV_SOCKET, unit);
3244 3244
3245 3245 if (info->pd_flags & PCM_MULTI_FUNCTION)
3246 3246 ppd->ppd_flags |= PPD_CARD_MULTI;
3247 3247
3248 3248 /*
3249 3249 * determine all the properties we need for PPD
3250 3250 * then create the properties
3251 3251 */
3252 3252 /* socket is unique */
3253 3253 pcmcia_find_regs(dip, info, ppd);
3254 3254
3255 3255 ppd->ppd_intr = pcmcia_need_intr(unit, info);
3256 3256
3257 3257 if (ppd->ppd_nreg > 0)
3258 3258 (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3259 3259 "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg *
3260 3260 sizeof (struct pcm_regs) / sizeof (int));
3261 3261 if (ppd->ppd_intr) {
3262 3262 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
3263 3263 "interrupts", ppd->ppd_intr);
3264 3264 ppd->ppd_intrspec =
3265 3265 kmem_zalloc(sizeof (struct intrspec), KM_SLEEP);
3266 3266 }
3267 3267
3268 3268 /* set parent private - our own format */
3269 3269 ddi_set_parent_data(dip, (caddr_t)ppd);
3270 3270
3271 3271 /* init the device type */
3272 3272 if (info->pd_type >= 0 &&
3273 3273 info->pd_type < (sizeof (pcmcia_dev_type) /
3274 3274 (sizeof (char *))))
3275 3275 dtype = pcmcia_dev_type[info->pd_type];
3276 3276 else
3277 3277 dtype = "unknown";
3278 3278
3279 3279 if (strlen(info->pd_vers1_name) > 0)
3280 3280 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
3281 3281 dip, PCM_DEV_MODEL, info->pd_vers1_name);
3282 3282
3283 3283 (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
3284 3284 PCM_DEVICETYPE, dtype);
3285 3285
3286 3286 /* set PC Card as active and present in socket */
3287 3287 pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] =
3288 3288 dip;
3289 3289
3290 3290 ppd->ppd_active = 1;
3291 3291
3292 3292 /*
3293 3293 * We should not call ndi_devi_online here if
3294 3294 * pcmcia attach is in progress. This causes a deadlock.
3295 3295 */
3296 3296 if (pcmcia_dip != dip) {
3297 3297 if (ndi_devi_online_async(dip, 0)
3298 3298 != NDI_SUCCESS) {
3299 3299 pcmcia_sockets[info->pd_socket]->\
3300 3300 ls_dip[info->pd_function] = NULL;
3301 3301 pcmcia_ppd_free(ppd);
3302 3302 (void) ndi_devi_free(dip);
3303 3303 return;
3304 3304 }
3305 3305 }
3306 3306
3307 3307 #if defined(PCMCIA_DEBUG)
3308 3308 if (pcmcia_debug)
3309 3309 cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n",
3310 3310 ddi_get_name(dip), info->pd_socket);
3311 3311 #endif
3312 3312 }
3313 3313
3314 3314 /*
3315 3315 * inform the event manager that a child was added
3316 3316 * to the device tree.
3317 3317 */
3318 3318 pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip));
3319 3319
3320 3320 #if defined(PCMCIA_DEBUG)
3321 3321 if (pcmcia_debug > 1) {
3322 3322 pcmcia_dump_minors(dip);
3323 3323 }
3324 3324 #endif
3325 3325 }
3326 3326
3327 3327 /*
3328 3328 * free any allocated parent-private data
3329 3329 */
3330 3330 static void
3331 3331 pcmcia_ppd_free(struct pcmcia_parent_private *ppd)
3332 3332 {
3333 3333 size_t len;
3334 3334
3335 3335 if (ppd->ppd_nreg != 0) {
3336 3336 len = ppd->ppd_nreg * sizeof (uint32_t) * 3;
3337 3337 kmem_free(ppd->ppd_reg, len);
3338 3338 len = sizeof (struct pcm_regs) * ppd->ppd_nreg;
3339 3339 kmem_free(ppd->ppd_assigned, len);
3340 3340 }
3341 3341
3342 3342 /*
3343 3343 * pcmcia only allocates 1 intrspec today
3344 3344 */
3345 3345 if (ppd->ppd_intr != 0) {
3346 3346 len = sizeof (struct intrspec) * ppd->ppd_intr;
3347 3347 kmem_free(ppd->ppd_intrspec, len);
3348 3348 }
3349 3349
3350 3350 kmem_free(ppd, sizeof (*ppd));
3351 3351 }
3352 3352
3353 3353
3354 3354 /*
3355 3355 * pcmcia_get_devinfo(socket)
3356 3356 * entry point to allow finding the device info structure
3357 3357 * for a given logical socket. Used by event manager
3358 3358 */
3359 3359 dev_info_t *
3360 3360 pcmcia_get_devinfo(int socket)
3361 3361 {
3362 3362 int func = CS_GET_FUNCTION_NUMBER(socket);
3363 3363 socket = CS_GET_SOCKET_NUMBER(socket);
3364 3364 if (pcmcia_sockets[socket])
3365 3365 return (pcmcia_sockets[socket]->ls_dip[func]);
3366 3366 return ((dev_info_t *)NULL);
3367 3367 }
3368 3368
3369 3369 /*
3370 3370 * CSGetCookiesAndDip()
3371 3371 * get info needed by CS to setup soft interrupt handler and provide
3372 3372 * socket-specific adapter information
3373 3373 */
3374 3374 static int
3375 3375 GetCookiesAndDip(sservice_t *serv)
3376 3376 {
3377 3377 pcmcia_logical_socket_t *socket;
3378 3378 csss_adapter_info_t *ai;
3379 3379 int sock;
3380 3380
3381 3381 sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket);
3382 3382
3383 3383 if (sock >= pcmcia_num_sockets ||
3384 3384 (int)serv->get_cookies.socket < 0)
3385 3385 return (BAD_SOCKET);
3386 3386
3387 3387 socket = pcmcia_sockets[sock];
3388 3388 ai = &serv->get_cookies.adapter_info;
3389 3389 serv->get_cookies.dip = socket->ls_adapter->pca_dip;
3390 3390 serv->get_cookies.iblock = socket->ls_adapter->pca_iblock;
3391 3391 serv->get_cookies.idevice = socket->ls_adapter->pca_idev;
3392 3392
3393 3393 /*
3394 3394 * Setup the adapter info for Card Services
3395 3395 */
3396 3396 (void) strcpy(ai->name, socket->ls_adapter->pca_name);
3397 3397 ai->major = socket->ls_adapter->pca_module;
3398 3398 ai->minor = socket->ls_adapter->pca_unit;
3399 3399 ai->number = socket->ls_adapter->pca_number;
3400 3400 ai->num_sockets = socket->ls_adapter->pca_numsockets;
3401 3401 ai->first_socket = socket->ls_adapter->pca_first_socket;
3402 3402
3403 3403 return (SUCCESS);
3404 3404 }
3405 3405
3406 3406 /*
3407 3407 * Note:
3408 3408 * The following functions that start with 'SS'
3409 3409 * implement SocketServices interfaces. They
3410 3410 * simply map the socket and/or window number to
3411 3411 * the adapter specific number based on the general
3412 3412 * value that CardServices uses.
3413 3413 *
3414 3414 * See the descriptions in SocketServices for
3415 3415 * details. Also refer to specific adapter drivers
3416 3416 * for implementation reference.
3417 3417 */
3418 3418
3419 3419 static int
3420 3420 SSGetAdapter(get_adapter_t *adapter)
3421 3421 {
3422 3422 int n;
3423 3423 get_adapter_t info;
3424 3424
3425 3425 adapter->state = (unsigned)0xFFFFFFFF;
3426 3426 adapter->SCRouting = 0xFFFFFFFF;
3427 3427
3428 3428 for (n = 0; n < pcmcia_num_adapters; n++) {
3429 3429 GET_ADAPTER(pcmcia_adapters[n]->pca_if,
3430 3430 pcmcia_adapters[n]->pca_dip, &info);
3431 3431 adapter->state &= info.state;
3432 3432 adapter->SCRouting &= info.SCRouting;
3433 3433 }
3434 3434
3435 3435 return (SUCCESS);
3436 3436 }
3437 3437
3438 3438 static int
3439 3439 SSGetPage(get_page_t *page)
3440 3440 {
3441 3441 pcmcia_logical_window_t *window;
3442 3442 get_page_t newpage;
3443 3443 int retval, win;
3444 3444
3445 3445 if (page->window > pcmcia_num_windows) {
3446 3446 return (BAD_WINDOW);
3447 3447 }
3448 3448
3449 3449 window = pcmcia_windows[page->window];
3450 3450 newpage = *page;
3451 3451 win = newpage.window = window->lw_window; /* real window */
3452 3452
3453 3453 retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip,
3454 3454 &newpage);
3455 3455 if (retval == SUCCESS) {
3456 3456 *page = newpage;
3457 3457 page->window = win;
3458 3458 }
3459 3459 return (retval);
3460 3460 }
3461 3461
3462 3462 static int
3463 3463 SSGetSocket(get_socket_t *socket)
3464 3464 {
3465 3465 int retval, sock;
3466 3466 get_socket_t newsocket;
3467 3467 pcmcia_logical_socket_t *sockp;
3468 3468
3469 3469 sock = socket->socket;
3470 3470 if (sock > pcmcia_num_sockets ||
3471 3471 (sockp = pcmcia_sockets[sock]) == NULL) {
3472 3472 return (BAD_SOCKET);
3473 3473 }
3474 3474
3475 3475 newsocket = *socket;
3476 3476 newsocket.socket = sockp->ls_socket;
3477 3477 retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3478 3478 &newsocket);
3479 3479 if (retval == SUCCESS) {
3480 3480 newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
3481 3481 newsocket.VccLevel,
3482 3482 VCC);
3483 3483 newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
3484 3484 newsocket.Vpp1Level,
3485 3485 VPP1);
3486 3486 newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
3487 3487 newsocket.Vpp2Level,
3488 3488 VPP2);
3489 3489 *socket = newsocket;
3490 3490 socket->socket = sock;
3491 3491 }
3492 3492
3493 3493 return (retval);
3494 3494 }
3495 3495
3496 3496 static int
3497 3497 SSGetStatus(get_ss_status_t *status)
3498 3498 {
3499 3499 get_ss_status_t newstat;
3500 3500 int sock, retval;
3501 3501 pcmcia_logical_socket_t *sockp;
3502 3502
3503 3503 sock = status->socket;
3504 3504 if (sock > pcmcia_num_sockets ||
3505 3505 (sockp = pcmcia_sockets[sock]) == NULL) {
3506 3506 return (BAD_SOCKET);
3507 3507 }
3508 3508
3509 3509 newstat = *status;
3510 3510 newstat.socket = sockp->ls_socket;
3511 3511 retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip,
3512 3512 &newstat);
3513 3513 if (retval == SUCCESS) {
3514 3514 *status = newstat;
3515 3515 status->socket = sock;
3516 3516 }
3517 3517
3518 3518 return (retval);
3519 3519 }
3520 3520
3521 3521 static int
3522 3522 SSGetWindow(get_window_t *window)
3523 3523 {
3524 3524 int win, retval;
3525 3525 get_window_t newwin;
3526 3526 pcmcia_logical_window_t *winp;
3527 3527
3528 3528 win = window->window;
3529 3529 winp = pcmcia_windows[win];
3530 3530 newwin = *window;
3531 3531 newwin.window = winp->lw_window;
3532 3532
3533 3533 retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
3534 3534 &newwin);
3535 3535 if (retval == SUCCESS) {
3536 3536 newwin.socket = winp->lw_socket;
3537 3537 newwin.window = win;
3538 3538 *window = newwin;
3539 3539 }
3540 3540 return (retval);
3541 3541 }
3542 3542
3543 3543 /*
3544 3544 * SSInquireAdapter()
3545 3545 * Get the capabilities of the "generic" adapter
3546 3546 * we are exporting to CS.
3547 3547 */
3548 3548 static int
3549 3549 SSInquireAdapter(inquire_adapter_t *adapter)
3550 3550 {
3551 3551 adapter->NumSockets = pcmcia_num_sockets;
3552 3552 adapter->NumWindows = pcmcia_num_windows;
3553 3553 adapter->NumEDCs = 0;
3554 3554 /*
3555 3555 * notes: Adapter Capabilities are going to be difficult to
3556 3556 * determine with reliability. Fortunately, most of them
3557 3557 * don't matter under Solaris or can be handled transparently
3558 3558 */
3559 3559 adapter->AdpCaps = 0; /* need to fix these */
3560 3560 /*
3561 3561 * interrupts need a little work. For x86, the valid IRQs will
3562 3562 * be restricted to those that the system has exported to the nexus.
3563 3563 * for SPARC, it will be the DoRight values.
3564 3564 */
3565 3565 adapter->ActiveHigh = 0;
3566 3566 adapter->ActiveLow = 0;
3567 3567 adapter->power_entry = pcmcia_power_table; /* until we resolve this */
3568 3568 adapter->NumPower = pcmcia_num_power;
3569 3569 return (SUCCESS);
3570 3570 }
3571 3571
3572 3572 static int
3573 3573 SSInquireSocket(inquire_socket_t *socket)
3574 3574 {
3575 3575 int retval, sock;
3576 3576 inquire_socket_t newsocket;
3577 3577 pcmcia_logical_socket_t *sockp;
3578 3578
3579 3579 sock = socket->socket;
3580 3580 if (sock > pcmcia_num_sockets ||
3581 3581 (sockp = pcmcia_sockets[sock]) == NULL)
3582 3582 return (BAD_SOCKET);
3583 3583 newsocket = *socket;
3584 3584 newsocket.socket = sockp->ls_socket;
3585 3585 retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3586 3586 &newsocket);
3587 3587 if (retval == SUCCESS) {
3588 3588 *socket = newsocket;
3589 3589 socket->socket = sock;
3590 3590 }
3591 3591 return (retval);
3592 3592 }
3593 3593
3594 3594 static int
3595 3595 SSInquireWindow(inquire_window_t *window)
3596 3596 {
3597 3597 int retval, win;
3598 3598 pcmcia_logical_window_t *winp;
3599 3599 inquire_window_t newwin;
3600 3600 int slide;
3601 3601
3602 3602 win = window->window;
3603 3603 if (win > pcmcia_num_windows)
3604 3604 return (BAD_WINDOW);
3605 3605
3606 3606 winp = pcmcia_windows[win];
3607 3607 newwin = *window;
3608 3608 newwin.window = winp->lw_window;
3609 3609 retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip,
3610 3610 &newwin);
3611 3611 #if defined(PCMCIA_DEBUG)
3612 3612 if (pcmcia_debug > 1)
3613 3613 cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n",
3614 3614 win, newwin.window);
3615 3615 #endif
3616 3616 if (retval == SUCCESS) {
3617 3617 *window = newwin;
3618 3618 /* just in case */
3619 3619 window->iowin_char.IOWndCaps &= ~WC_BASE;
3620 3620 slide = winp->lw_adapter->pca_first_socket;
3621 3621 /*
3622 3622 * note that sockets are relative to the adapter.
3623 3623 * we have to adjust the bits to show a logical
3624 3624 * version.
3625 3625 */
3626 3626
3627 3627 pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0);
3628 3628
3629 3629 #if defined(PCMCIA_DEBUG)
3630 3630 if (pcmcia_debug > 1) {
3631 3631 cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n",
3632 3632 (int)*(uint32_t *)newwin.Sockets,
3633 3633 (int)*(uint32_t *)window->Sockets);
3634 3634 cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps,
3635 3635 window->mem_win_char.MemWndCaps,
3636 3636 window->mem_win_char.MinSize);
3637 3637 }
3638 3638 #endif
3639 3639 window->window = win;
3640 3640 }
3641 3641 return (retval);
3642 3642 }
3643 3643
3644 3644 static int
3645 3645 SSResetSocket(int socket, int mode)
3646 3646 {
3647 3647 pcmcia_logical_socket_t *sockp;
3648 3648
3649 3649 if (socket >= pcmcia_num_sockets ||
3650 3650 (sockp = pcmcia_sockets[socket]) == NULL)
3651 3651 return (BAD_SOCKET);
3652 3652
3653 3653 return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3654 3654 sockp->ls_socket, mode));
3655 3655 }
3656 3656
3657 3657 static int
3658 3658 SSSetPage(set_page_t *page)
3659 3659 {
3660 3660 int window, retval;
3661 3661 set_page_t newpage;
3662 3662 pcmcia_logical_window_t *winp;
3663 3663
3664 3664 window = page->window;
3665 3665 if (window > pcmcia_num_windows) {
3666 3666 #if defined(PCMCIA_DEBUG)
3667 3667 if (pcmcia_debug > 1)
3668 3668 cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n",
3669 3669 window, pcmcia_num_windows);
3670 3670 #endif
3671 3671 return (BAD_WINDOW);
3672 3672 }
3673 3673
3674 3674 winp = pcmcia_windows[window];
3675 3675 newpage = *page;
3676 3676 newpage.window = winp->lw_window;
3677 3677 retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage);
3678 3678 if (retval == SUCCESS) {
3679 3679 newpage.window = window;
3680 3680 *page = newpage;
3681 3681 }
3682 3682 #if defined(PCMCIA_DEBUG)
3683 3683 if ((pcmcia_debug > 1) && retval != SUCCESS)
3684 3684 cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval);
3685 3685 #endif
3686 3686 return (retval);
3687 3687 }
3688 3688
3689 3689 static int
3690 3690 SSSetWindow(set_window_t *win)
3691 3691 {
3692 3692 int socket, window, retval, func;
3693 3693 set_window_t newwin;
3694 3694 pcmcia_logical_window_t *winp;
3695 3695 pcmcia_logical_socket_t *sockp;
3696 3696
3697 3697 window = win->window;
3698 3698 if (window > pcmcia_num_windows)
3699 3699 return (BAD_WINDOW);
3700 3700
3701 3701 socket = CS_GET_SOCKET_NUMBER(win->socket);
3702 3702 func = CS_GET_FUNCTION_NUMBER(win->socket);
3703 3703
3704 3704 if (socket > pcmcia_num_sockets ||
3705 3705 (sockp = pcmcia_sockets[socket]) == NULL) {
3706 3706 return (BAD_SOCKET);
3707 3707 }
3708 3708
3709 3709 winp = pcmcia_windows[window];
3710 3710 winp->lw_socket = win->socket; /* reverse map */
3711 3711 newwin = *win;
3712 3712 newwin.window = winp->lw_window;
3713 3713 newwin.socket = sockp->ls_socket;
3714 3714 newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */
3715 3715
3716 3716 retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin);
3717 3717 if (retval == SUCCESS) {
3718 3718 newwin.window = window;
3719 3719 newwin.socket = winp->lw_socket;
3720 3720 *win = newwin;
3721 3721 }
3722 3722 return (retval);
3723 3723 }
3724 3724
3725 3725 static int
3726 3726 SSSetSocket(set_socket_t *socket)
3727 3727 {
3728 3728 int sock, retval;
3729 3729 pcmcia_logical_socket_t *sockp;
3730 3730 set_socket_t newsock;
3731 3731
3732 3732 sock = socket->socket;
3733 3733 if (sock > pcmcia_num_sockets ||
3734 3734 (sockp = pcmcia_sockets[sock]) == NULL) {
3735 3735 return (BAD_SOCKET);
3736 3736 }
3737 3737
3738 3738 newsock = *socket;
3739 3739 /* note: we force CS to always get insert/removal events */
3740 3740 sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) |
3741 3741 PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL) |
3742 3742 PCE_E2M(PCE_PM_SUSPEND);
3743 3743 #if defined(PCMCIA_DEBUG)
3744 3744 if (pcmcia_debug > 1)
3745 3745 cmn_err(CE_CONT,
3746 3746 "SetSocket: SCIntMask = %x\n", newsock.SCIntMask);
3747 3747 #endif
3748 3748 newsock.socket = sockp->ls_socket;
3749 3749 newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter,
3750 3750 newsock.VccLevel, VCC);
3751 3751 newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter,
3752 3752 newsock.Vpp1Level, VPP1);
3753 3753 newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter,
3754 3754 newsock.Vpp2Level, VPP2);
3755 3755 retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip,
3756 3756 &newsock);
3757 3757 if (retval == SUCCESS) {
3758 3758 newsock.socket = sock;
3759 3759 newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter,
3760 3760 newsock.VccLevel,
3761 3761 VCC);
3762 3762 newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter,
3763 3763 newsock.Vpp1Level,
3764 3764 VPP1);
3765 3765 newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter,
3766 3766 newsock.Vpp2Level,
3767 3767 VPP2);
3768 3768 *socket = newsock;
3769 3769 if (socket->IREQRouting & IRQ_ENABLE) {
3770 3770 sockp->ls_flags |= PCS_IRQ_ENABLED;
3771 3771 } else {
3772 3772 sockp->ls_flags &= ~PCS_IRQ_ENABLED;
3773 3773 }
3774 3774 }
3775 3775 return (retval);
3776 3776 }
3777 3777
3778 3778 /*
3779 3779 * SSSetIRQHandler()
3780 3780 * arrange for IRQ to be allocated if appropriate and always
3781 3781 * arrange that PC Card interrupt handlers get called.
3782 3782 */
3783 3783 static int
3784 3784 SSSetIRQHandler(set_irq_handler_t *handler)
3785 3785 {
3786 3786 int sock, retval, func;
3787 3787 pcmcia_logical_socket_t *sockp;
3788 3788 struct pcmcia_parent_private *ppd;
3789 3789 dev_info_t *dip;
3790 3790 ddi_iblock_cookie_t iblk;
3791 3791 ddi_idevice_cookie_t idev;
3792 3792
3793 3793 sock = CS_GET_SOCKET_NUMBER(handler->socket);
3794 3794 func = CS_GET_FUNCTION_NUMBER(handler->socket);
3795 3795 if (sock > pcmcia_num_sockets ||
3796 3796 (sockp = pcmcia_sockets[sock]) == NULL) {
3797 3797 return (BAD_SOCKET);
3798 3798 }
3799 3799 #if defined(PCMCIA_DEBUG)
3800 3800 if (pcmcia_debug) {
3801 3801
3802 3802 cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n",
3803 3803 sock, func);
3804 3804 cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n",
3805 3805 (void *)handler->handler, handler->socket, handler->irq,
3806 3806 handler->handler_id);
3807 3807 }
3808 3808 #endif
3809 3809 dip = sockp->ls_dip[func];
3810 3810
3811 3811 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
3812 3812
3813 3813 handler->iblk_cookie = &iblk;
3814 3814 handler->idev_cookie = &idev;
3815 3815
3816 3816 retval = ddi_add_intr(dip, 0, handler->iblk_cookie,
3817 3817 handler->idev_cookie,
3818 3818 (uint32_t(*)(caddr_t)) handler->handler,
3819 3819 handler->arg1);
3820 3820
3821 3821 if (retval == DDI_SUCCESS) {
3822 3822 handler->iblk_cookie = &sockp->ls_iblk;
3823 3823 handler->idev_cookie = &sockp->ls_idev;
3824 3824 handler->irq = ppd->ppd_intrspec->intrspec_vec;
3825 3825 retval = SUCCESS;
3826 3826 } else {
3827 3827 retval = sockp->ls_error;
3828 3828 }
3829 3829 return (retval);
3830 3830 }
3831 3831
3832 3832 /*
3833 3833 * SSClearIRQHandler()
3834 3834 * Arrange to have the interrupt handler specified removed
3835 3835 * from the interrupt list.
3836 3836 */
3837 3837 static int
3838 3838 SSClearIRQHandler(clear_irq_handler_t *handler)
3839 3839 {
3840 3840 int sock, func;
3841 3841 pcmcia_logical_socket_t *sockp;
3842 3842 dev_info_t *dip;
3843 3843
3844 3844 sock = CS_GET_SOCKET_NUMBER(handler->socket);
3845 3845 func = CS_GET_FUNCTION_NUMBER(handler->socket);
3846 3846
3847 3847 #if defined(PCMCIA_DEBUG)
3848 3848 if (pcmcia_debug) {
3849 3849
3850 3850 cmn_err(CE_CONT,
3851 3851 "SSClearIRQHandler: socket=%x, function=%x\n",
3852 3852 sock, func);
3853 3853 cmn_err(CE_CONT,
3854 3854 "\thandler(%p): socket=%x, id=%x\n",
3855 3855 (void *)handler, handler->socket,
3856 3856 handler->handler_id);
3857 3857 }
3858 3858 #endif
3859 3859
3860 3860 if (sock > pcmcia_num_sockets ||
3861 3861 (sockp = pcmcia_sockets[sock]) == NULL) {
3862 3862 return (BAD_SOCKET);
3863 3863 }
3864 3864 dip = sockp->ls_dip[func];
3865 3865 if (dip) {
3866 3866 ddi_remove_intr(dip, 0, NULL);
3867 3867 return (SUCCESS);
3868 3868 }
3869 3869 return (BAD_SOCKET);
3870 3870 }
3871 3871
3872 3872
3873 3873 /*
3874 3874 * pcm_pathname()
3875 3875 * make a partial path from dip.
3876 3876 * used to mknods relative to /devices/pcmcia/
3877 3877 *
3878 3878 * XXX - we now use ddi_get_name_addr to get the "address" portion
3879 3879 * of the name; that way, we only have to modify the name creation
3880 3880 * algorithm in one place
3881 3881 */
3882 3882 static void
3883 3883 pcm_pathname(dev_info_t *dip, char *name, char *path)
3884 3884 {
3885 3885 (void) sprintf(path, "%s@%s:%s", ddi_node_name(dip),
3886 3886 ddi_get_name_addr(dip), name);
3887 3887 }
3888 3888
3889 3889 /*
3890 3890 * pcmcia_create_device()
3891 3891 * create the /devices entries for the driver
3892 3892 * it is assumed that the PC Card driver will do a
3893 3893 * RegisterClient for each subdevice.
3894 3894 * The device type string is encoded here to match
3895 3895 * the standardized names when possible.
3896 3896 * XXX - note that we may need to provide a way for the
3897 3897 * caller to specify the complete name string that
3898 3898 * we pass to ddi_set_name_addr
3899 3899 */
3900 3900 static int
3901 3901 pcmcia_create_device(ss_make_device_node_t *init)
3902 3902 {
3903 3903 int err = SUCCESS;
3904 3904 struct pcm_make_dev device;
3905 3905 struct dev_ops *ops;
3906 3906 major_t major;
3907 3907
3908 3908 /*
3909 3909 * Now that we have the name, create it.
3910 3910 */
3911 3911
3912 3912 bzero(&device, sizeof (device));
3913 3913 if (init->flags & SS_CSINITDEV_CREATE_DEVICE) {
3914 3914 if ((err = ddi_create_minor_node(init->dip,
3915 3915 init->name,
3916 3916 init->spec_type,
3917 3917 init->minor_num,
3918 3918 init->node_type,
3919 3919 0)) != DDI_SUCCESS) {
3920 3920 #if defined(PCMCIA_DEBUG)
3921 3921 if (pcmcia_debug)
3922 3922 cmn_err(CE_CONT,
3923 3923 "pcmcia_create_device: failed "
3924 3924 "create\n");
3925 3925 #endif
3926 3926 return (BAD_ATTRIBUTE);
3927 3927 }
3928 3928
3929 3929 major = ddi_driver_major(init->dip);
3930 3930 ops = ddi_get_driver(init->dip);
3931 3931 LOCK_DEV_OPS(&devnamesp[major].dn_lock);
3932 3932 INCR_DEV_OPS_REF(ops);
3933 3933 (void) ddi_pathname(init->dip, device.path);
3934 3934 DECR_DEV_OPS_REF(ops);
3935 3935 UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
3936 3936 (void) sprintf(device.path + strlen(device.path), ":%s",
3937 3937 init->name);
3938 3938
3939 3939 (void) strcpy(device.driver, ddi_binding_name(init->dip));
3940 3940 #if defined(PCMCIA_DEBUG)
3941 3941 if (pcmcia_debug)
3942 3942 cmn_err(CE_CONT,
3943 3943 "pcmcia_create_device: created %s "
3944 3944 "from %s [%s]\n",
3945 3945 device.path, init->name, device.driver);
3946 3946 #endif
3947 3947 device.dev =
3948 3948 makedevice(ddi_driver_major(init->dip), init->minor_num);
3949 3949 device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ?
3950 3950 PCM_EVENT_MORE : 0;
3951 3951 device.type = init->spec_type;
3952 3952 device.op = SS_CSINITDEV_CREATE_DEVICE;
3953 3953 device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
3954 3954 DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
3955 3955 -1);
3956 3956 } else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) {
3957 3957 device.op = SS_CSINITDEV_REMOVE_DEVICE;
3958 3958 device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip,
3959 3959 DDI_PROP_CANSLEEP, PCM_DEV_SOCKET,
3960 3960 -1);
3961 3961 if (init->name != NULL)
3962 3962 (void) strcpy(device.path, init->name);
3963 3963 device.dev = makedevice(ddi_driver_major(init->dip), 0);
3964 3964 ddi_remove_minor_node(init->dip, init->name);
3965 3965 }
3966 3966
3967 3967 /*
3968 3968 * we send an event for ALL devices created.
3969 3969 * To do otherwise ties us to using drvconfig
3970 3970 * forever. There are relatively few devices
3971 3971 * ever created so no need to do otherwise.
3972 3972 * The existence of the event manager must never
3973 3973 * be visible to a PCMCIA device driver.
3974 3974 */
3975 3975 pcm_event_manager(PCE_INIT_DEV, device.socket, &device);
3976 3976
3977 3977 return (err);
3978 3978 }
3979 3979
3980 3980 /*
3981 3981 * pcmcia_get_minors()
3982 3982 * We need to traverse the minor node list of the
3983 3983 * dip if there are any. This takes two passes;
3984 3984 * one to get the count and buffer size and the
3985 3985 * other to actually copy the data into the buffer.
3986 3986 * The framework requires that the dip be locked
3987 3987 * during this time to avoid breakage as well as the
3988 3988 * driver being locked.
3989 3989 */
3990 3990 int
3991 3991 pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors)
3992 3992 {
3993 3993 int circ;
3994 3994 int count = 0;
3995 3995 struct ddi_minor_data *dp;
3996 3996 struct pcm_make_dev *md;
3997 3997 int socket;
3998 3998 major_t major;
3999 3999 struct dev_ops *ops;
4000 4000
4001 4001 socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4002 4002 PCM_DEV_SOCKET, -1);
4003 4003 ndi_devi_enter(dip, &circ);
4004 4004 if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) {
4005 4005 for (dp = DEVI(dip)->devi_minor;
4006 4006 dp != (struct ddi_minor_data *)NULL;
4007 4007 dp = dp->next) {
4008 4008 count++; /* have one more */
4009 4009 }
4010 4010 /* we now know how many nodes to allocate */
4011 4011 md = kmem_zalloc(count * sizeof (struct pcm_make_dev),
4012 4012 KM_NOSLEEP);
4013 4013 if (md != NULL) {
4014 4014 *minors = md;
4015 4015 for (dp = DEVI(dip)->devi_minor;
4016 4016 dp != (struct ddi_minor_data *)NULL;
4017 4017 dp = dp->next, md++) {
4018 4018 #if defined(PCMCIA_DEBUG)
4019 4019 if (pcmcia_debug > 1) {
4020 4020 cmn_err(CE_CONT,
4021 4021 "pcmcia_get_minors: name=%s,"
4022 4022 "socket=%d, stype=%x, "
4023 4023 "ntype=%s, dev_t=%x",
4024 4024 dp->ddm_name,
4025 4025 socket,
4026 4026 dp->ddm_spec_type,
4027 4027 dp->ddm_node_type,
4028 4028 (int)dp->ddm_dev);
4029 4029 cmn_err(CE_CONT,
4030 4030 "\tbind name = %s\n",
4031 4031 ddi_binding_name(dip));
4032 4032 }
4033 4033 #endif
4034 4034 md->socket = socket;
4035 4035 md->op = SS_CSINITDEV_CREATE_DEVICE;
4036 4036 md->dev = dp->ddm_dev;
4037 4037 md->type = dp->ddm_spec_type;
4038 4038 (void) strcpy(md->driver,
4039 4039 ddi_binding_name(dip));
4040 4040 major = ddi_driver_major(dip);
4041 4041 ops = ddi_get_driver(dip);
4042 4042 LOCK_DEV_OPS(&devnamesp[major].dn_lock);
4043 4043 pcm_pathname(dip, dp->ddm_name, md->path);
4044 4044 INCR_DEV_OPS_REF(ops);
4045 4045 (void) ddi_pathname(dip, md->path);
4046 4046 DECR_DEV_OPS_REF(ops);
4047 4047 UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
4048 4048 (void) sprintf(md->path + strlen(md->path),
4049 4049 ":%s", dp->ddm_name);
4050 4050 if (dp->next == NULL)
4051 4051 /* no more */
4052 4052 md->flags |= PCM_EVENT_MORE;
4053 4053 }
4054 4054 } else {
4055 4055 count = 0;
4056 4056 }
4057 4057 }
4058 4058 ndi_devi_exit(dip, circ);
4059 4059 return (count);
4060 4060 }
4061 4061
4062 4062 #if defined(PCMCIA_DEBUG)
4063 4063 static char *ddmtypes[] = { "minor", "alias", "default", "internal" };
4064 4064
4065 4065 static void
4066 4066 pcmcia_dump_minors(dev_info_t *dip)
4067 4067 {
4068 4068 int circ;
4069 4069 int count = 0;
4070 4070 struct ddi_minor_data *dp;
4071 4071 int unit, major;
4072 4072 dev_info_t *np;
4073 4073
4074 4074 unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4075 4075 PCM_DEV_SOCKET, -1);
4076 4076 cmn_err(CE_CONT,
4077 4077 "pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit);
4078 4078
4079 4079 major = ddi_driver_major(dip);
4080 4080 if (major != -1) {
4081 4081 for (np = devnamesp[major].dn_head; np != NULL;
4082 4082 np = (dev_info_t *)DEVI(np)->devi_next) {
4083 4083 char *cf2 = "";
4084 4084 char *cur = "";
4085 4085 if (i_ddi_node_state(np) == DS_READY)
4086 4086 cf2 = "DS_READY";
4087 4087 if (np == dip)
4088 4088 cur = "CUR";
4089 4089 cmn_err(CE_CONT, "\tsibs: %s %s %s\n",
4090 4090 ddi_binding_name(np), cf2, cur);
4091 4091
4092 4092 ndi_devi_enter(np, &circ);
4093 4093 if (DEVI(np)->devi_minor !=
4094 4094 (struct ddi_minor_data *)NULL) {
4095 4095 for (dp = DEVI(np)->devi_minor;
4096 4096 dp != (struct ddi_minor_data *)NULL;
4097 4097 dp = dp->next) {
4098 4098 count++; /* have one more */
4099 4099 }
4100 4100 for (dp = DEVI(dip)->devi_minor;
4101 4101 dp != (struct ddi_minor_data *)NULL;
4102 4102 dp = dp->next) {
4103 4103 cmn_err(CE_CONT, "\ttype=%s, name=%s,"
4104 4104 "socket=%d, stype=%x, "
4105 4105 "ntype=%s, dev_t=%x",
4106 4106 ddmtypes[dp->type],
4107 4107 dp->ddm_name,
4108 4108 unit,
4109 4109 dp->ddm_spec_type,
4110 4110 dp->ddm_node_type,
4111 4111 (int)dp->ddm_dev);
4112 4112 cmn_err(CE_CONT, "\tbind name = %s\n",
4113 4113 ddi_binding_name(np));
4114 4114 }
4115 4115 }
4116 4116 ndi_devi_exit(np, circ);
4117 4117 }
4118 4118 }
4119 4119 }
4120 4120 #endif
4121 4121
4122 4122 /*
4123 4123 * experimental merging code
4124 4124 * what are the things that we should merge on?
4125 4125 * match something by name in the "compatible" property
4126 4126 * restrict to a specific "socket"
4127 4127 * restrict to a specific "instance"
4128 4128 */
4129 4129 /*ARGSUSED*/
4130 4130 static int
4131 4131 pcmcia_merge_conf(dev_info_t *dip)
4132 4132 {
4133 4133 return (0); /* merge failed */
4134 4134 }
4135 4135
4136 4136 /*
4137 4137 * pcmcia_mfc_intr()
4138 4138 * Multifunction Card interrupt handler
4139 4139 * While some adapters share interrupts at the lowest
4140 4140 * level, some can't. In order to be consistent, we
4141 4141 * split multifunction cards out with this intercept and
4142 4142 * allow the low level to do what is best for it.
4143 4143 * the arg is a pcmcia_socket structure and all interrupts
4144 4144 * are per-socket in this case. We also have the option
4145 4145 * to optimize if the cards support it. It also means
4146 4146 * that we can use the INTRACK mode if it proves desirable
4147 4147 */
4148 4148 /*ARGSUSED*/
4149 4149 static uint32_t
4150 4150 pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2)
4151 4151 {
4152 4152 pcmcia_logical_socket_t *sockp;
4153 4153 inthandler_t *intr, *first;
4154 4154 int done, result;
4155 4155
4156 4156 sockp = (pcmcia_logical_socket_t *)arg1;
4157 4157
4158 4158 #if defined(PCMCIA_DEBUG)
4159 4159 if (pcmcia_debug > 1) {
4160 4160 cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p"
4161 4161 " ls_inthandlers=%p\n"
4162 4162 "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n",
4163 4163 (void *) sockp, (void *) sockp->ls_inthandlers,
4164 4164 sockp->ls_flags, PCS_IRQ_ENABLED);
4165 4165 }
4166 4166 #endif
4167 4167
4168 4168 if (sockp == NULL || sockp->ls_inthandlers == NULL ||
4169 4169 !(sockp->ls_flags & PCS_IRQ_ENABLED))
4170 4170 return (DDI_INTR_UNCLAIMED);
4171 4171
4172 4172 mutex_enter(&sockp->ls_ilock);
4173 4173 for (done = 0, result = 0, first = intr = sockp->ls_inthandlers;
4174 4174 intr != NULL && !done; intr = intr->next) {
4175 4175 result |= intr->intr(intr->arg1, intr->arg2);
4176 4176 if (intr->next == first)
4177 4177 done++;
4178 4178 }
4179 4179 if (intr == NULL) {
4180 4180 cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list");
4181 4181 }
4182 4182 if (sockp->ls_inthandlers)
4183 4183 sockp->ls_inthandlers = sockp->ls_inthandlers->next;
4184 4184
4185 4185 mutex_exit(&sockp->ls_ilock);
4186 4186 return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
4187 4187 }
4188 4188
4189 4189 /*
4190 4190 * pcmcia_power(dip)
4191 4191 * control power for nexus and children
4192 4192 */
4193 4193 int
4194 4194 pcmcia_power(dev_info_t *dip, int component, int level)
4195 4195 {
4196 4196 #if 0
4197 4197 anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
4198 4198 int i;
4199 4199 /*
4200 4200 * for now, we only have one component. Should there be one per-socket?
4201 4201 * the level is only one (power on or off)
4202 4202 */
4203 4203 if (component != 0 || level > 1)
4204 4204 return (DDI_FAILURE);
4205 4205
4206 4206 for (i = 0; i < pcic->pc_numsockets; i++) {
4207 4207 if (pcic->pc_callback)
4208 4208 PC_CALLBACK(dip, pcic->pc_cb_arg,
4209 4209 (level == 0) ? PCE_PM_SUSPEND :
4210 4210 PCE_PM_RESUME,
4211 4211 i);
4212 4212 }
4213 4213 #else
4214 4214 cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s",
4215 4215 component, level, ddi_get_name_addr(dip));
4216 4216 return (DDI_FAILURE);
4217 4217 #endif
4218 4218 }
4219 4219
4220 4220 void
4221 4221 pcmcia_begin_resume(dev_info_t *dip)
4222 4222 {
4223 4223 int i;
4224 4224 struct pcmcia_adapter *adapt = NULL;
4225 4225 for (i = 0; i < pcmcia_num_adapters; i++) {
4226 4226 if (pcmcia_adapters[i]->pca_dip == dip) {
4227 4227 adapt = pcmcia_adapters[i];
4228 4228 break;
4229 4229 }
4230 4230 }
4231 4231 if (adapt == NULL)
4232 4232 return;
4233 4233
4234 4234 for (i = 0; i < adapt->pca_numsockets; i++) {
4235 4235 int s;
4236 4236 s = adapt->pca_first_socket + i;
4237 4237 if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) {
4238 4238 if (pcmcia_sockets[s]->ls_flags &
4239 4239 (1 << PCE_PM_RESUME)) {
4240 4240 (void) cs_event(PCE_PM_RESUME, s, 0);
4241 4241 pcm_event_manager(PCE_PM_RESUME, s, NULL);
4242 4242 }
4243 4243 (void) cs_event(PCE_CARD_REMOVAL, s, 0);
4244 4244 pcm_event_manager(PCE_CARD_REMOVAL, s, NULL);
4245 4245 }
4246 4246 }
4247 4247 }
4248 4248
4249 4249 /*
4250 4250 * mark a cardbus card as "suspended" in the pcmcia module
4251 4251 */
4252 4252 void
4253 4253 pcmcia_cb_suspended(int socket)
4254 4254 {
4255 4255 mutex_enter(&pcmcia_global_lock);
4256 4256 pcmcia_sockets[socket]->ls_flags |= PCS_SUSPENDED;
4257 4257 mutex_exit(&pcmcia_global_lock);
4258 4258
4259 4259 }
4260 4260
4261 4261 /*
4262 4262 * mark a cardbus card as "resumed" in the pcmcia module
4263 4263 */
4264 4264 void
4265 4265 pcmcia_cb_resumed(int socket)
4266 4266 {
4267 4267 if (pcmcia_sockets[socket]->ls_flags & PCS_SUSPENDED) {
4268 4268 mutex_enter(&pcmcia_global_lock);
4269 4269 pcmcia_sockets[socket]->ls_flags &= ~PCS_SUSPENDED;
4270 4270 cv_broadcast(&pcmcia_condvar);
4271 4271 mutex_exit(&pcmcia_global_lock);
4272 4272 #ifdef PCMCIA_DEBUG
4273 4273 if (pcmcia_debug) {
4274 4274 cmn_err(CE_NOTE, "pcmcia_cb_resume RESUMED");
4275 4275 }
4276 4276 #endif
4277 4277 }
4278 4278
4279 4279 }
4280 4280
4281 4281 void
4282 4282 pcmcia_wait_insert(dev_info_t *dip)
4283 4283 {
4284 4284 int i, f, tries, done;
4285 4285 struct pcmcia_adapter *adapt = NULL;
4286 4286 anp_t *nexus;
4287 4287
4288 4288 for (i = 0; i < pcmcia_num_adapters; i++) {
4289 4289 if (pcmcia_adapters[i]->pca_dip == dip) {
4290 4290 adapt = pcmcia_adapters[i];
4291 4291 break;
4292 4292 }
4293 4293 }
4294 4294 if (adapt == NULL)
4295 4295 return;
4296 4296
4297 4297 for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) {
4298 4298 done = 1;
4299 4299 mutex_enter(&pcmcia_global_lock);
4300 4300 for (i = 0; i < adapt->pca_numsockets; i++) {
4301 4301 int s;
4302 4302 s = adapt->pca_first_socket + i;
4303 4303 for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++)
4304 4304 if (pcmcia_sockets[s] &&
4305 4305 pcmcia_sockets[s]->ls_flags &
4306 4306 PCS_SUSPENDED) {
4307 4307
4308 4308 #ifdef PCMCIA_DEBUG
4309 4309 if (pcmcia_debug) {
4310 4310 cmn_err(CE_NOTE,
4311 4311 "pcmcia_wait_insert: "
4312 4312 "socket in SUSPENDED "
4313 4313 "state");
4314 4314 }
4315 4315 #endif
4316 4316 done = 0;
4317 4317 break;
4318 4318 }
4319 4319 }
4320 4320 if (!done) {
4321 4321 (void) cv_reltimedwait(&pcmcia_condvar,
4322 4322 &pcmcia_global_lock, drv_usectohz(100000),
4323 4323 TR_CLOCK_TICK);
4324 4324 } else {
4325 4325 tries = 0;
4326 4326 }
4327 4327 mutex_exit(&pcmcia_global_lock);
4328 4328 }
4329 4329
4330 4330 if (tries == 0) {
4331 4331 cmn_err(CE_NOTE, "pcmcia_wait_insert timed out");
4332 4332 }
4333 4333
4334 4334 nexus = (anp_t *)ddi_get_driver_private(dip);
4335 4335 pcmcia_find_cards(nexus);
4336 4336 }
4337 4337
4338 4338 int
4339 4339 pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra,
4340 4340 uint32_t state, caddr_t *base,
4341 4341 ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib,
4342 4342 uint32_t req_base)
4343 4343 {
4344 4344 struct pcmcia_parent_private *ppd;
4345 4345 int rnum = 0, type = PCMCIA_MAP_MEM;
4346 4346 ddi_map_req_t mr;
4347 4347 ddi_acc_hdl_t *hp;
4348 4348 int result;
4349 4349 struct regspec *reg;
4350 4350 ddi_device_acc_attr_t attr;
4351 4351
4352 4352 if (dip != NULL) {
4353 4353 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
4354 4354 if (ppd == NULL)
4355 4355 return (DDI_FAILURE);
4356 4356 for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) {
4357 4357 struct pcm_regs *p;
4358 4358 p = &ppd->ppd_reg[rnum];
4359 4359 if (state & WS_IO) {
4360 4360 /* need I/O */
4361 4361 type = PCMCIA_MAP_IO;
4362 4362 /*
4363 4363 * We want to find an IO regspec. When we
4364 4364 * find one, it either has to match
4365 4365 * the caller's requested base address
4366 4366 * or it has to be relocatable.
4367 4367 * We match on the requested base address
4368 4368 * rather than the allocated base
4369 4369 * address so that we handle the case
4370 4370 * of adapters that have IO window base
4371 4371 * relocation registers.
4372 4372 */
4373 4373 if ((p->phys_hi &
4374 4374 PC_REG_SPACE(PC_REG_SPACE_IO)) &&
4375 4375 ((req_base == p->phys_lo) ||
4376 4376 !(p->phys_hi & PC_REG_RELOC(1))))
4377 4377 break;
4378 4378 } else {
4379 4379 /* need memory */
4380 4380 type = PCMCIA_MAP_MEM;
4381 4381 if (p->phys_hi &
4382 4382 PC_REG_SPACE(PC_REG_SPACE_MEMORY|
4383 4383 PC_REG_SPACE_ATTRIBUTE))
4384 4384 break;
4385 4385 }
4386 4386 }
4387 4387 if (rnum >= ppd->ppd_nreg)
4388 4388 return (DDI_FAILURE);
4389 4389 } else if (state & WS_IO) {
4390 4390 return (DDI_FAILURE);
4391 4391 }
4392 4392
4393 4393 reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP);
4394 4394 reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra);
4395 4395
4396 4396 if (attrib == NULL ||
4397 4397 attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) {
4398 4398 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4399 4399 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4400 4400 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4401 4401 } else {
4402 4402 attr = *attrib;
4403 4403 }
4404 4404 /*
4405 4405 * Allocate and initialize the common elements of data access handle.
4406 4406 */
4407 4407 *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
4408 4408 hp = impl_acc_hdl_get(*handle);
4409 4409 hp->ah_vers = VERS_ACCHDL;
4410 4410 hp->ah_dip = dip != NULL ? dip : pdip;
4411 4411 hp->ah_rnumber = rnum;
4412 4412 hp->ah_offset = 0;
4413 4413 hp->ah_len = ra->ra_len;
4414 4414 hp->ah_acc = attr;
4415 4415
4416 4416 /*
4417 4417 * Set up the mapping request and call to parent.
4418 4418 */
4419 4419 mr.map_op = DDI_MO_MAP_LOCKED;
4420 4420 mr.map_type = DDI_MT_REGSPEC;
4421 4421 mr.map_obj.rp = reg;
4422 4422 mr.map_prot = PROT_READ | PROT_WRITE;
4423 4423 mr.map_flags = DDI_MF_KERNEL_MAPPING;
4424 4424 mr.map_handlep = hp;
4425 4425 mr.map_vers = DDI_MAP_VERSION;
4426 4426
4427 4427 result = ddi_map(pdip, &mr, 0, ra->ra_len, base);
4428 4428 if (result != DDI_SUCCESS) {
4429 4429 impl_acc_hdl_free(*handle);
4430 4430 *handle = (ddi_acc_handle_t)NULL;
4431 4431 } else {
4432 4432 hp->ah_addr = *base;
4433 4433 if (mr.map_op == DDI_MO_UNMAP)
4434 4434 ra = NULL;
4435 4435 if (dip != NULL)
4436 4436 pcmcia_set_assigned(dip, rnum, ra);
4437 4437 }
4438 4438
4439 4439 kmem_free(reg, sizeof (pci_regspec_t));
4440 4440
4441 4441 return (result);
4442 4442 }
4443 4443
4444 4444 struct pcmcia_adapter *
4445 4445 pcmcia_get_adapter(dev_info_t *dip)
4446 4446 {
4447 4447 int i;
4448 4448
4449 4449 for (i = 0; i < pcmcia_num_adapters; i++) {
4450 4450 if (pcmcia_adapters[i] &&
4451 4451 pcmcia_adapters[i]->pca_dip == dip) {
4452 4452 return (pcmcia_adapters[i]);
4453 4453 }
4454 4454 }
4455 4455 return (NULL);
4456 4456 }
4457 4457
4458 4458
4459 4459 void
4460 4460 pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret)
4461 4461 {
4462 4462 struct pcmcia_parent_private *ppd;
4463 4463 struct pcm_regs *reg, *assign;
4464 4464
4465 4465 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip);
4466 4466 if (ppd) {
4467 4467 reg = &ppd->ppd_reg[rnum];
4468 4468 assign = &ppd->ppd_assigned[rnum];
4469 4469 if (ret) {
4470 4470 if (assign->phys_hi == 0) {
4471 4471 assign->phys_hi = reg->phys_hi;
4472 4472 assign->phys_lo = ret->ra_addr_lo;
4473 4473 assign->phys_len = ret->ra_len;
4474 4474 } else if (assign->phys_lo != ret->ra_addr_lo) {
4475 4475 #ifdef PCMCIA_DEBUG
4476 4476 cmn_err(CE_WARN, "pcmcia: bad address:"
4477 4477 "%s=<%x,%x>",
4478 4478 ddi_get_name_addr(dip),
4479 4479 ret->ra_addr_lo, assign->phys_lo);
4480 4480 #else
4481 4481 cmn_err(CE_WARN, "!pcmcia: bad address:"
4482 4482 "%s=<%x,%x>",
4483 4483 ddi_get_name_addr(dip),
4484 4484 ret->ra_addr_lo, (int)assign->phys_lo);
4485 4485 #endif
4486 4486 }
4487 4487 assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi);
4488 4488 } else {
4489 4489 int i;
4490 4490 assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi);
4491 4491 i = PC_GET_REG_REFCNT(assign->phys_hi);
4492 4492 if (i == 0) {
4493 4493 assign->phys_hi = 0;
4494 4494 assign->phys_lo = 0;
4495 4495 assign->phys_len = 0;
4496 4496 }
4497 4497 }
4498 4498 }
4499 4499 }
4500 4500
4501 4501 int
4502 4502 pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
4503 4503 dev_info_t **res_dip)
4504 4504 {
4505 4505 return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip));
4506 4506 }
4507 4507
4508 4508 int
4509 4509 pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
4510 4510 dev_info_t **res_dip)
4511 4511 {
4512 4512 return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip));
4513 4513 }
4514 4514
4515 4515 static boolean_t
4516 4516 is_subtractv(dev_info_t *dip)
4517 4517 {
4518 4518 uint_t class;
4519 4519
4520 4520 if (dip == NULL)
4521 4521 return (B_FALSE);
4522 4522 class = ddi_getprop(DDI_DEV_T_ANY, dip,
4523 4523 DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
4524 4524 "class-code", 0xff);
4525 4525 if (class == PPB_SUBTRACTIVE) {
4526 4526 return (B_TRUE);
4527 4527 }
4528 4528 return (B_FALSE);
4529 4529 }
4530 4530
4531 4531 /*
4532 4532 * pcmcia_pci_alloc()
4533 4533 * allocate mem or I/O resource from the ancestor of the cardbus bridge.
4534 4534 * First start from the parent node. If the parent is a subtractive
4535 4535 * decode bridge and it does not have the requested resource, go up the
4536 4536 * device tree to find the resource.
4537 4537 *
4538 4538 * dip the parent node of the cardbus bridge
4539 4539 *
4540 4540 * res_dip returns a pointer to the node from which the
4541 4541 * resource is obtained. *res_dip could point to
4542 4542 * the parent or a higher level ancestor. *res_dip
4543 4543 * should be saved by the caller and later passed
4544 4544 * to pcmcia_ra_free();
4545 4545 */
4546 4546 int
4547 4547 pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
4548 4548 char *type, dev_info_t **res_dip)
4549 4549 {
4550 4550 uint64_t base = 0;
4551 4551 uint64_t len = 0;
4552 4552
4553 4553 if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
4554 4554 == NDI_FAILURE) ||
4555 4555 ((base >> 32) != 0)) {
4556 4556 if (is_subtractv(dip)) {
4557 4557 return (pcmcia_pci_alloc(ddi_get_parent(dip),
4558 4558 req, ret, type, res_dip));
4559 4559
4560 4560 } else {
4561 4561 ret->ra_addr_hi = 0;
4562 4562 ret->ra_addr_lo = 0;
4563 4563 ret->ra_len = 0;
4564 4564 return (DDI_FAILURE);
4565 4565 }
4566 4566 }
4567 4567 ret->ra_addr_lo = base & 0xffffffff;
4568 4568 ret->ra_addr_hi = 0;
4569 4569 ret->ra_len = len;
4570 4570 *res_dip = dip;
4571 4571 return (DDI_SUCCESS);
4572 4572 }
4573 4573
4574 4574 int
4575 4575 pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
4576 4576 char *type, dev_info_t **res_dip)
4577 4577 {
4578 4578 uint64_t base = 0;
4579 4579 uint64_t len = 0;
4580 4580
4581 4581 /*
4582 4582 * Allocate space from busra resource list
4583 4583 * should not return an address > 32 bits
4584 4584 */
4585 4585
4586 4586 if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
4587 4587 == NDI_FAILURE) ||
4588 4588 ((base >> 32) != 0)) {
4589 4589 return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret,
4590 4590 type, res_dip));
4591 4591 } else {
4592 4592 ret->ra_addr_lo = base & 0xffffffff;
4593 4593 ret->ra_addr_hi = 0;
4594 4594 ret->ra_len = len;
4595 4595 *res_dip = dip;
4596 4596 return (DDI_SUCCESS);
4597 4597 }
4598 4598 }
4599 4599
4600 4600 int
4601 4601 pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret)
4602 4602 {
4603 4603 return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM));
4604 4604 }
4605 4605
4606 4606 int
4607 4607 pcmcia_free_io(dev_info_t *dip, ra_return_t *ret)
4608 4608 {
4609 4609 return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO));
4610 4610 }
4611 4611
4612 4612 int
4613 4613 pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type)
4614 4614 {
4615 4615 if (dip == (dev_info_t *)-1)
4616 4616 return (DDI_FAILURE);
4617 4617 if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len,
4618 4618 type, NDI_RA_PASS) == NDI_SUCCESS) {
4619 4619 return (DDI_SUCCESS);
4620 4620 } else {
4621 4621 return (DDI_FAILURE);
4622 4622 }
4623 4623 }
4624 4624
4625 4625
4626 4626 /*
4627 4627 * when the low level device configuration does resource assignment
4628 4628 * (devconf) then free the allocated resources so we can reassign them
4629 4629 * later. Walk the child list to get them.
4630 4630 */
4631 4631 void
4632 4632 pcmcia_free_resources(dev_info_t *self)
4633 4633 {
4634 4634 struct regspec *assigned;
4635 4635 int len;
4636 4636 dev_info_t *dip;
4637 4637 int circ;
4638 4638
4639 4639 ndi_devi_enter(self, &circ);
4640 4640 /* do searches in compatible property order */
4641 4641 for (dip = (dev_info_t *)DEVI(self)->devi_child;
4642 4642 dip != NULL;
4643 4643 dip = (dev_info_t *)DEVI(dip)->devi_sibling) {
4644 4644 len = 0;
4645 4645 if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
4646 4646 DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP,
4647 4647 "assigned-addresses",
4648 4648 (caddr_t)&assigned,
4649 4649 &len) == DDI_PROP_SUCCESS) {
4650 4650 /*
4651 4651 * if there are assigned resources at this point,
4652 4652 * then the OBP or devconf have assigned them and
4653 4653 * they need to be freed.
4654 4654 */
4655 4655 kmem_free(assigned, len);
4656 4656 }
4657 4657 }
4658 4658 ndi_devi_exit(self, circ);
4659 4659 }
4660 4660
4661 4661 /*
4662 4662 * this is the equivalent of pcm_get_intr using ra_allocs.
4663 4663 * returns -1 if failed, otherwise returns the allocated irq.
4664 4664 * The input request, if less than zero it means not a specific
4665 4665 * irq requested. If larger then 0 then we are requesting that specific
4666 4666 * irq
4667 4667 */
4668 4668 int
4669 4669 pcmcia_get_intr(dev_info_t *dip, int request)
4670 4670 {
4671 4671 ndi_ra_request_t req;
4672 4672 uint64_t base;
4673 4673 uint64_t len;
4674 4674 int err;
4675 4675
4676 4676 bzero(&req, sizeof (req));
4677 4677 base = 0;
4678 4678 len = 1;
4679 4679 if (request >= 0) {
4680 4680 req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
4681 4681 req.ra_len = 1;
4682 4682 req.ra_addr = (uint64_t)request;
4683 4683 }
4684 4684
4685 4685 req.ra_boundbase = 0;
4686 4686 req.ra_boundlen = 0xffffffffUL;
4687 4687 req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
4688 4688
4689 4689 err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR,
4690 4690 NDI_RA_PASS);
4691 4691
4692 4692 if (err == NDI_FAILURE) {
4693 4693 return (-1);
4694 4694 } else {
4695 4695 return ((int)base);
4696 4696 }
4697 4697 }
4698 4698
4699 4699
4700 4700 int
4701 4701 pcmcia_return_intr(dev_info_t *dip, int request)
4702 4702 {
4703 4703 if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR,
4704 4704 NDI_RA_PASS)) == NDI_SUCCESS) {
4705 4705 return (0);
4706 4706 } else
4707 4707 return (-1);
4708 4708
4709 4709 }
4710 4710
4711 4711 #ifdef sparc
4712 4712
4713 4713 int
4714 4714 pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
4715 4715 ddi_intr_handle_impl_t *hdlp)
4716 4716 {
4717 4717
4718 4718 struct pcmcia_parent_private *ppd;
4719 4719 pcmcia_logical_socket_t *sockp;
4720 4720 int socket, ret;
4721 4721 struct pcmcia_adapter *adapt;
4722 4722 set_irq_handler_t handler;
4723 4723 struct intrspec *pispec;
4724 4724
4725 4725 #if defined(PCMCIA_DEBUG)
4726 4726 if (pcmcia_debug) {
4727 4727 cmn_err(CE_CONT,
4728 4728 "pcmcia_add_intr_impl() entered "
4729 4729 "dip=%p rdip=%p hdlp=%p \n",
4730 4730 (void *)dip, (void *)rdip, (void *)hdlp);
4731 4731 }
4732 4732 #endif
4733 4733
4734 4734 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
4735 4735 socket = ppd->ppd_socket;
4736 4736 sockp = pcmcia_sockets[socket];
4737 4737 adapt = sockp->ls_adapter;
4738 4738
4739 4739 #if defined(PCMCIA_DEBUG)
4740 4740 if (pcmcia_debug) {
4741 4741 cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
4742 4742 " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n"
4743 4743 " ppd_intrspec=%p ls_inthandlers=%p\n",
4744 4744 ppd->ppd_flags, PPD_CARD_MULTI,
4745 4745 (void *) ppd->ppd_intrspec,
4746 4746 (void *)sockp->ls_inthandlers);
4747 4747 }
4748 4748 #endif
4749 4749
4750 4750 /*
4751 4751 * calculate IPL level when we support multiple levels
4752 4752 */
4753 4753 pispec = ppd->ppd_intrspec;
4754 4754 if (pispec == NULL) {
4755 4755 sockp->ls_error = BAD_IRQ;
4756 4756 return (DDI_FAILURE);
4757 4757 }
4758 4758
4759 4759 handler.socket = sockp->ls_socket;
4760 4760 handler.irq = 0; /* default case */
4761 4761 handler.handler = (f_tt *)hdlp->ih_cb_func;
4762 4762 handler.arg1 = hdlp->ih_cb_arg1;
4763 4763 handler.arg2 = hdlp->ih_cb_arg2;
4764 4764 handler.handler_id = (uint32_t)(uintptr_t)rdip;
4765 4765
4766 4766 /*
4767 4767 * check if multifunction and do the right thing
4768 4768 * we put an intercept in between the mfc handler and
4769 4769 * us so we can catch and process. We might be able
4770 4770 * to optimize this depending on the card features
4771 4771 * (a future option).
4772 4772 */
4773 4773 if (ppd->ppd_flags & PPD_CARD_MULTI) {
4774 4774 inthandler_t *intr;
4775 4775 /*
4776 4776 * note that the first function is a special
4777 4777 * case since it sets things up. We fall through
4778 4778 * to the lower code and get the hardware set up.
4779 4779 * subsequent times we just lock the list and insert
4780 4780 * the handler and all is well.
4781 4781 */
4782 4782 intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
4783 4783 if (intr == NULL) {
4784 4784 sockp->ls_error = BAD_IRQ;
4785 4785 return (DDI_FAILURE);
4786 4786 }
4787 4787 intr->intr = hdlp->ih_cb_func;
4788 4788 intr->handler_id = (uint_t)(uintptr_t)rdip;
4789 4789 intr->arg1 = hdlp->ih_cb_arg1;
4790 4790 intr->arg2 = hdlp->ih_cb_arg2;
4791 4791 intr->socket = socket;
4792 4792
4793 4793 mutex_enter(&sockp->ls_ilock);
4794 4794 if (sockp->ls_inthandlers == NULL) {
4795 4795 intr->next = intr->prev = intr;
4796 4796 sockp->ls_inthandlers = intr;
4797 4797 sockp->ls_mfintr_dip = rdip;
4798 4798 mutex_exit(&sockp->ls_ilock);
4799 4799
4800 4800 /*
4801 4801 * replace first function handler with
4802 4802 * the mfc handler
4803 4803 */
4804 4804 handler.handler = (f_tt *)pcmcia_mfc_intr;
4805 4805 handler.arg1 = (caddr_t)sockp;
4806 4806 handler.arg2 = NULL;
4807 4807 } else {
4808 4808 insque(intr, sockp->ls_inthandlers);
4809 4809 mutex_exit(&sockp->ls_ilock);
4810 4810
4811 4811 pispec->intrspec_vec = sockp->ls_intr_vec;
4812 4812 pispec->intrspec_pri = sockp->ls_intr_pri;
4813 4813 hdlp->ih_pri = sockp->ls_intr_pri;
4814 4814
4815 4815 return (DDI_SUCCESS);
4816 4816 }
4817 4817 }
4818 4818
4819 4819 #if defined(PCMCIA_DEBUG)
4820 4820 if (pcmcia_debug) {
4821 4821 cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n");
4822 4822 }
4823 4823 #endif
4824 4824 pispec->intrspec_func = (uint32_t (*)())handler.handler;
4825 4825
4826 4826 /* set default IPL then check for override */
4827 4827
4828 4828 pispec->intrspec_pri = sockp->ls_intr_pri;
4829 4829 hdlp->ih_pri = pispec->intrspec_pri;
4830 4830
4831 4831 #if defined(PCMCIA_DEBUG)
4832 4832 if (pcmcia_debug) {
4833 4833 cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d"
4834 4834 " handler_id=0X%x handler=%p arg1=%p arg2=%p\n",
4835 4835 handler.socket, handler.irq,
4836 4836 handler.handler_id, (void *)handler.handler, handler.arg1,
4837 4837 handler.arg2);
4838 4838 }
4839 4839 #endif
4840 4840
4841 4841 if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
4842 4842 SUCCESS) {
4843 4843 sockp->ls_error = ret;
4844 4844 return (DDI_FAILURE);
4845 4845 }
4846 4846
4847 4847 #if defined(PCMCIA_DEBUG)
4848 4848 if (pcmcia_debug) {
4849 4849 cmn_err(CE_CONT, "pcmcia_add_intr_impl()"
4850 4850 " iblk_cookie=%p idev_cookie=%p\n"
4851 4851 " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n",
4852 4852 (void *)handler.iblk_cookie,
4853 4853 (void *)handler.idev_cookie,
4854 4854 sockp->ls_flags, PCS_COOKIES_VALID);
4855 4855 }
4856 4856 #endif
4857 4857
4858 4858 if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
4859 4859 hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie;
4860 4860 sockp->ls_iblk = *handler.iblk_cookie;
4861 4861 sockp->ls_idev = *handler.idev_cookie;
4862 4862 sockp->ls_flags |= PCS_COOKIES_VALID;
4863 4863 }
4864 4864
4865 4865 return (DDI_SUCCESS);
4866 4866 }
4867 4867
4868 4868 void
4869 4869 pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
4870 4870 ddi_intr_handle_impl_t *hdlp)
4871 4871 {
4872 4872
4873 4873 struct pcmcia_parent_private *ppd;
4874 4874 pcmcia_logical_socket_t *sockp;
4875 4875 clear_irq_handler_t handler;
4876 4876 struct intrspec *pispec;
4877 4877 int socket;
4878 4878
4879 4879 #if defined(PCMCIA_DEBUG)
4880 4880 if (pcmcia_debug) {
4881 4881 cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered"
4882 4882 " dip=%p rdip=%p hdlp=%p\n",
4883 4883 (void *)dip, (void *)rdip, (void *)hdlp);
4884 4884 }
4885 4885 #endif
4886 4886
4887 4887 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
4888 4888 socket = ppd->ppd_socket;
4889 4889 sockp = pcmcia_sockets[socket];
4890 4890 pispec = ppd->ppd_intrspec;
4891 4891
4892 4892 #if defined(PCMCIA_DEBUG)
4893 4893 if (pcmcia_debug) {
4894 4894 cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
4895 4895 " ls_inthandlers=%p ls_intrspec=%p\n",
4896 4896 (void *)sockp->ls_inthandlers,
4897 4897 (void *)&sockp->ls_intrspec);
4898 4898 }
4899 4899 #endif
4900 4900
4901 4901 /* first handle the multifunction case since it is simple */
4902 4902 mutex_enter(&sockp->ls_ilock);
4903 4903 if (sockp->ls_inthandlers != NULL) {
4904 4904 /* we must be MFC */
4905 4905 inthandler_t *intr;
4906 4906 int remhandler = 0;
4907 4907 intr = sockp->ls_inthandlers;
4908 4908
4909 4909 /* Check if there is only one handler left */
4910 4910 if ((intr->next == intr) && (intr->prev == intr)) {
4911 4911 if (intr->handler_id == (unsigned)(uintptr_t)rdip) {
4912 4912 sockp->ls_inthandlers = NULL;
4913 4913 remhandler++;
4914 4914 kmem_free(intr, sizeof (inthandler_t));
4915 4915 }
4916 4916 } else {
4917 4917 inthandler_t *first;
4918 4918 int done;
4919 4919
4920 4920 for (done = 0, first = intr; !done; intr = intr->next) {
4921 4921 if (intr->next == first)
4922 4922 done++;
4923 4923 if (intr->handler_id ==
4924 4924 (unsigned)(uintptr_t)rdip) {
4925 4925 done++;
4926 4926
4927 4927 /*
4928 4928 * If we're about to remove the
4929 4929 * handler at the head of
4930 4930 * the list, make the next
4931 4931 * handler in line the head.
4932 4932 */
4933 4933 if (sockp->ls_inthandlers == intr)
4934 4934 sockp->ls_inthandlers =
4935 4935 intr->next;
4936 4936
4937 4937 remque(intr);
4938 4938 kmem_free(intr, sizeof (inthandler_t));
4939 4939 break;
4940 4940 } /* handler_id */
4941 4941 } /* for */
4942 4942 } /* intr->next */
4943 4943
4944 4944 if (!remhandler) {
4945 4945 mutex_exit(&sockp->ls_ilock);
4946 4946 return;
4947 4947 }
4948 4948
4949 4949 /* need to get the dip that was used to add the handler */
4950 4950 rdip = sockp->ls_mfintr_dip;
4951 4951 }
4952 4952
4953 4953 mutex_exit(&sockp->ls_ilock);
4954 4954
4955 4955 #if defined(PCMCIA_DEBUG)
4956 4956 if (pcmcia_debug) {
4957 4957 cmn_err(CE_CONT, "pcmcia_remove_intr_impl()"
4958 4958 " pispec=%p rdip=%p\n",
4959 4959 (void *)pispec, (void *)rdip);
4960 4960 }
4961 4961 #endif
4962 4962
4963 4963 handler.socket = sockp->ls_socket;
4964 4964 handler.handler_id = (uint32_t)(uintptr_t)rdip;
4965 4965 handler.handler = (f_tt *)pispec->intrspec_func;
4966 4966 CLEAR_IRQ(sockp->ls_if, dip, &handler);
4967 4967 }
4968 4968
4969 4969
4970 4970 /* Consolidated interrupt processing interface */
4971 4971 /*ARGSUSED*/
4972 4972 int
4973 4973 pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
4974 4974 ddi_intr_handle_impl_t *hdlp, void *result)
4975 4975 {
4976 4976 int ret = DDI_SUCCESS;
4977 4977
4978 4978 #if defined(PCMCIA_DEBUG)
4979 4979 if (pcmcia_debug) {
4980 4980 cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n",
4981 4981 (int)intr_op);
4982 4982 }
4983 4983 #endif
4984 4984
4985 4985 switch (intr_op) {
4986 4986 case DDI_INTROP_GETCAP:
4987 4987 *(int *)result = DDI_INTR_FLAG_LEVEL;
4988 4988 break;
4989 4989 case DDI_INTROP_SETCAP:
4990 4990 ret = DDI_ENOTSUP;
4991 4991 break;
4992 4992 case DDI_INTROP_ALLOC:
4993 4993 *(int *)result = hdlp->ih_scratch1;
4994 4994 break;
4995 4995 case DDI_INTROP_FREE:
4996 4996 break;
4997 4997 case DDI_INTROP_GETPRI:
4998 4998 if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS)
4999 4999 return (DDI_FAILURE);
5000 5000 *(int *)result = hdlp->ih_pri;
5001 5001 pcmcia_remove_intr_impl(dip, rdip, hdlp);
5002 5002 break;
5003 5003 case DDI_INTROP_SETPRI:
5004 5004 break;
5005 5005 case DDI_INTROP_ADDISR:
5006 5006 ret = pcmcia_add_intr_impl(dip, rdip, hdlp);
5007 5007 break;
5008 5008 case DDI_INTROP_REMISR:
5009 5009 pcmcia_remove_intr_impl(dip, rdip, hdlp);
5010 5010 break;
5011 5011 case DDI_INTROP_ENABLE:
5012 5012 case DDI_INTROP_DISABLE:
5013 5013 break;
5014 5014 case DDI_INTROP_NINTRS:
5015 5015 case DDI_INTROP_NAVAIL:
5016 5016 *(int *)result = i_ddi_get_intx_nintrs(rdip);
5017 5017 break;
5018 5018 case DDI_INTROP_SUPPORTED_TYPES:
5019 5019 /* PCI nexus driver supports only fixed interrupts */
5020 5020 *(int *)result = i_ddi_get_intx_nintrs(rdip) ?
5021 5021 DDI_INTR_TYPE_FIXED : 0;
5022 5022 break;
5023 5023 default:
5024 5024 ret = DDI_ENOTSUP;
5025 5025 break;
5026 5026 }
5027 5027
5028 5028 return (ret);
5029 5029 }
5030 5030
5031 5031 #elif defined(__x86) || defined(__amd64)
5032 5032
5033 5033 static struct intrspec *pcmcia_intr_get_ispec(dev_info_t *, int,
5034 5034 pcmcia_logical_socket_t **);
5035 5035 static struct intrspec *pcmcia_intr_add_isr(dev_info_t *, dev_info_t *,
5036 5036 ddi_intr_handle_impl_t *);
5037 5037 static int pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *,
5038 5038 ddi_intr_handle_impl_t *);
5039 5039 static void pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *,
5040 5040 ddi_intr_handle_impl_t *);
5041 5041 static void pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *,
5042 5042 ddi_intr_handle_impl_t *);
5043 5043
5044 5044 /*
5045 5045 * pcmcia_intr_get_ispec:
5046 5046 * This is mostly copied from older 'pcmcia_get_intrspec' function
5047 5047 */
5048 5048 static struct intrspec *
5049 5049 pcmcia_intr_get_ispec(dev_info_t *rdip, int inum,
5050 5050 pcmcia_logical_socket_t **sockp)
5051 5051 {
5052 5052 int socket;
5053 5053 struct intrspec *intrspec;
5054 5054 struct pcmcia_parent_private *ppd;
5055 5055
5056 5056 if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip,
5057 5057 DDI_PROP_DONTPASS, "interrupts", -1) < 0))
5058 5058 return (NULL);
5059 5059
5060 5060 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5061 5061 if (ppd == NULL || ppd->ppd_intrspec == NULL)
5062 5062 return (NULL);
5063 5063
5064 5064 if ((socket = ppd->ppd_socket) < 0)
5065 5065 return (NULL);
5066 5066
5067 5067 if ((*sockp = pcmcia_sockets[socket]) == NULL)
5068 5068 return (NULL);
5069 5069
5070 5070 intrspec = ppd->ppd_intrspec;
5071 5071 if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0)
5072 5072 intrspec->intrspec_vec = (*sockp)->ls_intr_vec;
5073 5073
5074 5074 return (intrspec);
5075 5075 }
5076 5076
5077 5077 static struct intrspec *
5078 5078 pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip,
5079 5079 ddi_intr_handle_impl_t *hdlp)
5080 5080 {
5081 5081 int socket;
5082 5082 struct intrspec *ispecp;
5083 5083 struct pcmcia_adapter *adapt;
5084 5084 pcmcia_logical_socket_t *sockp;
5085 5085 struct pcmcia_parent_private *ppd;
5086 5086
5087 5087 #if defined(PCMCIA_DEBUG)
5088 5088 if (pcmcia_debug)
5089 5089 cmn_err(CE_CONT, "pcmcia_intr_add_isr: "
5090 5090 "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5091 5091 (void *)dip, (void *)rdip, (void *)hdlp);
5092 5092 #endif /* PCMCIA_DEBUG */
5093 5093
5094 5094 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5095 5095 socket = ppd->ppd_socket;
5096 5096 sockp = pcmcia_sockets[socket];
5097 5097 adapt = sockp->ls_adapter;
5098 5098
5099 5099 ispecp = ppd->ppd_intrspec;
5100 5100 if (ispecp == NULL) {
5101 5101 sockp->ls_error = BAD_IRQ;
5102 5102 return (ispecp);
5103 5103 }
5104 5104
5105 5105 /*
5106 5106 * check if multifunction and do the right thing
5107 5107 * we put an intercept in between the mfc handler and us so we can
5108 5108 * catch and process. We might be able to optimize this depending
5109 5109 * on the card features (a future option).
5110 5110 */
5111 5111 if (ppd->ppd_flags & PPD_CARD_MULTI &&
5112 5112 hdlp->ih_cb_func != pcmcia_mfc_intr) {
5113 5113 inthandler_t *intr;
5114 5114
5115 5115 /*
5116 5116 * note that the first function is a special case since it
5117 5117 * sets things up. We fall through to the lower code and
5118 5118 * get the hardware set up. Subsequent times we just lock
5119 5119 * the list and insert the handler and all is well.
5120 5120 */
5121 5121 intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
5122 5122 if (intr == NULL) {
5123 5123 sockp->ls_error = BAD_IRQ;
5124 5124 return (NULL);
5125 5125 }
5126 5126
5127 5127 intr->intr = (uint32_t (*)())hdlp->ih_cb_func;
5128 5128 intr->handler_id = (uint32_t)(uintptr_t)rdip;
5129 5129 intr->arg1 = hdlp->ih_cb_arg1;
5130 5130 intr->arg2 = hdlp->ih_cb_arg2;
5131 5131 intr->socket = socket;
5132 5132 mutex_enter(&sockp->ls_ilock);
5133 5133 if (sockp->ls_inthandlers == NULL) {
5134 5134 intr->next = intr->prev = intr;
5135 5135 sockp->ls_inthandlers = intr;
5136 5136 sockp->ls_mfintr_dip = rdip;
5137 5137 } else {
5138 5138 insque(intr, sockp->ls_inthandlers);
5139 5139 }
5140 5140 mutex_exit(&sockp->ls_ilock);
5141 5141 return (ispecp);
5142 5142 }
5143 5143
5144 5144 /*
5145 5145 * Do we need to allocate an IRQ at this point or not?
5146 5146 */
5147 5147 if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5148 5148 int i, irq;
5149 5149
5150 5150 /*
5151 5151 * this adapter needs IRQ allocations
5152 5152 * this is only necessary if it is the first function on the
5153 5153 * card being setup. The socket will keep the allocation info
5154 5154 */
5155 5155 /* all functions use same intrspec except mfc handler */
5156 5156 if (hdlp->ih_cb_func == pcmcia_mfc_intr) {
5157 5157 /*
5158 5158 * We treat this special in order to allow things to
5159 5159 * work properly for MFC cards. The intrspec for the
5160 5160 * mfc dispatcher is intercepted and taken from the
5161 5161 * logical socket in order to not be trying to
5162 5162 * multiplex the meaning when ENABLE is called.
5163 5163 */
5164 5164 ispecp = &sockp->ls_intrspec;
5165 5165 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
5166 5166 }
5167 5167
5168 5168 if (adapt->pca_flags & PCA_IRQ_ISA) {
5169 5169 for (irq = -1, i = 1; irq == -1 && i < 16; i++) {
5170 5170 /* find available and usable IRQ level */
5171 5171 if (adapt->pca_avail_intr & (1 << i))
5172 5172 irq = pcmcia_get_intr(dip, i);
5173 5173 }
5174 5174 }
5175 5175 if (irq < 0) {
5176 5176 sockp->ls_error = NO_RESOURCE;
5177 5177 return (NULL);
5178 5178 }
5179 5179 hdlp->ih_vector = sockp->ls_intr_vec = irq;
5180 5180
5181 5181
5182 5182 #if defined(PCMCIA_DEBUG)
5183 5183 if (pcmcia_debug)
5184 5184 cmn_err(CE_CONT, "allocated irq=%x\n", irq);
5185 5185 #endif /* PCMCIA_DEBUG */
5186 5186
5187 5187 ispecp->intrspec_vec = sockp->ls_intr_vec;
5188 5188 ispecp->intrspec_pri = sockp->ls_intr_pri;
5189 5189 return (ispecp);
5190 5190 }
5191 5191
5192 5192 if (ispecp->intrspec_func != NULL)
5193 5193 ispecp->intrspec_func = hdlp->ih_cb_func;
5194 5194
5195 5195 /* set default IPL then check for override */
5196 5196 ispecp->intrspec_pri = sockp->ls_intr_pri;
5197 5197 return (ispecp);
5198 5198 }
5199 5199
5200 5200
5201 5201 static int
5202 5202 pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip,
5203 5203 ddi_intr_handle_impl_t *hdlp)
5204 5204 {
5205 5205 int socket, ret;
5206 5206 int irq = 0; /* default case */
5207 5207 dev_info_t *parent = ddi_root_node();
5208 5208 struct intrspec *ispecp;
5209 5209 set_irq_handler_t handler;
5210 5210 struct pcmcia_adapter *adapt;
5211 5211 pcmcia_logical_socket_t *sockp;
5212 5212 struct pcmcia_parent_private *ppd;
5213 5213
5214 5214 #if defined(PCMCIA_DEBUG)
5215 5215 if (pcmcia_debug)
5216 5216 cmn_err(CE_CONT, "pcmcia_intr_enable_isr: "
5217 5217 "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5218 5218 (void *)dip, (void *)rdip, (void *)hdlp);
5219 5219 #endif /* PCMCIA_DEBUG */
5220 5220
5221 5221 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5222 5222 socket = ppd->ppd_socket;
5223 5223 sockp = pcmcia_sockets[socket];
5224 5224 adapt = sockp->ls_adapter;
5225 5225
5226 5226 ispecp = ppd->ppd_intrspec;
5227 5227 ASSERT(ispecp);
5228 5228
5229 5229 mutex_enter(&sockp->ls_ilock);
5230 5230 if ((sockp->ls_inthandlers != NULL) &&
5231 5231 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
5232 5232 &sockp->ls_intrspec) {
5233 5233 inthandler_t *intr = sockp->ls_inthandlers;
5234 5234
5235 5235 ASSERT(ppd->ppd_flags & PPD_CARD_MULTI);
5236 5236
5237 5237 /* Only one handler. So, call ddi_add_intr on it */
5238 5238 if ((intr->next == intr) && (intr->prev == intr)) {
5239 5239 hdlp->ih_cb_func = pcmcia_mfc_intr;
5240 5240 hdlp->ih_cb_arg1 = (caddr_t)sockp;
5241 5241 hdlp->ih_cb_arg2 = NULL;
5242 5242
5243 5243 ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->
5244 5244 bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE,
5245 5245 hdlp, NULL);
5246 5246
5247 5247 if (ret == DDI_FAILURE) {
5248 5248 sockp->ls_inthandlers = NULL;
5249 5249 kmem_free(intr, sizeof (inthandler_t));
5250 5250 sockp->ls_error = BAD_IRQ;
5251 5251 mutex_exit(&sockp->ls_ilock);
5252 5252 return (ret);
5253 5253 }
5254 5254 }
5255 5255 mutex_exit(&sockp->ls_ilock);
5256 5256 hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec;
5257 5257 hdlp->ih_pri = sockp->ls_intr_pri;
5258 5258 sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
5259 5259 sockp->ls_intr_pri;
5260 5260 sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector;
5261 5261 sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
5262 5262 return (DDI_SUCCESS);
5263 5263 }
5264 5264 mutex_exit(&sockp->ls_ilock);
5265 5265
5266 5266 if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5267 5267 if (hdlp->ih_cb_func == pcmcia_mfc_intr)
5268 5268 ispecp = (struct intrspec *)&sockp->ls_intrspec;
5269 5269
5270 5270 /* XXX: remove it later as this is done in _add_isr as well */
5271 5271 ispecp->intrspec_vec = sockp->ls_intr_vec;
5272 5272 ispecp->intrspec_pri = sockp->ls_intr_pri;
5273 5273
5274 5274 /* Enable interrupts */
5275 5275 ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
5276 5276 parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL);
5277 5277
5278 5278 sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t)
5279 5279 sockp->ls_intr_pri;
5280 5280 sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec;
5281 5281 sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri;
5282 5282
5283 5283 if (ret != DDI_SUCCESS)
5284 5284 sockp->ls_error = BAD_IRQ;
5285 5285 return (ret);
5286 5286 }
5287 5287
5288 5288 #if defined(PCMCIA_DEBUG)
5289 5289 if (pcmcia_debug)
5290 5290 cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n");
5291 5291 #endif /* PCMCIA_DEBUG */
5292 5292
5293 5293 handler.socket = sockp->ls_socket;
5294 5294 handler.irq = irq;
5295 5295 handler.handler = (f_tt *)hdlp->ih_cb_func;
5296 5296 handler.arg1 = hdlp->ih_cb_arg1;
5297 5297 handler.arg2 = hdlp->ih_cb_arg2;
5298 5298 handler.handler_id = (uint32_t)(uintptr_t)rdip;
5299 5299 if (ispecp->intrspec_func != NULL)
5300 5300 ispecp->intrspec_func = hdlp->ih_cb_func;
5301 5301
5302 5302 /* set default IPL then check for override */
5303 5303 ispecp->intrspec_pri = sockp->ls_intr_pri;
5304 5304
5305 5305 if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) !=
5306 5306 SUCCESS) {
5307 5307 sockp->ls_error = ret;
5308 5308 return (DDI_FAILURE);
5309 5309 }
5310 5310 ispecp->intrspec_func = hdlp->ih_cb_func;
5311 5311 if (!(sockp->ls_flags & PCS_COOKIES_VALID)) {
5312 5312 sockp->ls_iblk = *handler.iblk_cookie;
5313 5313 sockp->ls_idev = *handler.idev_cookie;
5314 5314 sockp->ls_flags |= PCS_COOKIES_VALID;
5315 5315 }
5316 5316 return (DDI_SUCCESS);
5317 5317 }
5318 5318
5319 5319 /* ARGSUSED */
5320 5320 static void
5321 5321 pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip,
5322 5322 ddi_intr_handle_impl_t *hdlp)
5323 5323 {
5324 5324 int done, remhandler = 0;
5325 5325 inthandler_t *intr, *first;
5326 5326 struct intrspec *ispecp;
5327 5327 pcmcia_logical_socket_t *sockp;
5328 5328
5329 5329 #if defined(PCMCIA_DEBUG)
5330 5330 if (pcmcia_debug)
5331 5331 cmn_err(CE_CONT, "pcmcia_intr_remove_isr: "
5332 5332 "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5333 5333 (void *)dip, (void *)rdip, (void *)hdlp);
5334 5334 #endif /* PCMCIA_DEBUG */
5335 5335
5336 5336 ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5337 5337 ASSERT(ispecp);
5338 5338
5339 5339 /* first handle the multifunction case since it is simple */
5340 5340 mutex_enter(&sockp->ls_ilock);
5341 5341 if (sockp->ls_inthandlers != NULL &&
5342 5342 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp !=
5343 5343 &sockp->ls_intrspec) {
5344 5344
5345 5345 intr = sockp->ls_inthandlers;
5346 5346
5347 5347 /* Check if there is only one handler left */
5348 5348 if ((intr->next == intr) && (intr->prev == intr)) {
5349 5349 if (intr->handler_id == (uint32_t)(uintptr_t)rdip) {
5350 5350 sockp->ls_inthandlers = NULL;
5351 5351 remhandler++;
5352 5352 kmem_free(intr, sizeof (inthandler_t));
5353 5353 }
5354 5354
5355 5355 } else {
5356 5356 for (done = 0, first = intr; !done; intr = intr->next) {
5357 5357 if (intr->next == first)
5358 5358 done++;
5359 5359 if (intr->handler_id ==
5360 5360 (uint32_t)(uintptr_t)rdip) {
5361 5361 done++;
5362 5362
5363 5363 /*
5364 5364 * If we're about to remove the handler
5365 5365 * at the head of the list, make the
5366 5366 * next handler in line the head.
5367 5367 */
5368 5368 if (sockp->ls_inthandlers == intr)
5369 5369 sockp->ls_inthandlers =
5370 5370 intr->next;
5371 5371
5372 5372 remque(intr);
5373 5373 kmem_free(intr, sizeof (inthandler_t));
5374 5374 break;
5375 5375 } /* handler_id */
5376 5376 } /* end of for */
5377 5377 } /* end of if intr->next */
5378 5378
5379 5379 if (!remhandler) {
5380 5380 mutex_exit(&sockp->ls_ilock);
5381 5381 return;
5382 5382 }
5383 5383 }
5384 5384 mutex_exit(&sockp->ls_ilock);
5385 5385
5386 5386 if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) {
5387 5387 sockp->ls_intr_vec = 0;
5388 5388 ispecp->intrspec_vec = 0;
5389 5389 }
5390 5390 }
5391 5391
5392 5392
5393 5393 static void
5394 5394 pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip,
5395 5395 ddi_intr_handle_impl_t *hdlp)
5396 5396 {
5397 5397 int socket, ret;
5398 5398 dev_info_t *parent;
5399 5399 struct intrspec *ispecp;
5400 5400 clear_irq_handler_t handler;
5401 5401 struct pcmcia_adapter *adapt;
5402 5402 pcmcia_logical_socket_t *sockp;
5403 5403 struct pcmcia_parent_private *ppd;
5404 5404 ihdl_plat_t *ihdl_plat_datap =
5405 5405 (ihdl_plat_t *)hdlp->ih_private;
5406 5406
5407 5407 #if defined(PCMCIA_DEBUG)
5408 5408 if (pcmcia_debug)
5409 5409 cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5410 5410 "dip=0x%p rdip=0x%p hdlp=0x%p\n",
5411 5411 (void *)dip, (void *)rdip, (void *)hdlp);
5412 5412 #endif /* PCMCIA_DEBUG */
5413 5413
5414 5414 ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip);
5415 5415 socket = ppd->ppd_socket;
5416 5416 sockp = pcmcia_sockets[socket];
5417 5417 adapt = sockp->ls_adapter;
5418 5418 ispecp = ppd->ppd_intrspec;
5419 5419 ASSERT(ispecp);
5420 5420
5421 5421 mutex_enter(&sockp->ls_ilock);
5422 5422 if (sockp->ls_inthandlers != NULL &&
5423 5423 ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) {
5424 5424 inthandler_t *intr = sockp->ls_inthandlers;
5425 5425
5426 5426 /* Check if there is only one handler left */
5427 5427 if ((intr->next == intr) && (intr->prev == intr)) {
5428 5428 if (intr->handler_id != (uint32_t)(uintptr_t)rdip)
5429 5429 /*
5430 5430 * need to get the dip that was
5431 5431 * used to add the handler
5432 5432 */
5433 5433 rdip = sockp->ls_mfintr_dip;
5434 5434 ispecp = (struct intrspec *)&sockp->ls_intrspec;
5435 5435 } else {
5436 5436 /* Don't call cleanup if list still has members */
5437 5437 mutex_exit(&sockp->ls_ilock);
5438 5438 return;
5439 5439 }
5440 5440 }
5441 5441 mutex_exit(&sockp->ls_ilock);
5442 5442
5443 5443 if (ihdl_plat_datap->ip_ispecp ==
5444 5444 (struct intrspec *)&sockp->ls_intrspec)
5445 5445 ispecp = ihdl_plat_datap->ip_ispecp;
5446 5446
5447 5447 if (adapt->pca_flags & PCA_RES_NEED_IRQ) {
5448 5448 ret = ispecp->intrspec_vec;
5449 5449 parent = ddi_root_node();
5450 5450 ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))(
5451 5451 parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL);
5452 5452 (void) pcmcia_return_intr(dip, hdlp->ih_vector);
5453 5453 #if defined(PCMCIA_DEBUG)
5454 5454 if (pcmcia_debug)
5455 5455 cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5456 5456 "INTROP_DISABLE returned %x\n", ret);
5457 5457 #endif /* PCMCIA_DEBUG */
5458 5458 } else {
5459 5459 handler.socket = sockp->ls_socket;
5460 5460 handler.handler_id = (uint32_t)(uintptr_t)rdip;
5461 5461 handler.handler = (f_tt *)ispecp->intrspec_func;
5462 5462 ret = CLEAR_IRQ(sockp->ls_if, dip, &handler);
5463 5463 #if defined(PCMCIA_DEBUG)
5464 5464 if (pcmcia_debug)
5465 5465 cmn_err(CE_CONT, "pcmcia_intr_disable_isr: "
5466 5466 "CLEAR_IRQ returned %x\n", ret);
5467 5467 #endif /* PCMCIA_DEBUG */
5468 5468 }
5469 5469 }
5470 5470
5471 5471 /* Consolidated interrupt processing interface */
5472 5472 int
5473 5473 pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
5474 5474 ddi_intr_handle_impl_t *hdlp, void *result)
5475 5475 {
5476 5476 struct intrspec *ispecp;
5477 5477 pcmcia_logical_socket_t *sockp;
5478 5478
5479 5479 #if defined(PCMCIA_DEBUG)
5480 5480 if (pcmcia_debug)
5481 5481 cmn_err(CE_CONT, "pcmcia_intr_ops: "
5482 5482 "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n",
5483 5483 (void *)dip, (void *)rdip, intr_op, (void *)hdlp);
5484 5484 #endif /* PCMCIA_DEBUG */
5485 5485
5486 5486 switch (intr_op) {
5487 5487 case DDI_INTROP_SUPPORTED_TYPES:
5488 5488 if (ddi_get_parent_data(rdip) == NULL) {
5489 5489 *(int *)result = 0;
5490 5490 return (DDI_FAILURE);
5491 5491 }
5492 5492 *(int *)result = DDI_INTR_TYPE_FIXED;
5493 5493 break;
5494 5494 case DDI_INTROP_GETCAP:
5495 5495 *(int *)result = DDI_INTR_FLAG_LEVEL;
5496 5496 break;
5497 5497 case DDI_INTROP_NINTRS:
5498 5498 case DDI_INTROP_NAVAIL:
5499 5499 if (i_ddi_get_intx_nintrs(rdip) == 0) {
5500 5500 *(int *)result = 0;
5501 5501 return (DDI_FAILURE);
5502 5502 }
5503 5503 *(int *)result = 1; /* for PCMCIA there is only one intr */
5504 5504 break;
5505 5505 case DDI_INTROP_ALLOC:
5506 5506 if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum,
5507 5507 &sockp)) == NULL)
5508 5508 return (DDI_FAILURE);
5509 5509 *(int *)result = hdlp->ih_scratch1;
5510 5510 break;
5511 5511 case DDI_INTROP_FREE:
5512 5512 break;
5513 5513 case DDI_INTROP_GETPRI:
5514 5514 ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5515 5515 if (ispecp == NULL) {
5516 5516 *(int *)result = 0;
5517 5517 return (DDI_FAILURE);
5518 5518 }
5519 5519
5520 5520 *(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri;
5521 5521 break;
5522 5522 case DDI_INTROP_SETPRI:
5523 5523 if (*(int *)result > LOCK_LEVEL)
5524 5524 return (DDI_FAILURE);
5525 5525 ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp);
5526 5526 ASSERT(ispecp);
5527 5527 ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result;
5528 5528 break;
5529 5529 case DDI_INTROP_ADDISR:
5530 5530 if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL)
5531 5531 return (DDI_FAILURE);
5532 5532 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
5533 5533 break;
5534 5534 case DDI_INTROP_REMISR:
5535 5535 pcmcia_intr_remove_isr(dip, rdip, hdlp);
5536 5536 break;
5537 5537 case DDI_INTROP_ENABLE:
5538 5538 if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS)
5539 5539 return (DDI_FAILURE);
5540 5540 break;
5541 5541 case DDI_INTROP_DISABLE:
5542 5542 pcmcia_intr_disable_isr(dip, rdip, hdlp);
5543 5543 break;
5544 5544 default:
5545 5545 return (DDI_ENOTSUP);
5546 5546 }
5547 5547
5548 5548 return (DDI_SUCCESS);
5549 5549 }
5550 5550 #endif
↓ open down ↓ |
5233 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX