6908114 Kerberos integer underflow bugs in AES and RC4 decryption [MITKRB5-SA-2009...
[illumos-gate.git] / usr / src / uts / sun / io / stp4020.c
blob29ad3a2df193e88c6880de17f923a7a6c57a5aaa
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * DRT device/interrupt handler
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/user.h>
35 #include <sys/buf.h>
36 #include <sys/file.h>
37 #include <sys/uio.h>
38 #include <sys/conf.h>
39 #include <sys/stat.h>
40 #include <sys/autoconf.h>
41 #include <sys/vtoc.h>
42 #include <sys/dkio.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/ddidmareq.h>
46 #include <sys/kstat.h>
47 #include <sys/kmem.h>
49 #include <sys/pctypes.h>
50 #include <sys/pcmcia.h>
51 #include <sys/sservice.h>
53 #include <sys/stp4020_reg.h>
54 #include <sys/stp4020_var.h>
55 #include <sys/spl.h>
58 struct stpramap *stpra_freelist = NULL;
62 char _depends_on[] = "misc/pcmcia";
64 #define OUTB(a, b) outb(a, b)
65 #define INB(a) inb(a)
67 int drt_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
68 static int drt_attach(dev_info_t *, ddi_attach_cmd_t);
69 static int drt_detach(dev_info_t *, ddi_detach_cmd_t);
71 static void drt_ll_reset(drt_dev_t *, int);
72 static void drt_stop_intr(drt_dev_t *, int);
73 static void drt_cpr(drt_dev_t *, int);
74 static void drt_new_card(drt_dev_t *, int);
75 static void drt_fixprops(dev_info_t *);
76 static int drt_inquire_adapter(dev_info_t *, inquire_adapter_t *);
78 static struct stpramap *stpra_alloc_map();
79 static void stpra_free_map(struct stpramap *);
80 static void stpra_free(struct stpramap **, uint32_t, uint32_t);
81 static int stpra_alloc(struct stpramap **, stpra_request_t *, stpra_return_t *);
82 static uint32_t stpra_fix_pow2(uint32_t);
85 static kmutex_t stpra_lock;
87 static
88 struct bus_ops pcmciabus_ops = {
89 BUSO_REV,
90 i_ddi_bus_map,
91 NULL,
92 NULL,
93 NULL,
94 i_ddi_map_fault,
95 ddi_no_dma_map,
96 ddi_no_dma_allochdl,
97 ddi_no_dma_freehdl,
98 ddi_no_dma_bindhdl,
99 ddi_no_dma_unbindhdl,
100 ddi_no_dma_flush,
101 ddi_no_dma_win,
102 ddi_no_dma_mctl,
103 pcmcia_ctlops,
104 pcmcia_prop_op,
105 NULL, /* (*bus_get_eventcookie)(); */
106 NULL, /* (*bus_add_eventcall)(); */
107 NULL, /* (*bus_remove_eventcall)(); */
108 NULL, /* (*bus_post_event)(); */
109 NULL, /* (*bus_intr_ctl)(); */
110 NULL, /* (*bus_config)(); */
111 NULL, /* (*bus_unconfig)(); */
112 NULL, /* (*bus_fm_init)(); */
113 NULL, /* (*bus_fm_fini)(); */
114 NULL, /* (*bus_enter)() */
115 NULL, /* (*bus_exit)() */
116 NULL, /* (*bus_power)() */
117 pcmcia_intr_ops /* (*bus_intr_op)(); */
120 static struct dev_ops drt_devops = {
121 DEVO_REV,
123 drt_getinfo,
124 nulldev,
125 nulldev,
126 drt_attach,
127 drt_detach,
128 nulldev,
129 NULL,
130 &pcmciabus_ops,
131 ddi_power,
132 ddi_quiesce_not_supported, /* devo_quiesce */
135 #if defined(DEBUG)
136 #define DRT_DEBUG
137 #endif
138 #if defined(DRT_DEBUG)
139 static void drt_dmp_regs(stp4020_socket_csr_t *);
140 int drt_debug = 0;
141 #endif
143 /* bit patterns to select voltage levels */
144 int drt_vpp_levels[13] = {
145 0, 0, 0, 0, 0,
146 1, /* 5V */
147 0, 0, 0, 0, 0, 0,
148 2 /* 12V */
150 struct power_entry drt_power[DRT_NUM_POWER] = {
152 0, /* off */
153 VCC|VPP1|VPP2
156 5*10, /* 5Volt */
157 VCC|VPP1|VPP2
160 12*10, /* 12Volt */
161 VPP1|VPP2
165 drt_dev_t *drt_get_driver_private(dev_info_t *);
166 uint32_t drt_hi_intr(caddr_t);
167 uint32_t drt_lo_intr(caddr_t);
169 static int drt_callback(dev_info_t *, int (*)(), int);
170 static int drt_inquire_adapter(dev_info_t *, inquire_adapter_t *);
171 static int drt_get_adapter(dev_info_t *, get_adapter_t *);
172 static int drt_get_page(dev_info_t *, get_page_t *);
173 static int drt_get_socket(dev_info_t *, get_socket_t *);
174 static int drt_get_status(dev_info_t *, get_ss_status_t *);
175 static int drt_get_window(dev_info_t *, get_window_t *);
176 static int drt_inquire_socket(dev_info_t *, inquire_socket_t *);
177 static int drt_inquire_window(dev_info_t *, inquire_window_t *);
178 static int drt_reset_socket(dev_info_t *, int, int);
179 static int drt_set_page(dev_info_t *, set_page_t *);
180 static int drt_set_window(dev_info_t *, set_window_t *);
181 static int drt_set_socket(dev_info_t *, set_socket_t *);
182 static int drt_set_interrupt(dev_info_t *, set_irq_handler_t *);
183 static int drt_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
184 void drt_socket_card_id(drt_dev_t *, drt_socket_t *, int);
187 * pcmcia interface operations structure
188 * this is the private interface that is exported to the nexus
190 pcmcia_if_t drt_if_ops = {
191 PCIF_MAGIC,
192 PCIF_VERSION,
193 drt_callback,
194 drt_get_adapter,
195 drt_get_page,
196 drt_get_socket,
197 drt_get_status,
198 drt_get_window,
199 drt_inquire_adapter,
200 drt_inquire_socket,
201 drt_inquire_window,
202 drt_reset_socket,
203 drt_set_page,
204 drt_set_window,
205 drt_set_socket,
206 drt_set_interrupt,
207 drt_clear_interrupt,
208 NULL,
212 * This is the loadable module wrapper.
214 #include <sys/modctl.h>
216 extern struct mod_ops mod_driverops;
218 static struct modldrv modldrv = {
219 &mod_driverops, /* Type of module. This one is a driver */
220 "STP4020 (SUNW,pcmcia) adapter driver", /* Name of the module. */
221 &drt_devops, /* driver ops */
224 static struct modlinkage modlinkage = {
225 MODREV_1, (void *)&modldrv, NULL
229 _init()
231 int ret;
233 mutex_init(&stpra_lock, NULL, MUTEX_DRIVER,
234 (void *)(uintptr_t)__ipltospl(SPL7 - 1));
235 if ((ret = mod_install(&modlinkage)) != 0) {
236 mutex_destroy(&stpra_lock);
238 return (ret);
242 _fini()
244 int ret;
245 struct stpramap *next;
247 if ((ret = mod_remove(&modlinkage)) == 0) {
249 mutex_enter(&stpra_lock);
250 while (stpra_freelist != NULL) {
251 next = stpra_freelist->ra_next;
252 kmem_free((caddr_t)stpra_freelist,
253 sizeof (struct stpramap));
254 stpra_freelist = next;
256 mutex_exit(&stpra_lock);
258 mutex_destroy(&stpra_lock);
260 return (ret);
264 _info(struct modinfo *modinfop)
266 return (mod_info(&modlinkage, modinfop));
270 * drt_getinfo()
271 * provide instance/device information about driver
274 drt_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
276 int error = DDI_SUCCESS;
277 switch (cmd) {
278 case DDI_INFO_DEVT2DEVINFO:
279 /* should make independent of SUNW,pcmcia */
280 dip = ddi_find_devinfo("SUNW,pcmcia", getminor((dev_t)arg), 1);
281 *result = dip;
282 break;
283 case DDI_INFO_DEVT2INSTANCE:
284 *result = 0;
285 break;
286 default:
287 error = DDI_FAILURE;
288 break;
291 return (error);
295 * drt_attach()
296 * attach the DRT (SPARC STP4020) driver
297 * to the system. This is a child of "sysbus" since that is where
298 * the hardware lives, but it provides services to the "pcmcia"
299 * nexus driver. It gives a pointer back via its private data
300 * structure which contains both the dip and socket services entry
301 * points
303 static int
304 drt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
306 drt_dev_t *drt;
307 struct pcmcia_adapter_nexus_private *drt_nexus;
308 int i;
309 ddi_device_acc_attr_t dev_attr;
310 int regs[24];
311 int err;
313 #if defined(DRT_DEBUG)
314 if (drt_debug) {
315 cmn_err(CE_CONT, "drt_attach(%d): entered\n", cmd);
317 #endif
318 switch (cmd) {
319 default:
320 return (DDI_FAILURE);
321 case DDI_RESUME:
322 drt_nexus = ddi_get_driver_private(dip);
323 drt = (drt_dev_t *)drt_get_driver_private(dip);
324 #if defined(DRT_DEBUG)
325 if (drt_debug) {
326 cmn_err(CE_CONT, "drt_attach: DDI_RESUME\n");
328 #endif
329 if (drt != NULL && drt->pc_flags & PCF_SUSPENDED) {
330 /* XXX - why would drt be NULL?? */
331 int sn;
332 for (sn = 0; sn < DRSOCKETS; sn++) {
333 drt_socket_t *sockp = &drt->pc_sockets[sn];
335 /* Restore adapter hardware state */
336 mutex_enter(&drt->pc_lock);
337 drt_cpr(drt, DRT_RESTORE_HW_STATE);
338 drt_new_card(drt, sn);
339 drt_socket_card_id(drt, sockp,
340 drt->pc_csr->socket[sn].stat0);
341 mutex_exit(&drt->pc_lock);
343 } /* for (sn) */
344 mutex_enter(&drt->pc_lock);
345 drt->pc_flags &= ~PCF_SUSPENDED;
346 mutex_exit(&drt->pc_lock);
347 /* do we want to do anything here??? */
349 /* this code should do PC Card Standard form */
350 (void) pcmcia_begin_resume(dip);
352 * this will do the CARD_INSERTION
353 * due to needing time for threads to
354 * run, it must be delayed for a short amount
355 * of time. pcmcia_wait_insert checks for all
356 * children to be removed and then triggers insert.
358 (void) pcmcia_wait_insert(dip);
360 * for complete implementation need END_RESUME (later)
362 return (DDI_SUCCESS);
364 return (DDI_FAILURE);
365 case DDI_ATTACH:
366 break;
369 drt = (drt_dev_t *)kmem_zalloc(sizeof (drt_dev_t), KM_NOSLEEP);
370 if (drt == NULL) {
371 return (DDI_FAILURE);
374 #if defined(DRT_DEBUG)
375 if (drt_debug)
376 cmn_err(CE_CONT, "drt_attach: drt=%p\n", (void *)drt);
377 #endif
378 drt_nexus = (struct pcmcia_adapter_nexus_private *)
379 kmem_zalloc(sizeof (struct pcmcia_adapter_nexus_private),
380 KM_NOSLEEP);
381 if (drt_nexus == NULL) {
382 kmem_free(drt, sizeof (drt_dev_t));
383 return (DDI_FAILURE);
385 /* map everything in we will ultimately need */
386 drt->pc_devinfo = dip;
387 drt->pc_csr = 0;
388 dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
389 dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
390 dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
391 if (ddi_regs_map_setup(dip, DRMAP_ASIC_CSRS, (caddr_t *)&drt->pc_csr,
392 (off_t)0, sizeof (stp4020_socket_csr_t),
393 &dev_attr, &drt->pc_handle) != 0) {
394 kmem_free(drt, sizeof (drt_dev_t));
395 kmem_free(drt_nexus,
396 sizeof (struct pcmcia_adapter_nexus_private *));
397 return (DDI_FAILURE);
399 #if defined(DRT_DEBUG)
400 if (drt_debug) {
401 cmn_err(CE_CONT, "drt_attach: %x->%p\n", DRMAP_ASIC_CSRS,
402 (void *)drt->pc_csr);
404 #endif
406 i = sizeof (regs);
407 if ((err = ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
408 DDI_PROP_CANSLEEP, "reg",
409 (caddr_t)regs, &i)) != DDI_SUCCESS) {
411 kmem_free(drt, sizeof (drt_dev_t));
412 kmem_free(drt_nexus,
413 sizeof (struct pcmcia_adapter_nexus_private));
414 return (DDI_FAILURE);
418 drt_nexus->an_dip = dip;
419 drt_nexus->an_if = &drt_if_ops;
420 drt_nexus->an_private = drt;
422 drt->pc_numpower = DRT_NUM_POWER;
423 drt->pc_power = drt_power;
425 drt->pc_numsockets = DRSOCKETS;
426 drt->pc_flags |= PCF_ATTACHING;
428 ddi_set_driver_private(dip, drt_nexus);
430 /* allow property to override audio */
431 if (ddi_getprop(DDI_DEV_T_NONE, dip,
432 DDI_PROP_DONTPASS, "disable-audio", -1) == -1)
433 drt->pc_flags |= PCF_AUDIO;
435 /* now enable both interrupt handlers */
436 if (ddi_add_intr(dip, 1, &drt->pc_icookie_hi, &drt->pc_dcookie_hi,
437 drt_hi_intr, (caddr_t)dip) != DDI_SUCCESS) {
438 /* if it fails, unwind everything */
439 ddi_regs_map_free(&drt->pc_handle);
440 kmem_free((caddr_t)drt, sizeof (drt_dev_t));
441 kmem_free((caddr_t)drt_nexus, sizeof (*drt_nexus));
442 return (DDI_FAILURE);
445 #if 0
446 if (ddi_add_intr(dip, 0, &drt->pc_icookie_lo, &drt->pc_dcookie_lo,
447 drt_lo_intr, (caddr_t)dip) != DDI_SUCCESS) {
448 /* if it fails, unwind everything */
449 ddi_remove_intr(dip, 0, &drt->pc_icookie_hi);
450 ddi_regs_map_free(&drt->pc_handle);
451 kmem_free((caddr_t)drt, sizeof (drt_dev_t));
452 kmem_free((caddr_t)drt_nexus, sizeof (*drt_nexus));
453 return (DDI_FAILURE);
455 #endif
456 mutex_init(&drt->pc_lock, NULL, MUTEX_DRIVER, drt->pc_icookie_hi);
457 mutex_init(&drt->pc_intr, NULL, MUTEX_DRIVER, drt->pc_icookie_hi);
459 drt_nexus->an_iblock = &drt->pc_icookie_hi;
460 drt_nexus->an_idev = &drt->pc_dcookie_hi;
462 mutex_enter(&drt->pc_lock);
464 for (i = 0; i < DRSOCKETS; i++) {
465 struct stpramap *map;
467 drt->pc_csr->socket[i].ctl1 = 0; /* turn things off */
468 drt->pc_csr->socket[i].ctl0 = 0; /* before we touch anything */
470 /* work around for false status bugs */
471 drt->pc_csr->socket[i].stat1 = 0x3FFF;
472 drt->pc_csr->socket[i].stat0 = 0x3FFF;
475 * enable the socket as well
476 * want status change interrupts for all possible events
477 * We do this even though CS hasn't asked. The system
478 * wants to manage these and will only tell CS of those
479 * it asks for
481 /* identify current state of card */
482 drt_socket_card_id(drt, &drt->pc_sockets[i],
483 drt->pc_csr->socket[i].stat0);
485 /* finally, turn it on */
486 drt->pc_csr->socket[i].ctl0 = DRT_CHANGE_DEFAULT;
488 /* now we need per-socket I/O space allocation */
489 map = drt->pc_sockets[i].drt_iomap = stpra_alloc_map();
490 map->ra_base = 0;
491 map->ra_len = 0xffffff; /* 1MB */
494 drt_fixprops(dip);
497 * now that the adapter is fully operational
498 * it is time to pull in the PCMCIA framework
499 * and let it know we exist and are "ready"
501 mutex_exit(&drt->pc_lock);
502 err = pcmcia_attach(dip, drt_nexus);
504 return (err);
508 * drt_detach()
509 * request to detach from the system
511 static int
512 drt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
514 int i;
515 drt_dev_t *drt = (drt_dev_t *)drt_get_driver_private(dip);
517 switch (cmd) {
518 case DDI_DETACH:
519 if (drt != NULL) {
520 /* turn everything off for all sockets and chips */
521 for (i = 0; i < drt->pc_numsockets; i++) {
522 drt->pc_csr->socket[i].ctl0 = 0;
523 drt->pc_csr->socket[i].ctl1 = 0;
525 stpra_free_map(drt->pc_sockets[i].drt_iomap);
526 ddi_regs_map_free(&drt->pc_handle);
527 ddi_remove_intr(dip, 0, drt->pc_icookie_lo);
528 ddi_remove_intr(dip, 1, drt->pc_icookie_hi);
529 drt->pc_flags = 0;
530 mutex_destroy(&drt->pc_lock);
531 return (DDI_SUCCESS);
533 break;
535 case DDI_PM_SUSPEND:
536 #if defined(DRT_DEBUG)
537 if (drt_debug) {
538 cmn_err(CE_WARN, "stp4020: DDI_PM_SUSPEND\n");
540 #endif
541 /*FALLTHROUGH*/
542 case DDI_SUSPEND:
543 #if defined(DRT_DEBUG)
544 if (drt_debug) {
545 cmn_err(CE_CONT, "drt_detach: DDI_SUSPEND\n");
547 #endif
548 if (drt != NULL) {
549 /* XXX - why is this test necessary here? */
550 int sn;
551 mutex_enter(&drt->pc_lock);
552 drt->pc_flags |= PCF_SUSPENDED;
553 mutex_exit(&drt->pc_lock);
554 for (sn = 0; sn < DRSOCKETS; sn++) {
555 /* drt_stop_intr(drt, sn); XXX ?? */
556 mutex_enter(&drt->pc_lock);
557 /* clears sockp->drt_flags */
558 drt_new_card(drt, sn);
559 mutex_exit(&drt->pc_lock);
562 * Save the adapter's hardware state here
564 mutex_enter(&drt->pc_lock);
565 drt_cpr(drt, DRT_SAVE_HW_STATE);
566 mutex_exit(&drt->pc_lock);
567 return (DDI_SUCCESS);
568 } /* if (drt) */
569 } /* switch */
570 return (DDI_FAILURE);
573 drt_dev_t *
574 drt_get_driver_private(dev_info_t *dip)
576 struct pcmcia_adapter_nexus_private *nexus;
577 nexus = ddi_get_driver_private(dip);
578 return ((drt_dev_t *)nexus->an_private);
582 * drt_inquire_adapter()
583 * SocketServices InquireAdapter function
584 * get characteristics of the physical adapter
586 static int
587 drt_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
589 drt_dev_t *drt = drt_get_driver_private(dip);
590 #if defined(DRT_DEBUG)
591 if (drt_debug)
592 cmn_err(CE_CONT, "drt_inquire_adapter\n");
593 #endif
594 config->NumSockets = drt->pc_numsockets;
595 config->NumWindows = DRT_NUMWINDOWS;
596 config->NumEDCs = 0;
597 config->AdpCaps = 0;
598 config->ActiveHigh = 3;
599 config->ActiveLow = 0;
600 config->NumPower = drt->pc_numpower;
601 config->power_entry = drt->pc_power; /* until we resolve this */
602 config->ResourceFlags = RES_OWN_IRQ | RES_OWN_IO | RES_OWN_MEM |
603 RES_IRQ_NEXUS | RES_IRQ_SHAREABLE;
604 return (SUCCESS);
608 * drt_callback()
609 * The PCMCIA nexus calls us via this function
610 * in order to set the callback function we are
611 * to call the nexus with
613 static int
614 drt_callback(dev_info_t *dip, int (*handler)(), int arg)
616 drt_dev_t *drt = (drt_dev_t *)drt_get_driver_private(dip);
617 #if defined(DRT_DEBUG)
618 if (drt_debug) {
619 #ifdef XXX
620 cmn_err(CE_CONT, "drt_callback: drt=%x, lock=%x\n",
621 (int)drt, (int)drt->pc_lock);
622 #endif
623 cmn_err(CE_CONT, "\thandler=%p, arg=%x\n", (void *)handler,
624 arg);
626 #endif
627 if (handler != NULL) {
628 drt->pc_callback = handler;
629 drt->pc_cb_arg = arg;
630 drt->pc_flags |= PCF_CALLBACK;
631 } else {
632 drt->pc_callback = NULL;
633 drt->pc_cb_arg = 0;
634 drt->pc_flags &= ~PCF_CALLBACK;
637 * we're now registered with the nexus
638 * it is acceptable to do callbacks at this point.
639 * don't call back from here though since it could block
642 return (PC_SUCCESS);
646 * drt_calc_speed()
647 * determine the bit pattern for speeds to be put in the control register
650 static int
651 drt_calc_speed(int speed)
653 int length;
654 int delay;
656 * the documented speed determination (25MHZ) is
657 * 250 + (CMDLNG - 4) * 40 < speed <= 250 + (CMDLNG - 3) * 40
658 * The value of CMDLNG is roughly determined by
659 * CMDLNG == ((speed - 250) / 40) + [3|4]
660 * the calculation is very approximate.
661 * for speeds <= 250ns, use simple formula
663 * this should really be based on processor speed.
666 if (speed <= 250) {
667 if (speed < 100)
668 speed = 100;
669 length = (speed - 100) / 50;
670 if (speed <= 100)
671 delay = 1;
672 else
673 delay = 2;
674 } else {
675 length = ((speed - 250) / 40);
676 if ((250 + (length - 3) * 40) == speed)
677 length += 3;
678 else
679 length += 4;
680 delay = 2;
683 #if defined(DRT_DEBUG)
684 if (drt_debug)
685 cmn_err(CE_CONT, "drt_calc_speed: speed=%d, length=%x, "
686 "delay=%x, ret=%x\n",
687 speed, length, delay,
688 (SET_DRWIN_CMDDLY(delay) | SET_DRWIN_CMDLNG(length)));
689 #endif
690 return (SET_DRWIN_CMDDLY(delay) | SET_DRWIN_CMDLNG(length));
694 * drt_set_window
695 * essentially the same as the Socket Services specification
696 * We use socket and not adapter since they are identifiable
697 * but the rest is the same
699 * dip drt driver's device information
700 * window parameters for the request
702 static int
703 drt_set_window(dev_info_t *dip, set_window_t *window)
705 int prevstate;
706 int which, win;
707 drt_dev_t *drt = drt_get_driver_private(dip);
708 drt_socket_t *sockp;
709 struct drt_window *winp;
710 stp4020_socket_csr_t *csrp;
711 int windex;
713 #if defined(DRT_DEBUG)
714 if (drt_debug) {
715 cmn_err(CE_CONT, "drt_set_window: entered\n");
716 cmn_err(CE_CONT,
717 "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
718 window->window, window->socket, window->WindowSize,
719 window->speed);
720 cmn_err(CE_CONT,
721 "\tbase=%x, state=%x\n", (int)window->base,
722 window->state);
724 #endif
728 * do some basic sanity checking on what we support
729 * we don't do paged mode
731 if (window->state & WS_PAGED)
732 return (BAD_ATTRIBUTE);
735 * make sure we use the correct internal socket/window
736 * combination
738 win = window->window % DRWINDOWS;
739 if (window->socket != (window->window / DRWINDOWS)) {
740 return (BAD_SOCKET);
743 if (!(window->state & WS_IO) && (window->WindowSize != DRWINSIZE &&
744 !(window->state & WS_EXACT_MAPIN)) ||
745 window->WindowSize > DRWINSIZE) {
746 #if defined(DRT_DEBUG)
747 if (drt_debug)
748 cmn_err(CE_CONT, "\tBAD SIZE\n");
749 #endif
750 return (BAD_SIZE);
753 sockp = &drt->pc_sockets[window->socket];
755 #if defined(DRT_DEBUG)
756 if (drt_debug)
757 cmn_err(CE_CONT,
758 "\tusing window/socket %d/%d\n", win, window->socket);
759 #endif
762 * we don't care about previous mappings.
763 * Card Services will deal with that so don't
764 * even check
767 winp = &sockp->drt_windows[win];
768 csrp = &drt->pc_csr->socket[window->socket];
770 mutex_enter(&drt->pc_lock); /* protect the registers */
771 prevstate = winp->drtw_flags;
772 which = 0; /* no error */
774 /* disable current settings */
775 csrp->window[win].ctl0 = 0;
778 * disable current mapping
779 * this will handle the case of WS_ENABLED not being set
781 #ifdef notdef
782 if ((window->state & (WS_IO|WS_EXACT_MAPIN)) ==
783 (WS_IO|WS_EXACT_MAPIN)) {
784 if (window->base.base != 0) {
785 /* compensate for having to start at 0 */
786 window->WindowSize += (uint32_t)window->base.base;
789 #endif
791 if (window->socket == 0)
792 windex = DRMAP_CARD0_WIN0 + win;
793 else
794 windex = DRMAP_CARD1_WIN0 + win;
796 if ((prevstate & DRW_MAPPED) &&
797 (window->WindowSize != winp->drtw_len)) {
798 mutex_exit(&drt->pc_lock);
799 ddi_regs_map_free(&winp->drtw_handle);
800 mutex_enter(&drt->pc_lock);
801 #if defined(DRT_DEBUG)
802 if (drt_debug)
803 cmn_err(CE_CONT,
804 "\tunmapped: base being set to NULL\n");
805 #endif
806 winp->drtw_flags &= ~(DRW_MAPPED|DRW_ENABLED);
807 if (prevstate & DRW_IO) {
808 stpra_free(&sockp->drt_iomap,
809 (uint32_t)(uintptr_t)winp->drtw_reqaddr,
810 (uint32_t)winp->drtw_len);
812 winp->drtw_base = NULL;
815 if (window->state & WS_ENABLED) {
816 if (winp->drtw_base == NULL) {
817 if (window->state & WS_IO) {
818 stpra_request_t req;
819 stpra_return_t ret;
820 bzero((caddr_t)&req, sizeof (req));
821 bzero((caddr_t)&ret, sizeof (ret));
822 req.ra_flags = STP_RA_ALLOC_POW2 |
823 STP_RA_ALIGN_SIZE;
824 req.ra_len = window->WindowSize;
825 req.ra_addr_lo = window->base;
827 if (window->base != 0)
828 req.ra_flags |= STP_RA_ALLOC_SPECIFIED;
830 if (stpra_alloc(&sockp->drt_iomap,
831 &req, &ret) != DDI_SUCCESS) {
832 mutex_exit(&drt->pc_lock);
833 return (BAD_BASE);
835 /* now use the resultant address */
836 window->base = ret.ra_addr_lo;
838 mutex_exit(&drt->pc_lock);
839 which = ddi_regs_map_setup(drt->pc_devinfo,
840 windex,
841 &winp->drtw_base,
842 (offset_t)window->base,
843 window->WindowSize,
844 &window->attr,
845 &winp->drtw_handle);
846 mutex_enter(&drt->pc_lock);
847 if (which != DDI_SUCCESS) {
848 mutex_exit(&drt->pc_lock);
849 return (BAD_SIZE);
851 #if defined(DRT_DEBUG)
852 if (drt_debug)
853 cmn_err(CE_CONT,
854 "\tmapped: handle = 0x%p base = %p, "
855 "len=%x\n",
856 (void *)winp->drtw_handle,
857 (void *)winp->drtw_base,
858 (int)window->WindowSize);
859 #endif
861 winp->drtw_reqaddr = (caddr_t)(uintptr_t)window->base;
862 winp->drtw_flags |= DRW_MAPPED | DRW_ENABLED;
864 if (!(window->state & WS_IO)) {
865 winp->drtw_speed = window->speed;
866 winp->drtw_ctl0 = drt_calc_speed(window->speed);
867 winp->drtw_ctl0 |= DRWIN_ASPSEL_CM;
868 winp->drtw_flags &= ~DRW_IO;
869 } else {
870 winp->drtw_flags |= DRW_IO;
871 winp->drtw_ctl0 = DRWIN_ASPSEL_IO |
872 drt_calc_speed(window->speed);
873 winp->drtw_modhandle.ah_addr += (int)window->base;
875 window->handle = winp->drtw_handle;
876 csrp->window[win].ctl0 = winp->drtw_ctl0;
877 csrp->window[win].ctl1 = SET_DRWIN_WAITREQ(1) |
878 SET_DRWIN_WAITDLY(0);
879 winp->drtw_len = window->WindowSize;
880 } else {
881 if (winp->drtw_flags & DRW_ENABLED) {
882 winp->drtw_flags &= ~DRW_ENABLED;
883 csrp->window[win].ctl0 = 0; /* force off */
884 #ifdef XXX
885 if (prevstate & DRW_IO) {
886 stpra_free(&sockp->drt_iomap,
887 (uint32_t)winp->drtw_reqaddr,
888 (uint32_t)winp->drtw_len);
890 #endif /* XXX */
892 winp->drtw_base = NULL;
895 #if defined(DRT_DEBUG)
896 if (drt_debug) {
897 cmn_err(CE_CONT,
898 "\tbase now set to %p (->%p), csrp=%p, winreg=%p"
899 ", len=%x\n",
900 (void *)window->handle,
901 (void *)winp->drtw_base, (void *)csrp,
902 (void *)&csrp->window[win].ctl0,
903 (int)window->WindowSize);
904 cmn_err(CE_CONT,
905 "\twindow type is now %s\n", window->state & WS_IO ?
906 "I/O" : "memory");
907 if (drt_debug > 1)
908 drt_dmp_regs(csrp);
910 #endif
912 mutex_exit(&drt->pc_lock);
914 return (SUCCESS);
918 * drt_card_state()
919 * compute the instantaneous Card State information
922 drt_card_state(drt_dev_t *drt, int socket)
924 int value, result;
926 mutex_enter(&drt->pc_lock); /* protect the registers */
928 value = drt->pc_csr->socket[socket].stat0;
929 #if defined(DRT_DEBUG)
930 if (drt_debug) {
931 cmn_err(CE_CONT, "drt_card_state: socket=%d, *lock=%p\n",
932 socket, (void *)&drt->pc_lock);
933 cmn_err(CE_CONT, "\tcsr@%p\n", (void *)drt->pc_csr);
935 cmn_err(CE_CONT, "\tstat0=%b\n", value,
936 "\020\1PWRON\2WAIT\3WP\4RDYBSY\5BVD1\6BVD2\7CD1"
937 "\10CD2\011ACCTO\012WPC\013RBC\014BVD1C\015BVD2C"
938 "\016CDSC\017STAT");
939 cmn_err(CE_CONT,
940 "\tstat1=%x\n",
941 (int)drt->pc_csr->socket[socket].stat1);
942 cmn_err(CE_CONT, "\t&stat0=%p, &stat1=%p\n",
943 (void *)&drt->pc_csr->socket[socket].stat0,
944 (void *)&drt->pc_csr->socket[socket].stat1);
946 #endif
948 if (value & DRSTAT_WPST)
949 result = SBM_WP;
950 else
951 result = 0;
953 switch (value & DRSTAT_BVDST) {
954 case DRSTAT_BATT_LOW:
955 result |= SBM_BVD2;
956 break;
957 case DRSTAT_BATT_OK:
958 break;
959 default:
960 /* battery dead */
961 result |= SBM_BVD1;
962 break;
965 if (value & DRSTAT_RDYST)
966 result |= SBM_RDYBSY;
967 if ((value & (DRSTAT_CD1ST|DRSTAT_CD2ST)) ==
968 (DRSTAT_CD1ST|DRSTAT_CD2ST))
969 result |= SBM_CD;
971 mutex_exit(&drt->pc_lock);
973 return (result);
977 * drt_set_page()
978 * SocketServices SetPage function
979 * set the page of PC Card memory that should be in the mapped
980 * window
984 drt_set_page(dev_info_t *dip, set_page_t *page)
986 int which, socket, win;
987 drt_dev_t *drt = drt_get_driver_private(dip);
988 drt_socket_t *sockp;
989 struct drt_window *winp;
990 stp4020_socket_csr_t *csrp;
992 if (page->window >= DRT_NUMWINDOWS) {
993 #if defined(DRT_DEBUG)
994 if (drt_debug)
995 cmn_err(CE_CONT, "drt_set_page: window=%d (%d)\n",
996 page->window, DRWINDOWS);
997 #endif
998 return (BAD_WINDOW);
1001 win = page->window % DRWINDOWS;
1002 socket = page->window / DRWINDOWS;
1004 sockp = &drt->pc_sockets[socket];
1006 #if defined(DRT_DEBUG)
1007 if (drt_debug) {
1008 cmn_err(CE_CONT,
1009 "drt_set_page: window=%d, socket=%d, page=%d\n",
1010 win, socket, page->page);
1012 #endif
1014 /* only one page supported (fixed at 1MB) */
1015 #if defined(DRT_DEBUG)
1016 if (drt_debug)
1017 cmn_err(CE_CONT, "\tpage=%d\n", page->page);
1018 #endif
1019 winp = &sockp->drt_windows[win];
1020 csrp = &drt->pc_csr->socket[socket];
1022 if (winp->drtw_flags & DRW_IO) {
1023 return (BAD_WINDOW);
1026 if (page->page != 0) {
1027 return (BAD_PAGE);
1030 mutex_enter(&drt->pc_lock); /* protect the registers */
1033 * now map the card's memory pages - we start with page 0
1036 if (page->state & PS_ATTRIBUTE) {
1037 which = SET_DRWIN_CMDDLY(2) | SET_DRWIN_CMDLNG(4);
1038 winp->drtw_flags |= DRW_ATTRIBUTE;
1039 } else {
1040 which = winp->drtw_ctl0 & (DRWIN_CMDLNG_M|DRWIN_CMDDLY_M);
1041 winp->drtw_flags &= ~DRW_ATTRIBUTE;
1044 which |= (page->state & PS_ATTRIBUTE) ?
1045 DRWIN_ASPSEL_AM : DRWIN_ASPSEL_CM;
1047 /* if card says Write Protect, enforce it */
1048 /* but we don't have hardware support to do it */
1050 /* The actual PC Card address mapping */
1051 #if defined(DRT_DEBUG)
1052 if (drt_debug)
1053 cmn_err(CE_CONT, "\ta2p=%x, base=%x, csrp=%p\n",
1054 (int)ADDR2PAGE(page->offset),
1055 SET_DRWIN_BASE(ADDR2PAGE(page->offset)),
1056 (void *)csrp);
1057 #endif
1058 which |= SET_DRWIN_BASE(ADDR2PAGE(page->offset));
1059 winp->drtw_addr = (caddr_t)page->offset;
1061 /* now set the register */
1062 #if defined(DRT_DEBUG)
1063 if (drt_debug)
1064 cmn_err(CE_CONT, "\tset ctl0=%x\n", which);
1065 #endif
1067 csrp->window[win].ctl0 = (ushort_t)which;
1068 csrp->window[win].ctl1 = SET_DRWIN_WAITREQ(1) | SET_DRWIN_WAITDLY(0);
1070 /* now */
1072 #if defined(DRT_DEBUG)
1073 if (drt_debug) {
1074 cmn_err(CE_CONT, "\tmemory type = %s\n",
1075 (which & DRWIN_ASPSEL_CM) ? "common" : "attribute");
1077 #endif
1080 #if defined(DRT_DEBUG)
1081 if (drt_debug) {
1082 cmn_err(CE_CONT,
1083 "\tpage offset=%x, base=%p (PC addr=%p, sockets=%d)\n",
1084 (int)page->offset, (void *)winp->drtw_base,
1085 (void *)winp->drtw_addr, drt->pc_numsockets);
1086 cmn_err(CE_CONT, "\t*base=%x, win reg=%p\n",
1087 *(ushort_t *)winp->drtw_base,
1088 (void *)&csrp->window[win].ctl0);
1089 if (drt_debug > 1)
1090 drt_dmp_regs(csrp);
1092 #endif
1093 mutex_exit(&drt->pc_lock);
1095 return (SUCCESS);
1099 * drt_set_socket()
1100 * Socket Services SetSocket call
1101 * sets basic socket configuration
1103 static int
1104 drt_set_socket(dev_info_t *dip, set_socket_t *socket)
1106 int value, sock;
1107 drt_dev_t *drt = drt_get_driver_private(dip);
1108 drt_socket_t *sockp = &drt->pc_sockets[socket->socket];
1109 int irq = 0;
1110 int powerlevel = 0;
1111 int ind;
1113 sock = socket->socket;
1115 #if defined(DRT_DEBUG)
1116 if (drt_debug) {
1117 cmn_err(CE_CONT, "drt_set_socket: entered (socket=%d)\n", sock);
1119 #endif
1121 * check VccLevel, etc. before setting mutex
1122 * if this is zero, power is being turned off
1123 * if it is non-zero, power is being turned on.
1124 * the default case is to assume Vcc only.
1127 /* this appears to be very implementation specific */
1129 if (socket->VccLevel == 0) {
1130 powerlevel = 0;
1131 } else if (socket->VccLevel < drt->pc_numpower &&
1132 drt_power[socket->VccLevel].ValidSignals & VCC) {
1133 /* enable Vcc */
1134 powerlevel = DRCTL_MSTPWR|DRCTL_PCIFOE;
1135 sockp->drt_vcc = socket->VccLevel;
1136 } else {
1137 return (BAD_VCC);
1139 #if defined(DRT_DEBUG)
1140 if (drt_debug) {
1141 cmn_err(CE_CONT, "\tVccLevel=%d, Vpp1Level=%d, Vpp2Level=%d\n",
1142 socket->VccLevel,
1143 socket->Vpp1Level, socket->Vpp2Level);
1145 #endif
1146 ind = 0; /* default index to 0 power */
1147 if (socket->Vpp1Level >= 0 && socket->Vpp1Level < drt->pc_numpower) {
1148 if (!(drt_power[socket->Vpp1Level].ValidSignals & VPP1)) {
1149 return (BAD_VPP);
1151 ind = drt_power[socket->Vpp1Level].PowerLevel/10;
1152 powerlevel |= drt_vpp_levels[ind] << 2;
1153 sockp->drt_vpp1 = socket->Vpp1Level;
1155 if (socket->Vpp2Level >= 0 && socket->Vpp2Level < drt->pc_numpower) {
1156 if (!(drt_power[socket->Vpp2Level].ValidSignals & VPP2)) {
1157 return (BAD_VPP);
1159 ind = drt_power[socket->Vpp2Level].PowerLevel/10;
1160 powerlevel |= (drt_vpp_levels[ind] << 4);
1161 sockp->drt_vpp2 = socket->Vpp2Level;
1164 #if defined(DRT_DEBUG)
1165 if (drt_debug) {
1166 cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n", powerlevel, ind);
1168 #endif
1169 mutex_enter(&drt->pc_lock); /* protect the registers */
1171 /* make sure not still in RESET */
1172 value = drt->pc_csr->socket[sock].ctl0;
1173 drt->pc_csr->socket[sock].ctl0 = value & ~DRCTL_RESET;
1175 * ctlind processing -- we can ignore this
1176 * there aren't any outputs on the chip for this
1177 * the GUI will display what it thinks is correct
1181 /* handle event mask */
1182 sockp->drt_intmask = socket->SCIntMask;
1183 value = (drt->pc_csr->socket[sock].ctl0 & ~DRT_CHANGE_MASK) |
1184 DRT_CHANGE_DEFAULT; /* always want CD */
1186 if (socket->SCIntMask & SBM_CD)
1187 value |= DRCTL_CDIE;
1188 if (socket->SCIntMask & SBM_BVD1)
1189 value |= DRCTL_BVD1IE;
1190 if (socket->SCIntMask & SBM_BVD2)
1191 value |= DRCTL_BVD2IE;
1192 if (socket->SCIntMask & SBM_WP)
1193 value |= DRCTL_WPIE;
1194 if (socket->SCIntMask & SBM_RDYBSY)
1195 value |= DRCTL_RDYIE;
1196 /* irq processing */
1197 if (socket->IFType == IF_IO) {
1198 /* IRQ only for I/O */
1199 irq = socket->IREQRouting & 0xF;
1200 if (socket->IREQRouting & IRQ_ENABLE) {
1201 irq = DRCTL_IOIE;
1202 #if 0
1203 if (socket->IREQRouting & IRQ_PRIORITY) {
1204 irq |= DRCTL_IOILVL_SB1;
1205 sockp->drt_flags |= DRT_INTR_HIPRI;
1206 } else {
1207 irq |= DRCTL_IOILVL_SB0;
1209 #else
1210 irq |= DRCTL_IOILVL_SB1;
1211 sockp->drt_flags |= DRT_INTR_HIPRI;
1212 #endif
1213 sockp->drt_flags |= DRT_INTR_ENABLED;
1214 } else {
1215 irq = 0; /* no interrupts */
1216 sockp->drt_flags &= ~(DRT_INTR_ENABLED|DRT_INTR_HIPRI);
1218 sockp->drt_irq = socket->IREQRouting;
1220 #if defined(DRT_DEBUG)
1221 if (drt_debug) {
1222 cmn_err(CE_CONT,
1223 "\tsocket type is I/O and irq %x is %s\n", irq,
1224 (socket->IREQRouting & IRQ_ENABLE) ?
1225 "enabled" : "not enabled");
1227 #endif
1228 sockp->drt_flags |= DRT_SOCKET_IO;
1229 if (drt->pc_flags & PCF_AUDIO)
1230 value |= DRCTL_IFTYPE_IO | irq | DRCTL_SPKREN;
1231 else
1232 value |= DRCTL_IFTYPE_IO | irq;
1233 } else {
1234 /* enforce memory mode */
1235 value &= ~(DRCTL_IFTYPE_IO | DRCTL_SPKREN |
1236 DRCTL_IOILVL_SB1 | DRCTL_IOILVL_SB0 |
1237 DRCTL_IOIE);
1238 sockp->drt_flags &= ~(DRT_INTR_ENABLED|DRT_SOCKET_IO);
1240 drt->pc_csr->socket[sock].ctl0 = (ushort_t)value;
1243 * set power to socket
1244 * note that the powerlevel was calculated earlier
1247 drt->pc_csr->socket[sock].ctl1 = (ushort_t)powerlevel;
1248 #if defined(DRT_DEBUG)
1249 if (drt_debug) {
1250 cmn_err(CE_CONT,
1251 "\tpowerlevel (socket->ctl1) = %x\n", powerlevel);
1252 if (drt_debug > 1)
1253 drt_dmp_regs(&drt->pc_csr->socket[sock]);
1255 #endif
1256 sockp->drt_state &= ~socket->State;
1257 mutex_exit(&drt->pc_lock);
1258 return (SUCCESS);
1262 * drt_inquire_socket()
1263 * SocketServices InquireSocket function
1264 * returns basic characteristics of the socket
1266 static int
1267 drt_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
1269 int value;
1270 drt_dev_t *drt = drt_get_driver_private(dip);
1272 socket->SCIntCaps = DRT_DEFAULT_INT_CAPS;
1273 socket->SCRptCaps = DRT_DEFAULT_RPT_CAPS;
1274 socket->CtlIndCaps = DRT_DEFAULT_CTL_CAPS;
1275 value = drt->pc_sockets[socket->socket].drt_flags;
1276 socket->SocketCaps = IF_IO | IF_MEMORY;
1277 socket->ActiveHigh = 3; /* 0 and 1 */
1278 socket->ActiveLow = 0;
1280 #ifdef lint
1281 if (value > 0)
1282 panic("lint panic");
1283 #endif
1285 return (SUCCESS);
1289 * drt_inquire_window()
1290 * SocketServices InquireWindow function
1291 * returns detailed characteristics of the window
1292 * this is where windows get tied to sockets
1294 static int
1295 drt_inquire_window(dev_info_t *dip, inquire_window_t *window)
1297 int socket, win;
1298 drt_dev_t *drt = drt_get_driver_private(dip);
1299 struct drt_window *winp;
1300 iowin_char_t *io;
1301 mem_win_char_t *mem;
1303 #if defined(DRT_DEBUG)
1304 if (drt_debug)
1305 cmn_err(CE_CONT,
1306 "drt_inquire_window: win=%d\n", window->window);
1307 #endif
1308 window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT|WC_IO;
1310 /* get correct socket */
1311 socket = window->window / DRWINDOWS;
1312 win = window->window % DRWINDOWS;
1313 winp = &drt->pc_sockets[socket].drt_windows[win];
1314 /* initialize the socket map - one socket per window */
1315 PR_ZERO(window->Sockets);
1316 PR_SET(window->Sockets, socket);
1318 io = &window->iowin_char;
1319 io->IOWndCaps = WC_CALIGN|WC_IO_RANGE_PER_WINDOW|WC_WENABLE|
1320 WC_8BIT|WC_16BIT|WC_SIZE;
1321 io->FirstByte = (baseaddr_t)winp->drtw_base;
1322 io->LastByte = (baseaddr_t)winp->drtw_base + DRWINSIZE;
1323 io->MinSize = 1;
1324 io->MaxSize = DRWINSIZE;
1325 io->ReqGran = ddi_ptob(dip, 1);
1326 io->AddrLines = DRADDRLINES;
1327 io->EISASlot = 0;
1329 mem = &window->mem_win_char;
1330 mem->MemWndCaps = WC_CALIGN|WC_WENABLE|WC_8BIT|WC_16BIT;
1331 mem->FirstByte = (baseaddr_t)winp->drtw_base;
1332 mem->LastByte = (baseaddr_t)winp->drtw_base + DRWINSIZE;
1333 #if defined(DRT_DEBUG)
1334 if (drt_debug) {
1335 cmn_err(CE_CONT, "\tFirstByte=%p, LastByte=%p\n",
1336 (void *)mem->FirstByte, (void *)mem->LastByte);
1338 #endif
1339 mem->MinSize = DRWINSIZE;
1340 mem->MaxSize = DRWINSIZE;
1341 mem->ReqGran = ddi_ptob(dip, 1L);
1342 mem->ReqBase = 0;
1343 mem->ReqOffset = DRWINSIZE;
1344 mem->Slowest = MEM_SPEED_MAX;
1345 mem->Fastest = MEM_SPEED_MIN;
1347 return (SUCCESS);
1351 * drt_get_adapter()
1352 * SocketServices GetAdapter function
1353 * this is nearly a no-op.
1355 static int
1356 drt_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
1358 drt_dev_t *drt = drt_get_driver_private(dip);
1360 if (drt->pc_flags & PCF_INTRENAB)
1361 adapt->SCRouting = IRQ_ENABLE;
1362 adapt->state = 0;
1363 return (SUCCESS);
1367 * drt_get_page()
1368 * SocketServices GetPage function
1369 * returns info about the window
1371 static int
1372 drt_get_page(dev_info_t *dip, get_page_t *page)
1374 int socket, window;
1375 drt_dev_t *drt = drt_get_driver_private(dip);
1376 struct drt_window *winp;
1378 window = page->window % DRWINDOWS;
1379 socket = page->window / DRWINDOWS;
1381 winp = &drt->pc_sockets[socket].drt_windows[window];
1383 if (page->page > 0)
1384 return (BAD_PAGE);
1386 page->state = 0;
1388 if (winp->drtw_flags & DRW_IO)
1389 page->state |= PS_IO;
1391 if (winp->drtw_flags & DRW_ENABLED)
1392 page->state |= PS_ENABLED;
1394 if (winp->drtw_flags & DRW_ATTRIBUTE)
1395 page->state |= PS_ATTRIBUTE;
1397 page->offset = (off_t)winp->drtw_addr;
1399 return (SUCCESS);
1403 * drt_get_socket()
1404 * SocketServices GetSocket
1405 * returns information about the current socket settings
1407 static int
1408 drt_get_socket(dev_info_t *dip, get_socket_t *socket)
1410 int socknum, irq_enabled;
1411 drt_socket_t *sockp;
1412 drt_dev_t *drt = drt_get_driver_private(dip);
1414 socknum = socket->socket;
1415 sockp = &drt->pc_sockets[socknum];
1417 socket->SCIntMask = sockp->drt_intmask;
1418 socket->state = sockp->drt_state;
1419 socket->VccLevel = sockp->drt_vcc;
1420 socket->Vpp1Level = sockp->drt_vpp1;
1421 socket->Vpp2Level = sockp->drt_vpp2;
1422 socket->CtlInd = 0; /* no indicators */
1423 irq_enabled = (sockp->drt_flags & DRT_INTR_ENABLED) ? IRQ_ENABLE : 0;
1424 #if 0
1425 irq_enabled |= (sockp->drt_flags & DRT_INTR_HIPRI) ? IRQ_HIGH : 0;
1426 #endif
1427 socket->IRQRouting = sockp->drt_irq | irq_enabled;
1428 socket->IFType = (sockp->drt_flags & DRT_SOCKET_IO) ? IF_IO : IF_MEMORY;
1429 return (SUCCESS);
1433 * drt_get_status()
1434 * SocketServices GetStatus
1435 * returns status information about the PC Card in
1436 * the selected socket
1438 static int
1439 drt_get_status(dev_info_t *dip, get_ss_status_t *status)
1441 int socknum, irq_enabled;
1442 drt_socket_t *sockp;
1443 drt_dev_t *drt = drt_get_driver_private(dip);
1444 #if defined(DRT_DEBUG)
1445 if (drt_debug) {
1446 cmn_err(CE_CONT, "drt_get_status: drt=%p\n", (void *)drt);
1448 #endif
1450 if (drt == NULL) {
1451 return (BAD_ADAPTER);
1454 socknum = status->socket;
1455 sockp = &drt->pc_sockets[socknum];
1457 status->CardState = drt_card_state(drt, socknum);
1458 status->SocketState = sockp->drt_state;
1459 status->CtlInd = 0; /* no indicators */
1460 irq_enabled = (sockp->drt_flags & DRT_INTR_ENABLED) ? IRQ_ENABLE : 0;
1461 status->IRQRouting = sockp->drt_irq | irq_enabled;
1462 status->IFType = (sockp->drt_flags & DRT_SOCKET_IO) ?
1463 IF_IO : IF_MEMORY;
1464 return (SUCCESS);
1468 * drt_get_window()
1469 * SocketServices GetWindow function
1470 * returns state information about the specified window
1472 static int
1473 drt_get_window(dev_info_t *dip, get_window_t *window)
1475 int socket, win;
1476 drt_socket_t *sockp;
1477 drt_dev_t *drt = drt_get_driver_private(dip);
1478 struct drt_window *winp;
1480 if (window->window >= DRT_NUMWINDOWS) {
1481 #if defined(DRT_DEBUG)
1482 if (drt_debug)
1483 cmn_err(CE_CONT, "drt_get_window: failed\n");
1484 #endif
1485 return (BAD_WINDOW);
1487 socket = window->window / DRWINDOWS;
1488 win = window->window % DRWINDOWS;
1489 window->socket = socket;
1490 sockp = &drt->pc_sockets[socket];
1491 winp = &sockp->drt_windows[win];
1493 window->size = winp->drtw_len;
1494 window->speed = winp->drtw_speed;
1495 window->base = (uint32_t)(uintptr_t)winp->drtw_reqaddr;
1496 window->handle = winp->drtw_handle;
1497 window->state = 0;
1499 if (winp->drtw_flags & DRW_IO)
1500 window->state |= WS_IO;
1502 if (winp->drtw_flags & DRW_ENABLED)
1503 window->state |= WS_ENABLED;
1504 #if defined(DRT_DEBUG)
1505 if (drt_debug) {
1506 cmn_err(CE_CONT,
1507 "drt_get_window: socket=%d, window=%d\n", socket, win);
1508 cmn_err(CE_CONT,
1509 "\tsize=%d, speed=%d, base=%x, state=%x\n",
1510 window->size, (int)window->speed,
1511 (int)window->base,
1512 window->state);
1514 #endif
1516 return (SUCCESS);
1520 * drt_ll_reset - This function handles the socket RESET signal timing and
1521 * control.
1523 * There are two variables that control the RESET timing:
1524 * drt_prereset_time - time in mS before asserting RESET
1525 * drt_reset_time - time in mS to assert RESET
1527 * XXX - need to rethink RESET timing delays to avoid using drv_usecwait
1529 int drt_prereset_time = 1;
1530 int drt_reset_time = 5;
1532 static void
1533 drt_ll_reset(drt_dev_t *drt, int socket)
1535 uint32_t value;
1537 value = drt->pc_csr->socket[socket].ctl0;
1539 if (drt_prereset_time > 0)
1540 drv_usecwait(drt_prereset_time * 1000);
1542 /* turn reset on then off again */
1543 drt->pc_csr->socket[socket].ctl0 = value | DRCTL_RESET;
1545 if (drt_reset_time > 0)
1546 drv_usecwait(drt_reset_time * 1000);
1548 drt->pc_csr->socket[socket].ctl0 = value & ~DRCTL_RESET;
1550 #if defined(DRT_DEBUG)
1551 if (drt_debug)
1552 cmn_err(CE_CONT, "drt_ll_reset: socket=%d, ctl0=%x, ctl1=%x\n",
1553 socket,
1554 drt->pc_csr->socket[socket].ctl0,
1555 drt->pc_csr->socket[socket].ctl1);
1556 #endif
1560 * drt_new_card()
1561 * put socket into known state on card insertion
1563 static void
1564 drt_new_card(drt_dev_t *drt, int socket)
1566 drt->pc_csr->socket[socket].ctl0 = 0; /* off */
1567 drt->pc_csr->socket[socket].ctl0 = DRT_CHANGE_DEFAULT; /* on */
1568 drt->pc_csr->socket[socket].ctl1 = 0;
1569 drt->pc_sockets[socket].drt_state = 0;
1570 drt->pc_sockets[socket].drt_flags = 0;
1574 * drt_reset_socket()
1575 * SocketServices ResetSocket function
1576 * puts the PC Card in the socket into the RESET state
1577 * and then takes it out after the the cycle time
1578 * The socket is back to initial state when done
1580 static int
1581 drt_reset_socket(dev_info_t *dip, int socket, int mode)
1583 drt_dev_t *drt = drt_get_driver_private(dip);
1584 int window;
1585 drt_socket_t *sockp;
1587 mutex_enter(&drt->pc_lock); /* protect the registers */
1589 drt_ll_reset(drt, socket);
1591 if (mode == RESET_MODE_FULL) {
1592 /* need to unmap windows, etc. */
1594 drt->pc_sockets[socket].drt_state = 0;
1596 for (window = 0, sockp = &drt->pc_sockets[socket];
1597 window < DRT_NUMWINDOWS; window++) {
1598 sockp->drt_windows[window].drtw_flags &= ~DRW_ENABLED;
1602 mutex_exit(&drt->pc_lock);
1603 return (SUCCESS);
1607 * drt_set_interrupt()
1608 * SocketServices SetInterrupt function
1610 static int
1611 drt_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
1613 inthandler_t *intr;
1614 drt_dev_t *drt = drt_get_driver_private(dip);
1616 #if defined(DRT_DEBUG)
1617 if (drt_debug)
1618 cmn_err(CE_CONT, "drt_set_interrupt(%p, %p) pc_handlers=%p\n",
1619 (void *)dip, (void *)handler, (void *)drt->pc_handlers);
1620 #endif
1622 intr = (inthandler_t *)kmem_zalloc(sizeof (inthandler_t),
1623 KM_NOSLEEP);
1624 if (intr == NULL) {
1625 return (BAD_IRQ);
1628 intr->intr = (uint32_t (*)())handler->handler;
1629 intr->handler_id = handler->handler_id;
1630 intr->arg1 = handler->arg1;
1631 intr->arg2 = handler->arg2;
1632 intr->socket = handler->socket;
1633 intr->irq = handler->irq;
1634 mutex_enter(&drt->pc_intr);
1635 mutex_enter(&drt->pc_lock); /* protect the registers and structures */
1637 if (drt->pc_handlers == NULL) {
1638 drt->pc_handlers = intr;
1639 intr->next = intr;
1640 intr->prev = intr;
1641 } else {
1642 insque(intr, drt->pc_handlers);
1645 /* interrupt handlers for both interrupts already done in attach */
1648 * need to fill in cookies in event of multiple high priority
1649 * interrupt handlers on same IRQ
1651 intr->iblk_cookie = drt->pc_icookie_hi;
1652 intr->idev_cookie = drt->pc_dcookie_hi;
1653 mutex_exit(&drt->pc_lock);
1654 mutex_exit(&drt->pc_intr);
1656 handler->iblk_cookie = &intr->iblk_cookie;
1657 handler->idev_cookie = &intr->idev_cookie;
1659 return (SUCCESS);
1663 * drt_clear_interrupt()
1664 * SocketServices ClearInterrupt function
1665 * "What controls the socket interrupt?"
1667 static int
1668 drt_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
1670 int i = 0;
1671 drt_dev_t *drt = drt_get_driver_private(dip);
1672 inthandler_t *intr, *done;
1674 #if defined(DRT_DEBUG)
1675 if (drt_debug)
1676 cmn_err(CE_CONT, "drt_clear_interrupt(%p, %p) "
1677 "pc_handlers = %p\n",
1678 (void *)dip, (void *)handler, (void *)drt->pc_handlers);
1679 #endif
1681 mutex_enter(&drt->pc_lock); /* protect the registers */
1683 for (intr = drt->pc_handlers, done = drt->pc_handlers;
1684 done != NULL; /* empty */) {
1686 if (intr->handler_id == handler->handler_id) {
1687 /* Check if there is only one handler left */
1688 if ((intr->next == intr) && (intr->prev == intr)) {
1689 drt->pc_handlers = NULL;
1690 } else {
1691 if (drt->pc_handlers == intr) {
1692 drt->pc_handlers = intr->next;
1694 remque(intr);
1696 kmem_free((caddr_t)intr, sizeof (inthandler_t));
1697 break;
1699 intr = intr->next;
1700 if (intr == done)
1701 done = NULL;
1704 mutex_exit(&drt->pc_lock);
1706 #ifdef lint
1707 if (i > 0)
1708 panic("lint panic");
1709 #endif
1711 return (SUCCESS);
1714 static void
1715 drt_stop_intr(drt_dev_t *drt, int socket)
1717 inthandler_t *intr;
1718 int done;
1720 mutex_enter(&drt->pc_intr);
1721 for (intr = drt->pc_handlers, done = 0; !done && intr != NULL;
1722 intr = intr->next) {
1723 if (socket == intr->socket) {
1724 intr->socket |= 0x8000; /* make an illegal socket */
1726 if (intr->next == drt->pc_handlers)
1727 done++;
1729 mutex_exit(&drt->pc_intr);
1732 /*ARGSUSED*/
1734 drt_do_intr(drt_dev_t *drt, int socket, int priority)
1736 inthandler_t *intr, *done;
1737 int result = 0;
1739 mutex_enter(&drt->pc_intr);
1741 #if defined(DRT_DEBUG)
1742 if (drt_debug > 2)
1743 cmn_err(CE_CONT, "drt_do_intr(%p, %d, %d)\n",
1744 (void *)drt, socket, priority);
1745 #endif
1748 * If we're suspended, then we don't need to process
1749 * any more interrupts. We have already (or will
1750 * shortly) be disabling all interrupts on the
1751 * adapter, but we still need to ACK any that
1752 * we receive and that the adapter has generated.
1753 * XXX - do we really want to do this here, or does it
1754 * make more sense to let the clients receive any
1755 * interrupts even as we're in the process of
1756 * suspending?
1758 if (drt->pc_flags & PCF_SUSPENDED) {
1759 mutex_exit(&drt->pc_intr);
1760 return (DDI_INTR_CLAIMED);
1763 #if defined(DRT_DEBUG)
1764 if (drt_debug && drt->pc_handlers == NULL)
1765 cmn_err(CE_CONT, "drt_do_intr: pc_handlers == NULL\n");
1766 #endif
1767 for (intr = drt->pc_handlers, done = drt->pc_handlers;
1768 done != NULL && intr != NULL; intr = intr->next) {
1769 #if defined(DRT_DEBUG)
1770 if (drt_debug > 2)
1771 cmn_err(CE_CONT,
1772 "\tintr-> socket=%d, priority=%d, intr=%p,"
1773 "arg1=%p arg2=%p (drt_flags=%x:%s)\n",
1774 intr->socket, intr->priority,
1775 (void *)intr->intr, intr->arg1, intr->arg2,
1776 drt->pc_sockets[socket].drt_flags,
1777 (drt->pc_sockets[socket].drt_flags &
1778 DRT_INTR_ENABLED) ?
1779 "true":"false");
1780 #endif
1781 #if 0
1782 /* may need to rethink the priority stuff */
1783 if (socket == intr->socket &&
1784 (priority ^ (intr->priority < 10)) &&
1785 drt->pc_sockets[socket].drt_flags & DRT_INTR_ENABLED) {
1786 result |= (*intr->intr)(intr->arg);
1788 #else
1789 result |= (*intr->intr)(intr->arg1, intr->arg2);
1790 #endif
1791 if (done == intr->next)
1792 done = NULL;
1794 /* do a round robin adjust */
1795 if (drt->pc_handlers != NULL)
1796 drt->pc_handlers = drt->pc_handlers->next;
1797 mutex_exit(&drt->pc_intr);
1798 return (result);
1801 uint32_t
1802 drt_hi_intr(caddr_t arg)
1804 drt_dev_t *drt = drt_get_driver_private((dev_info_t *)arg);
1805 int i, intr_sockets = 0;
1806 int result, changes;
1808 mutex_enter(&drt->pc_lock);
1810 #if defined(DRT_DEBUG)
1811 if (drt_debug)
1812 cmn_err(CE_CONT, "drt_hi_intr: entered\n");
1813 #endif
1816 * need to change to only ACK and touch the slot that
1817 * actually caused the interrupt. Currently everything
1818 * is acked
1820 * we need to look at all known sockets to determine
1821 * what might have happened, so step through the list
1822 * of them
1824 result = 0;
1826 for (i = 0; i < DRSOCKETS; i++) {
1827 int card_type;
1828 int x = drt->pc_cb_arg;
1829 drt_socket_t *sockp;
1831 sockp = &drt->pc_sockets[i];
1833 if (drt->pc_csr->socket[i].ctl0 & DRCTL_IFTYPE)
1834 card_type = IF_IO;
1835 else
1836 card_type = IF_MEMORY;
1838 changes = drt->pc_csr->socket[i].stat0;
1839 #if defined(DRT_DEBUG)
1840 if (drt_debug)
1841 cmn_err(CE_CONT, "\tstat0=%x, type=%s\n",
1842 changes, card_type == IF_IO ? "IO":"MEM");
1843 #endif
1844 /* ack the interrupts we see */
1845 drt->pc_csr->socket[i].stat0 = (ushort_t)changes;
1847 if (changes & DRSTAT_SCINT) {
1848 #if defined(DRT_DEBUG)
1849 if (drt_debug)
1850 cmn_err(CE_CONT,
1851 "\tcard status change interrupt"
1852 " on socket %d\n", i);
1853 #endif
1855 * We set the result here mainly for IF_MEMORY cases.
1856 * The drt_do_intr() call at the end of this for loop
1857 * will not be called for IF_MEMORY cases since
1858 * intr_sockets are set ONLY for IF_IO cases.
1860 result |= DDI_INTR_CLAIMED;
1862 /* there was a valid interrupt on status change */
1863 if (drt->pc_callback == NULL) {
1864 /* nothing to do */
1865 continue;
1867 if (changes & DRSTAT_CDCHG) {
1868 if ((sockp->drt_flags &
1869 DRT_CARD_PRESENT) &&
1870 (changes & DRSTAT_CD_MASK) !=
1871 DRSTAT_PRESENT_OK) {
1872 sockp->drt_flags &=
1873 ~DRT_CARD_PRESENT;
1875 * stop interrupt handler
1876 * then do the callback
1878 drt_stop_intr(drt, i);
1880 * XXX - note that drt_new_card will
1881 * clear sockp->drt_flags
1883 drt_new_card(drt, i); /* paranoia */
1884 PC_CALLBACK(drt, arg, x,
1885 PCE_CARD_REMOVAL, i);
1886 continue;
1887 } else {
1888 if ((changes & DRSTAT_CD_MASK) ==
1889 DRSTAT_PRESENT_OK &&
1890 !(sockp->drt_flags &
1891 DRT_CARD_PRESENT)) {
1892 drt_new_card(drt, i);
1893 drt_ll_reset(drt, i);
1894 sockp->drt_state |= SBM_CD;
1895 drt_socket_card_id(drt,
1896 sockp,
1897 changes);
1898 PC_CALLBACK(drt, arg, x,
1899 PCE_CARD_INSERT,
1901 continue;
1905 * since other events may be the result of
1906 * "bounce", don't check them on this pass.
1907 * The insert code will check them anyway.
1909 continue;
1912 /* Ready/Change Detect */
1913 #if defined(DRT_DEBUG)
1914 if (drt_debug && changes & DRSTAT_RDYCHG)
1915 cmn_err(CE_CONT, "\trdychg: stat=%x, type=%s\n",
1916 changes,
1917 card_type == IF_MEMORY ?
1918 "memory" : "I/O");
1919 #endif
1920 if (card_type == IF_MEMORY &&
1921 changes & DRSTAT_RDYCHG &&
1922 changes & DRSTAT_RDYST) {
1923 sockp->drt_state |= SBM_RDYBSY;
1924 PC_CALLBACK(drt, arg, x, PCE_CARD_READY, i);
1927 /* write protect switch moved */
1928 if (card_type == IF_MEMORY && changes & DRSTAT_WPCHG) {
1929 if (changes & DRSTAT_WPST)
1930 sockp->drt_state |= SBM_WP;
1931 else
1932 sockp->drt_state &= ~SBM_WP;
1933 PC_CALLBACK(drt, arg, x,
1934 PCE_CARD_WRITE_PROTECT, i);
1937 if (card_type == IF_MEMORY &&
1938 changes & DRSTAT_BVDCHG) {
1940 * there was a change in battery state.
1941 * this could be a false alarm at
1942 * card insertion but could be real.
1943 * The individual change bits aren't
1944 * meaningful so look at the live
1945 * status and latch that
1947 switch (changes & DRSTAT_BVDST) {
1948 case DRSTAT_BATT_LOW:
1949 if (!(sockp->drt_flags &
1950 DRT_BATTERY_LOW)) {
1951 sockp->drt_flags |=
1952 DRT_BATTERY_LOW;
1953 sockp->drt_state |= SBM_BVD2;
1954 sockp->drt_state &= ~SBM_BVD1;
1955 PC_CALLBACK(drt, arg, x,
1956 PCE_CARD_BATTERY_WARN,
1959 break;
1960 case DRSTAT_BATT_OK:
1961 sockp->drt_state &=
1962 ~(DRT_BATTERY_LOW|
1963 DRT_BATTERY_DEAD);
1964 sockp->drt_state &=
1965 ~(SBM_BVD1|SBM_BVD2);
1966 break;
1967 default: /* battery failed */
1968 if (!(sockp->drt_flags &
1969 DRT_BATTERY_DEAD)) {
1970 /* so we only see one of them */
1971 sockp->drt_flags |=
1972 DRT_BATTERY_DEAD;
1973 sockp->drt_flags &=
1974 DRT_BATTERY_LOW;
1975 sockp->drt_state |= SBM_BVD1;
1976 PC_CALLBACK(drt, arg, x,
1977 PCE_CARD_BATTERY_DEAD,
1982 if (card_type == IF_IO &&
1983 !(changes & DRSTAT_BVD1ST)) {
1985 * Disable status change interrupts. We
1986 * will enable them again later after
1987 * Card Services has processed this
1988 * event.
1990 drt->pc_csr->socket[i].ctl0 &=
1991 ~DRCTL_BVD1IE;
1993 /* we have an I/O status change */
1994 PC_CALLBACK(drt, arg, x,
1995 PCE_CARD_STATUS_CHANGE,
1998 #if 0
2000 * need to reexamine this section to see what really
2001 * needs to be done
2003 /* Battery Warn Detect */
2004 if (changes & DRSTAT_BVD2CHG) {
2005 if (card_type == IF_MEMORY &&
2006 !(sockp->drt_flags & DRT_BATTERY_LOW)) {
2007 sockp->drt_flags |= DRT_BATTERY_LOW;
2008 sockp->drt_state |= SBM_BVD2;
2009 PC_CALLBACK(drt, arg, x,
2010 PCE_CARD_BATTERY_WARN,
2012 } else if (card_type == IF_IO) {
2013 PC_CALLBACK(drt, arg, x,
2014 PCE_CARD_STATUS_CHANGE,
2019 /* Battery Fail Detect */
2020 if (card_type == IF_MEMORY &&
2021 changes & DRSTAT_BVD1CHG &&
2022 !(sockp->drt_flags & DRT_BATTERY_DEAD)) {
2023 /* so we only see one of them */
2024 sockp->drt_flags |= DRT_BATTERY_DEAD;
2025 sockp->drt_state |= SBM_BVD1;
2026 PC_CALLBACK(drt, arg, x,
2027 PCE_CARD_BATTERY_DEAD, i);
2029 #endif
2031 /* now flag any PC Card interrupts */
2032 if (card_type == IF_IO && changes & DRSTAT_IOINT) {
2033 intr_sockets |= 1 << i;
2035 #if defined(DRT_DEBUG)
2036 if (drt_debug)
2037 cmn_err(CE_CONT, "\tsocket %d: ctl0=%x, ctl1=%x\n",
2039 drt->pc_csr->socket[i].ctl0,
2040 drt->pc_csr->socket[i].ctl1);
2041 #endif
2044 mutex_exit(&drt->pc_lock);
2046 for (i = 0; i < DRSOCKETS; i++) {
2047 if (intr_sockets & (1 << i))
2048 result |= drt_do_intr(drt, i, 1);
2051 if (changes & DRSTAT_SCINT || result || intr_sockets)
2052 return (DDI_INTR_CLAIMED);
2053 if (drt->pc_flags & PCF_ATTACHING) {
2054 drt->pc_flags &= ~PCF_ATTACHING;
2055 return (DDI_INTR_CLAIMED);
2058 return (DDI_INTR_UNCLAIMED);
2061 uint32_t
2062 drt_lo_intr(caddr_t arg)
2064 drt_dev_t *drt = drt_get_driver_private((dev_info_t *)arg);
2065 int i, result;
2067 #if defined(DRT_DEBUG)
2068 if (drt_debug)
2069 cmn_err(CE_CONT, "drt_lo_intr(%p)\n", (void *)arg);
2070 #endif
2072 * we need to look at all known sockets to determine
2073 * what might have happened, so step through the list
2074 * of them
2077 /* XXX is this the lost interrupt problem?? XXX */
2078 for (i = 0, result = 0; i < drt->pc_numsockets; i++) {
2079 if (drt->pc_csr->socket[i].stat0 & DRSTAT_IOINT) {
2080 #if defined(DRT_DEBUG)
2081 if (drt_debug)
2082 cmn_err(CE_CONT, "\tsocket=%x, stat0=%x\n",
2083 i, drt->pc_csr->socket[i].stat0);
2084 #endif
2085 result |= drt_do_intr(drt, i, 0);
2086 drt->pc_csr->socket[i].stat0 |= DRSTAT_IOINT;
2089 if (result)
2090 return (DDI_INTR_CLAIMED);
2091 return (DDI_INTR_UNCLAIMED);
2095 * drt_socket_card_id()
2096 * figure out current status of card in socket
2097 * this is used to prevent callbacks at card insertion
2099 /* ARGSUSED */
2100 void
2101 drt_socket_card_id(drt_dev_t *drt, drt_socket_t *socket, int status)
2104 /* need to record if a card is present to init state */
2105 if ((status & DRSTAT_CD_MASK) == DRSTAT_PRESENT_OK)
2106 socket->drt_flags |= DRT_CARD_PRESENT;
2108 /* check battery state to avoid callbacks */
2109 switch (status & DRSTAT_BVDST) {
2110 case DRSTAT_BATT_LOW:
2111 socket->drt_flags |= DRT_BATTERY_LOW;
2112 socket->drt_flags &= ~DRT_BATTERY_DEAD;
2113 socket->drt_state |= SBM_BVD2;
2114 socket->drt_state &= ~SBM_BVD1;
2115 break;
2116 case DRSTAT_BATT_OK:
2117 socket->drt_flags &= ~(DRT_BATTERY_LOW|DRT_BATTERY_DEAD);
2118 socket->drt_state &= ~(SBM_BVD1|SBM_BVD2);
2119 break;
2120 default:
2121 /* battery dead */
2122 socket->drt_flags |= DRT_BATTERY_DEAD;
2123 socket->drt_state |= SBM_BVD1;
2124 break;
2127 /* check write protect status */
2128 if (status & DRSTAT_WPST)
2129 socket->drt_state |= SBM_WP;
2130 else
2131 socket->drt_state &= ~SBM_WP;
2133 /* and ready/busy */
2134 if (status & DRSTAT_RDYST)
2135 socket->drt_state |= SBM_RDYBSY;
2136 else
2137 socket->drt_state &= ~SBM_RDYBSY;
2140 #if defined(DRT_DEBUG)
2141 static void
2142 drt_dmp_regs(stp4020_socket_csr_t *csrp)
2144 int i;
2146 cmn_err(CE_CONT, "drt_dmp_regs (%p):\n", (void *)csrp);
2147 cmn_err(CE_CONT, "\tctl0: %b\n", csrp->ctl0,
2148 "\020\1IFTYPE\2SFTRST\3SPKREN\4IOILVL\5IOIE\6RSVD"
2149 "\7CTOIE\010WPIE\011RDYIE\012BVD1IE\013BVD2IE\014CDIE"
2150 "\015SCILVL\016PROMEN\017RSVDX");
2151 cmn_err(CE_CONT,
2152 "\tctl1: %b\n", csrp->ctl1,
2153 "\020\1PCIFOE\1MSTPWR\7APWREN"
2154 "\10RSVD\11DIAGEN\12WAITDB\13WPDB\14RDYDB\15BVD1DB\16BVD2DB"
2155 "\17CD1DB\20LPBKEN");
2156 cmn_err(CE_CONT,
2157 "\tstat0: %b\n", csrp->stat0,
2158 "\020\1PWRON\2WAITST\3WPST"
2159 "\4RDYST\5BVD1ST\6BVD2ST\7CD1ST\10CD2ST\11PCTO\12WPCHG"
2160 "\13RDCHG\14BVD1CHG\15BVD2CHG\16CDCHG\17SCINT\20IOINT");
2161 cmn_err(CE_CONT,
2162 "\tstat1: types=%x, rev=%x\n",
2163 (int)(csrp->stat1 & DRSTAT_PCTYS_M),
2164 csrp->stat1 & DRSTAT_REV_M);
2165 for (i = 0; i < 3; i++) {
2166 cmn_err(CE_CONT, "\twin%d:\tctl0: cmdlng=%x, cmddly=%x, "
2167 "aspsel=%x, base=%x\n", i,
2168 GET_DRWIN_CMDLNG(csrp->window[i].ctl0),
2169 GET_DRWIN_CMDDLY(csrp->window[i].ctl0),
2170 csrp->window[i].ctl0 & DRWIN_ASPSEL_M,
2171 GET_DRWIN_BASE(csrp->window[i].ctl0));
2172 cmn_err(CE_CONT, "\t\tctl1: %x\n", csrp->window[i].ctl1);
2176 #endif
2179 * drt_cpr - save/restore the adapter's hardware state
2181 static void
2182 drt_cpr(drt_dev_t *drt, int cmd)
2184 int sn, wn;
2186 switch (cmd) {
2187 case DRT_SAVE_HW_STATE:
2188 for (sn = 0; sn < DRSOCKETS; sn++) {
2189 stp4020_socket_csr_t *drs = &drt->pc_csr->socket[sn];
2190 for (wn = 0; wn < DRWINDOWS; wn++) {
2191 drt->saved_socket[sn].window[wn].ctl0 =
2192 drs->window[wn].ctl0;
2193 drt->saved_socket[sn].window[wn].ctl1 =
2194 drs->window[wn].ctl1;
2196 drt->saved_socket[sn].ctl0 = drs->ctl0;
2197 drt->saved_socket[sn].ctl1 = drs->ctl1;
2199 break;
2200 case DRT_RESTORE_HW_STATE:
2201 for (sn = 0; sn < DRSOCKETS; sn++) {
2202 stp4020_socket_csr_t *drs = &drt->pc_csr->socket[sn];
2203 for (wn = 0; wn < DRWINDOWS; wn++) {
2204 drs->window[wn].ctl0 =
2205 drt->saved_socket[sn].window[wn].ctl0;
2206 drs->window[wn].ctl1 =
2207 drt->saved_socket[sn].window[wn].ctl1;
2210 /* work around for false status bugs */
2211 /* XXX - why 0x3FFF and not 0xFFFF?? */
2212 drs->stat0 = 0x3FFF;
2213 drs->stat1 = 0x3FFF;
2215 drs->ctl0 = drt->saved_socket[sn].ctl0;
2216 drs->ctl1 = drt->saved_socket[sn].ctl1;
2218 break;
2219 } /* switch */
2224 * drt_fixprops(dip)
2225 * if the adapter predates 1275 properties, add them.
2226 * We do this by checking presence of the property
2227 * and adding what we know if properties not present
2229 /* ARGSUSED */
2230 static void
2231 drt_fixprops(dev_info_t *dip)
2235 * note that there are a number of properties that
2236 * should be added here if not present
2245 * stpra_alloc_map()
2246 * allocate an stpramap structure.
2249 struct stpramap *
2250 stpra_alloc_map()
2252 struct stpramap *new;
2253 mutex_enter(&stpra_lock);
2254 new = NULL;
2255 if (stpra_freelist != NULL) {
2256 new = stpra_freelist;
2257 stpra_freelist = new->ra_next;
2259 mutex_exit(&stpra_lock);
2260 if (new == NULL) {
2261 new = (struct stpramap *)kmem_zalloc(sizeof (struct stpramap),
2262 KM_SLEEP);
2263 } else {
2264 bzero((caddr_t)new, sizeof (struct stpramap));
2266 return (new);
2270 * stpra_free_map(map)
2271 * return a used map to the freelist.
2272 * Should probably check to see if above
2273 * some threshold and kmem_free() any excess
2275 void
2276 stpra_free_map(struct stpramap *map)
2278 if (map != NULL) {
2279 mutex_enter(&stpra_lock);
2280 map->ra_next = stpra_freelist;
2281 stpra_freelist = map;
2282 mutex_exit(&stpra_lock);
2288 * stpra_free(map, base, len)
2289 * return the specified range (base to base+len)
2290 * to the specified map
2293 void
2294 stpra_free(struct stpramap **map, uint32_t base, uint32_t len)
2296 struct stpramap *newmap, *oldmap = NULL;
2297 struct stpramap *mapp, *backp;
2298 uint32_t newbase, mapend;
2301 * always allocate a map entry so we can manipulate
2302 * things without blocking inside our lock
2304 newmap = stpra_alloc_map();
2305 ASSERT(newmap);
2307 mutex_enter(&stpra_lock);
2309 mapp = *map;
2310 backp = (struct stpramap *)map;
2312 /* now find where range lies and fix things up */
2313 newbase = base + len;
2314 for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
2315 mapend = mapp->ra_base + mapp->ra_len;
2316 if (mapend == 0) {
2318 * special case: sum is larger than 32bit
2320 mapend = mapp->ra_len;
2322 if (newbase == mapp->ra_base) {
2323 /* simple - on front */
2324 mapp->ra_base = base;
2325 mapp->ra_len += len;
2327 * don't need to check if it merges with
2328 * previous since that would match on on end
2330 break;
2331 } else if (newbase == mapend) {
2332 /* simple - on end */
2333 mapp->ra_len += len;
2334 if (mapp->ra_next && newbase ==
2335 mapp->ra_next->ra_base) {
2336 /* merge with next node */
2337 oldmap = mapp->ra_next;
2338 mapp->ra_len += oldmap->ra_len;
2339 mapp->ra_next = oldmap->ra_next;
2341 break;
2342 } else if (base < mapp->ra_base) {
2343 /* somewhere in between so just an insert */
2344 newmap->ra_base = base;
2345 newmap->ra_len = len;
2346 newmap->ra_next = mapp;
2347 backp->ra_next = newmap;
2348 newmap = NULL;
2349 break;
2351 /* else haven't found the spot yet */
2353 if (mapp == NULL) {
2354 /* special case of running off the end - stick on end */
2355 newmap->ra_base = base;
2356 newmap->ra_len = len;
2357 backp->ra_next = newmap;
2358 newmap = NULL;
2360 mutex_exit(&stpra_lock);
2361 if (newmap != NULL)
2362 stpra_free_map(newmap);
2363 if (oldmap != NULL)
2364 stpra_free_map(oldmap);
2368 * stpra_alloc(map, reqest, return)
2369 * Allocate a memory-like resource (physical memory, I/O space)
2370 * subject to the constraints defined in the request structure.
2374 stpra_alloc(struct stpramap **map, stpra_request_t *req, stpra_return_t *ret)
2376 struct stpramap *mapp, *backp;
2377 struct stpramap *newmap, *old = NULL;
2378 int type = 0, len;
2379 uint32_t mask = 0;
2380 int newlen, rval = DDI_FAILURE;
2381 uint32_t base, lower, upper;
2383 if (req->ra_flags & STP_RA_ALLOC_SPECIFIED)
2384 type = STP_RA_ALLOC_SPECIFIED;
2385 else
2386 type = 0;
2388 if (req->ra_flags & (STP_RA_ALLOC_POW2|STP_RA_ALIGN_SIZE)) {
2389 if (req->ra_len != stpra_fix_pow2(req->ra_len)) {
2390 #if defined(DRT_DEBUG)
2391 if (drt_debug)
2392 cmn_err(CE_WARN, "ra: bad length (pow2) %d\n",
2393 req->ra_len);
2394 #endif
2395 ret->ra_addr_hi = 0;
2396 ret->ra_addr_lo = 0;
2397 ret->ra_len = 0;
2398 return (DDI_FAILURE);
2401 mask = req->ra_align;
2402 if (req->ra_flags & STP_RA_ALIGN_SIZE) {
2403 len = stpra_fix_pow2(req->ra_len);
2404 mask = len - 1;
2405 #if defined(DRT_DEBUG)
2406 if (drt_debug)
2407 cmn_err(CE_CONT, "len=%d, mask=%x\n", len, mask);
2408 #endif
2411 newmap = stpra_alloc_map(); /* just in case */
2413 mutex_enter(&stpra_lock);
2415 mapp = *map;
2416 #if defined(DRT_DEBUG)
2417 if (drt_debug)
2418 cmn_err(CE_CONT, "stpra_alloc: mapp = %p\n",
2419 (void *)mapp);
2420 #endif
2422 backp = (struct stpramap *)map;
2424 len = req->ra_len;
2426 lower = 0;
2427 upper = ~(uint32_t)0;
2431 if (type != STP_RA_ALLOC_SPECIFIED) {
2432 /* first fit - not user specified */
2433 #if defined(DRT_DEBUG)
2434 if (drt_debug)
2435 cmn_err(CE_CONT, "stpra_alloc(unspecified request)"
2436 "lower=%x, upper=%x\n", lower, upper);
2437 #endif
2438 for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
2439 #if defined(DRT_DEBUG)
2440 if (drt_debug)
2441 cmn_err(CE_CONT, "stpra_alloc: ra_len = %x, len = %x",
2442 mapp->ra_len, len);
2443 #endif
2445 if (mapp->ra_len >= len) {
2446 /* a candidate -- apply constraints */
2447 base = mapp->ra_base;
2448 if (base < lower &&
2449 (base + mapp->ra_len) < (lower + len)) {
2450 if (((base + mapp->ra_len) != 0) ||
2451 ((base + mapp->ra_len) >
2452 mapp->ra_len))
2453 /* same as the above case */
2454 continue;
2456 if (base < lower)
2457 base = lower;
2458 #if defined(DRT_DEBUG)
2459 if (drt_debug)
2460 cmn_err(CE_CONT,
2461 "\tbase=%x, ra_base=%x,"
2462 "mask=%x\n",
2463 base, mapp->ra_base, mask);
2464 #endif
2465 if ((mapp->ra_base & mask) != 0) {
2467 * failed a critical constraint
2468 * adjust and see if it still fits
2470 base = mapp->ra_base & ~mask;
2471 base += (mask + 1);
2472 #if defined(DRT_DEBUG)
2473 if (drt_debug)
2474 cmn_err(CE_CONT,
2475 "\tnew base=%x\n",
2476 base);
2477 #endif
2478 if (len > (mapp->ra_len -
2479 (base - mapp->ra_base)))
2480 continue;
2482 /* we have a fit */
2483 #if defined(DRT_DEBUG)
2484 if (drt_debug)
2485 cmn_err(CE_CONT, "\thave a fit\n");
2486 #endif
2487 #ifdef lint
2488 upper = upper; /* need to check upper bound */
2489 #endif
2490 if (base != mapp->ra_base) {
2491 /* in the middle or end */
2492 newlen = base - mapp->ra_base;
2493 if ((mapp->ra_len - newlen) == len) {
2494 /* on the end */
2495 mapp->ra_len = newlen;
2496 } else {
2497 newmap->ra_next = mapp->ra_next;
2498 newmap->ra_base = base + len;
2499 newmap->ra_len = mapp->ra_len -
2500 (len + newlen);
2501 mapp->ra_len = newlen;
2502 mapp->ra_next = newmap;
2503 newmap = NULL;
2506 } else {
2507 /* at the beginning */
2508 mapp->ra_base += len;
2509 mapp->ra_len -= len;
2510 if (mapp->ra_len == 0) {
2511 /* remove the whole node */
2512 backp->ra_next = mapp->ra_next;
2513 old = mapp;
2516 rval = DDI_SUCCESS;
2517 break;
2520 } else {
2521 /* want an exact value/fit */
2522 base = req->ra_addr_lo;
2523 len = req->ra_len;
2524 for (; mapp != NULL; backp = mapp, mapp = mapp->ra_next) {
2525 if (base >= mapp->ra_base &&
2526 base < (mapp->ra_base + mapp->ra_len)) {
2527 /* this is the node */
2528 if ((base + len) >
2529 (mapp->ra_base + mapp->ra_len)) {
2530 /* no match */
2531 base = 0;
2532 } else {
2533 /* this is the one */
2534 if (base == mapp->ra_base) {
2535 /* at the front */
2536 mapp->ra_base += len;
2537 mapp->ra_len -= len;
2538 if (mapp->ra_len == 0) {
2539 /* used it up */
2540 old = mapp;
2541 backp->ra_next =
2542 mapp->ra_next;
2544 } else {
2545 /* on the end or in middle */
2546 if ((base + len) ==
2547 (mapp->ra_base +
2548 mapp->ra_len)) {
2549 /* on end */
2550 mapp->ra_len -= len;
2551 } else {
2552 uint32_t
2553 newbase, newlen;
2554 /* in the middle */
2555 newbase = base + len;
2556 newlen =
2557 (mapp->ra_base +
2558 mapp->ra_len) -
2559 newbase;
2560 newmap->ra_base =
2561 newbase;
2562 newmap->ra_len = newlen;
2563 newmap->ra_next =
2564 mapp->ra_next;
2565 mapp->ra_next = newmap;
2566 mapp->ra_len -=
2567 newlen + len;
2568 newmap = NULL;
2572 rval = DDI_SUCCESS;
2573 break;
2578 mutex_exit(&stpra_lock);
2580 if (old)
2581 stpra_free_map(old);
2582 if (newmap)
2583 stpra_free_map(newmap);
2586 if (rval == DDI_SUCCESS) {
2587 ret->ra_addr_hi = 0;
2588 ret->ra_addr_lo = base;
2589 ret->ra_len = req->ra_len;
2591 return (rval);
2598 * stpra_fix_pow2(value)
2599 * a utility function which rounds up to the
2600 * nearest power of two value.
2603 uint32_t
2604 stpra_fix_pow2(uint32_t value)
2606 int i;
2608 if (ddi_ffs(value) == ddi_fls(value))
2609 return (value);
2610 /* not a power of two so round up */
2611 i = ddi_fls(value);
2612 /* this works since ffs/fls is plus 1 */
2613 #if defined(DRT_DEBUG)
2614 if (drt_debug) {
2615 cmn_err(CE_CONT, "stpra_fix_pow2(%x)->%x:%x\n", value, i,
2616 1 << i);
2617 cmn_err(CE_CONT,
2618 "\tffs=%d, fls=%d\n", ddi_ffs(value), ddi_fls(value));
2620 #endif
2621 return (1 << i);