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