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