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