1/*	$NetBSD: mmeyepcmcia.c,v 1.27 2024/02/13 21:39:02 andvar Exp $	*/
2
3/*
4 * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Marc Horowitz.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 *  PCMCIA I/F for MMEYE
34 *
35 *  T.Horiuichi
36 *  Brains Corp. 1998.8.25
37 */
38
39#include <sys/cdefs.h>
40__KERNEL_RCSID(0, "$NetBSD: mmeyepcmcia.c,v 1.27 2024/02/13 21:39:02 andvar Exp $");
41
42#include <sys/types.h>
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/device.h>
48#include <sys/extent.h>
49#include <sys/kmem.h>
50#include <sys/kthread.h>
51#include <sys/bus.h>
52
53#include <uvm/uvm_extern.h>
54
55#include <machine/autoconf.h>
56#include <machine/intr.h>
57#include <machine/mmeye.h>
58
59#include <dev/pcmcia/pcmciareg.h>
60#include <dev/pcmcia/pcmciavar.h>
61#include <dev/pcmcia/pcmciachip.h>
62
63#include <mmeye/dev/mmeyepcmciareg.h>
64
65#include "locators.h"
66
67#ifdef MMEYEPCMCIADEBUG
68int	mmeyepcmcia_debug = 1;
69#define	DPRINTF(arg) if (mmeyepcmcia_debug) printf arg;
70#else
71#define	DPRINTF(arg)
72#endif
73
74struct mmeyepcmcia_event {
75	SIMPLEQ_ENTRY(mmeyepcmcia_event) pe_q;
76	int pe_type;
77};
78
79/* pe_type */
80#define MMEYEPCMCIA_EVENT_INSERTION	0
81#define MMEYEPCMCIA_EVENT_REMOVAL	1
82
83struct mmeyepcmcia_handle {
84	struct mmeyepcmcia_softc *sc;
85	int	flags;
86	int	laststate;
87	int	memalloc;
88	struct {
89		bus_addr_t		addr;
90		bus_size_t		size;
91		int			kind;
92		bus_space_tag_t		memt;
93		bus_space_handle_t	memh;
94	} mem[MMEYEPCMCIA_MEM_WINS];
95	int	ioalloc;
96	struct {
97		bus_addr_t		addr;
98		bus_size_t		size;
99		int			width;
100		bus_space_tag_t		iot;
101		bus_space_handle_t	ioh;
102	} io[MMEYEPCMCIA_IO_WINS];
103	int	ih_irq;
104	device_t pcmcia;
105
106	int	shutdown;
107	lwp_t	*event_thread;
108	SIMPLEQ_HEAD(, mmeyepcmcia_event) events;
109};
110
111#define	MMEYEPCMCIA_FLAG_CARDP		0x0002
112#define	MMEYEPCMCIA_FLAG_SOCKETP	0x0001
113
114#define MMEYEPCMCIA_LASTSTATE_PRESENT	0x0002
115#define MMEYEPCMCIA_LASTSTATE_HALF	0x0001
116#define MMEYEPCMCIA_LASTSTATE_EMPTY	0x0000
117
118/*
119 * This is sort of arbitrary.  It merely needs to be "enough". It can be
120 * overridden in the conf file, anyway.
121 */
122
123#define	MMEYEPCMCIA_MEM_PAGES	4
124
125#define	MMEYEPCMCIA_NSLOTS	1
126
127#define MMEYEPCMCIA_WINS	5
128#define MMEYEPCMCIA_IOWINS	2
129
130struct mmeyepcmcia_softc {
131	device_t dev;
132
133	bus_space_tag_t iot;		/* mmeyepcmcia registers */
134	bus_space_handle_t ioh;
135	int controller_irq;
136
137	bus_space_tag_t memt;		/* PCMCIA spaces */
138	bus_space_handle_t memh;
139	int card_irq;
140
141	pcmcia_chipset_tag_t pct;
142
143	/* this needs to be large enough to hold PCIC_MEM_PAGES bits */
144	int	subregionmask;
145#define MMEYEPCMCIA_MAX_MEM_PAGES (8 * sizeof(int))
146
147	/*
148	 * used by io/mem window mapping functions.  These can actually overlap
149	 * with another pcic, since the underlying extent mapper will deal
150	 * with individual allocations.  This is here to deal with the fact
151	 * that different busses have different real widths (different pc
152	 * hardware seems to use 10 or 12 bits for the I/O bus).
153	 */
154	bus_addr_t iobase;
155	bus_addr_t iosize;
156
157	struct mmeyepcmcia_handle handle[MMEYEPCMCIA_NSLOTS];
158};
159
160static void	mmeyepcmcia_attach_sockets(struct mmeyepcmcia_softc *);
161static int	mmeyepcmcia_intr(void *arg);
162
163static inline int mmeyepcmcia_read(struct mmeyepcmcia_handle *, int);
164static inline void mmeyepcmcia_write(struct mmeyepcmcia_handle *, int, int);
165
166static int	mmeyepcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
167		    struct pcmcia_mem_handle *);
168static void	mmeyepcmcia_chip_mem_free(pcmcia_chipset_handle_t,
169		    struct pcmcia_mem_handle *);
170static int	mmeyepcmcia_chip_mem_map(pcmcia_chipset_handle_t, int,
171		    bus_addr_t, bus_size_t, struct pcmcia_mem_handle *,
172		    bus_size_t *, int *);
173static void	mmeyepcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int);
174
175static int	mmeyepcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
176		    bus_size_t, bus_size_t, struct pcmcia_io_handle *);
177static void	mmeyepcmcia_chip_io_free(pcmcia_chipset_handle_t,
178		    struct pcmcia_io_handle *);
179static int	mmeyepcmcia_chip_io_map(pcmcia_chipset_handle_t, int,
180		    bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *);
181static void	mmeyepcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int);
182
183static void	mmeyepcmcia_chip_socket_enable(pcmcia_chipset_handle_t);
184static void	mmeyepcmcia_chip_socket_disable(pcmcia_chipset_handle_t);
185static void	mmeyepcmcia_chip_socket_settype(pcmcia_chipset_handle_t, int);
186
187static inline int mmeyepcmcia_read(struct mmeyepcmcia_handle *, int);
188static inline int
189mmeyepcmcia_read(struct mmeyepcmcia_handle *h, int idx)
190{
191	static int prev_idx = 0;
192
193	if (idx == -1){
194		idx = prev_idx;
195	}
196	prev_idx = idx;
197	return bus_space_read_stream_2(h->sc->iot, h->sc->ioh, idx);
198}
199
200static inline void mmeyepcmcia_write(struct mmeyepcmcia_handle *, int, int);
201static inline void
202mmeyepcmcia_write(struct mmeyepcmcia_handle *h, int idx, int data)
203{
204	static int prev_idx;
205	if (idx == -1){
206		idx = prev_idx;
207	}
208	prev_idx = idx;
209	bus_space_write_stream_2(h->sc->iot, h->sc->ioh, idx, (data));
210}
211
212static void	*mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t,
213		    struct pcmcia_function *, int, int (*) (void *), void *);
214static void	mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t,
215		    void *);
216static void	*mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t,
217		    struct pcmcia_function *, int, int (*) (void *), void *);
218static void	mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t,
219		    void *);
220
221static void	mmeyepcmcia_attach_socket(struct mmeyepcmcia_handle *);
222static void	mmeyepcmcia_init_socket(struct mmeyepcmcia_handle *);
223static int	mmeyepcmcia_print (void *, const char *);
224static int	mmeyepcmcia_intr_socket(struct mmeyepcmcia_handle *);
225static void	mmeyepcmcia_attach_card(struct mmeyepcmcia_handle *);
226static void	mmeyepcmcia_detach_card(struct mmeyepcmcia_handle *, int);
227static void	mmeyepcmcia_deactivate_card(struct mmeyepcmcia_handle *);
228static void	mmeyepcmcia_event_thread(void *);
229static void	mmeyepcmcia_queue_event(struct mmeyepcmcia_handle *, int);
230
231static int	mmeyepcmcia_match(device_t, cfdata_t, void *);
232static void	mmeyepcmcia_attach(device_t, device_t, void *);
233
234CFATTACH_DECL_NEW(mmeyepcmcia, sizeof(struct mmeyepcmcia_softc),
235    mmeyepcmcia_match, mmeyepcmcia_attach, NULL, NULL);
236
237static struct pcmcia_chip_functions mmeyepcmcia_functions = {
238	mmeyepcmcia_chip_mem_alloc,
239	mmeyepcmcia_chip_mem_free,
240	mmeyepcmcia_chip_mem_map,
241	mmeyepcmcia_chip_mem_unmap,
242
243	mmeyepcmcia_chip_io_alloc,
244	mmeyepcmcia_chip_io_free,
245	mmeyepcmcia_chip_io_map,
246	mmeyepcmcia_chip_io_unmap,
247
248	mmeyepcmcia_chip_intr_establish,
249	mmeyepcmcia_chip_intr_disestablish,
250
251	mmeyepcmcia_chip_socket_enable,
252	mmeyepcmcia_chip_socket_disable,
253	mmeyepcmcia_chip_socket_settype,
254	NULL,
255};
256
257static int
258mmeyepcmcia_match(device_t parent, cfdata_t match, void *aux)
259{
260	struct mainbus_attach_args *ma = aux;
261
262	if (strcmp(ma->ma_name, match->cf_name) != 0)
263		return 0;
264
265	/* Disallow wildcarded values. */
266	if (ma->ma_addr1 == MAINBUSCF_ADDR1_DEFAULT ||
267	    ma->ma_addr2 == MAINBUSCF_ADDR2_DEFAULT ||
268	    ma->ma_irq2 == MAINBUSCF_IRQ2_DEFAULT)
269		return 0;
270
271	return 1;
272}
273
274static void
275mmeyepcmcia_attach(device_t parent, device_t self, void *aux)
276{
277	struct mainbus_attach_args *ma = aux;
278	struct mmeyepcmcia_softc *sc = device_private(self);
279
280	aprint_naive("\n");
281
282	sc->dev = self;
283	sc->subregionmask = 1;	/* 1999.05.17 T.Horiuchi for R1.4 */
284
285	sc->pct = (pcmcia_chipset_tag_t)&mmeyepcmcia_functions;
286	sc->iot = 0;
287	/* Map i/o space. */
288	if (bus_space_map(sc->iot, ma->ma_addr1, MMEYEPCMCIA_IOSIZE,
289	    0, &sc->ioh)) {
290		aprint_error(": can't map i/o space\n");
291		return;
292	}
293	sc->memt = 0;
294	sc->iobase = ma->ma_addr2;
295	sc->controller_irq = ma->ma_irq1;
296	sc->card_irq = ma->ma_irq2;
297
298	sc->handle[0].sc = sc;
299	sc->handle[0].flags = MMEYEPCMCIA_FLAG_SOCKETP;
300	sc->handle[0].laststate = MMEYEPCMCIA_LASTSTATE_EMPTY;
301
302	SIMPLEQ_INIT(&sc->handle[0].events);
303
304	if (sc->controller_irq != MAINBUSCF_IRQ1_DEFAULT) {
305		aprint_normal(": using MMTA irq %d\n", sc->controller_irq);
306		mmeye_intr_establish(sc->controller_irq,
307		    IST_LEVEL, IPL_TTY, mmeyepcmcia_intr, sc);
308	} else
309		aprint_normal("\n");
310
311	mmeyepcmcia_attach_sockets(sc);
312}
313
314static void *
315mmeyepcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch,
316    struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg)
317{
318	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
319	int irq = h->sc->card_irq;
320	void *ih;
321
322	ih = mmeye_intr_establish(irq, IST_LEVEL, ipl, fct, arg);
323	h->ih_irq = irq;
324
325	printf("%s: card irq %d\n", device_xname(h->pcmcia), irq);
326
327	return ih;
328}
329
330static void
331mmeyepcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
332{
333	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
334
335	h->ih_irq = 0;
336	mmeye_intr_disestablish(ih);
337}
338
339
340static void
341mmeyepcmcia_attach_sockets(struct mmeyepcmcia_softc *sc)
342{
343
344	mmeyepcmcia_attach_socket(&sc->handle[0]);
345}
346
347static void
348mmeyepcmcia_attach_socket(struct mmeyepcmcia_handle *h)
349{
350	struct pcmciabus_attach_args paa;
351
352	/* initialize the rest of the handle */
353
354	h->shutdown = 0;
355	h->memalloc = 0;
356	h->ioalloc = 0;
357	h->ih_irq = 0;
358
359	/* now, config one pcmcia device per socket */
360
361	paa.paa_busname = "pcmcia";
362	paa.pct = (pcmcia_chipset_tag_t) h->sc->pct;
363	paa.pch = (pcmcia_chipset_handle_t) h;
364
365	h->pcmcia =
366	    config_found(h->sc->dev, &paa, mmeyepcmcia_print, CFARGS_NONE);
367
368	/* if there's actually a pcmcia device attached, initialize the slot */
369
370	if (h->pcmcia)
371		mmeyepcmcia_init_socket(h);
372}
373
374static void
375mmeyepcmcia_event_thread(void *arg)
376{
377	struct mmeyepcmcia_handle *h = arg;
378	struct mmeyepcmcia_event *pe;
379	int s;
380
381	while (h->shutdown == 0) {
382		s = splhigh();
383		if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) {
384			splx(s);
385			(void) tsleep(&h->events, PWAIT, "mmeyepcmciaev", 0);
386			continue;
387		} else {
388			splx(s);
389			/* sleep .25s to be enqueued chatterling interrupts */
390			(void) tsleep((void *)mmeyepcmcia_event_thread, PWAIT,
391			    "mmeyepcmciass", hz/4);
392		}
393		s = splhigh();
394		SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
395		splx(s);
396
397		switch (pe->pe_type) {
398		case MMEYEPCMCIA_EVENT_INSERTION:
399			s = splhigh();
400			while (1) {
401				struct mmeyepcmcia_event *pe1, *pe2;
402
403				if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
404					break;
405				if (pe1->pe_type != MMEYEPCMCIA_EVENT_REMOVAL)
406					break;
407				if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
408					break;
409				if (pe2->pe_type == MMEYEPCMCIA_EVENT_INSERTION) {
410					SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
411					kmem_free(pe1, sizeof(*pe1));
412					SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
413					kmem_free(pe2, sizeof(*pe2));
414				}
415			}
416			splx(s);
417
418			DPRINTF(("%s: insertion event\n", device_xname(h->sc->dev)));
419			mmeyepcmcia_attach_card(h);
420			break;
421
422		case MMEYEPCMCIA_EVENT_REMOVAL:
423			s = splhigh();
424			while (1) {
425				struct mmeyepcmcia_event *pe1, *pe2;
426
427				if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
428					break;
429				if (pe1->pe_type != MMEYEPCMCIA_EVENT_INSERTION)
430					break;
431				if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
432					break;
433				if (pe2->pe_type == MMEYEPCMCIA_EVENT_REMOVAL) {
434					SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
435					kmem_free(pe1, sizeof(*pe1));
436					SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
437					kmem_free(pe2, sizeof(*pe2));
438				}
439			}
440			splx(s);
441
442			DPRINTF(("%s: removal event\n", device_xname(h->sc->dev)));
443			mmeyepcmcia_detach_card(h, DETACH_FORCE);
444			break;
445
446		default:
447			panic("mmeyepcmcia_event_thread: unknown event %d",
448			    pe->pe_type);
449		}
450		kmem_free(pe, sizeof(*pe));
451	}
452
453	h->event_thread = NULL;
454
455	/* In case parent is waiting for us to exit. */
456	wakeup(h->sc);
457
458	kthread_exit(0);
459}
460
461static void
462mmeyepcmcia_init_socket(struct mmeyepcmcia_handle *h)
463{
464	int reg;
465
466	/*
467	 * queue creation of a kernel thread to handle insert/removal events.
468	 */
469#ifdef DIAGNOSTIC
470	if (h->event_thread != NULL)
471		panic("mmeyepcmcia_attach_socket: event thread");
472#endif
473
474	/* if there's a card there, then attach it. */
475
476	reg = mmeyepcmcia_read(h, MMEYEPCMCIA_IF_STATUS);
477	reg &= ~MMEYEPCMCIA_IF_STATUS_BUSWIDTH; /* Set bus width to 16bit */
478
479	if ((reg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) ==
480	    MMEYEPCMCIA_IF_STATUS_CARDDETECT_PRESENT) {
481		int i;
482
483		/* reset the card */
484		mmeyepcmcia_write(h, MMEYEPCMCIA_IF_STATUS, reg|MMEYEPCMCIA_IF_STATUS_RESET);
485		delay(1000); /* wait 1000 uSec */
486		mmeyepcmcia_write(h, MMEYEPCMCIA_IF_STATUS,
487			     reg & ~MMEYEPCMCIA_IF_STATUS_RESET);
488		for (i = 0; i < 10000; i++)
489			delay(1000); /* wait 1 mSec */
490
491		mmeyepcmcia_attach_card(h);
492		h->laststate = MMEYEPCMCIA_LASTSTATE_PRESENT;
493	} else {
494		h->laststate = MMEYEPCMCIA_LASTSTATE_EMPTY;
495	}
496
497	if (kthread_create(PRI_NONE, 0, NULL, mmeyepcmcia_event_thread, h,
498	    &h->event_thread, "%s", device_xname(h->sc->dev))) {
499		printf("%s: unable to create event thread\n",
500		    device_xname(h->sc->dev));
501		panic("mmeyepcmcia_create_event_thread");
502	}
503}
504
505static int
506mmeyepcmcia_print(void *arg, const char *pnp)
507{
508
509	if (pnp)
510		aprint_normal("pcmcia at %s", pnp);
511
512	return UNCONF;
513}
514
515static int
516mmeyepcmcia_intr(void *arg)
517{
518	struct mmeyepcmcia_softc *sc = arg;
519
520	DPRINTF(("%s: intr\n", device_xname(sc->dev)));
521
522	mmeyepcmcia_intr_socket(&sc->handle[0]);
523
524	return 0;
525}
526
527static int
528mmeyepcmcia_intr_socket(struct mmeyepcmcia_handle *h)
529{
530	int cscreg;
531
532	cscreg = mmeyepcmcia_read(h, MMEYEPCMCIA_CSC);
533
534	cscreg &= (MMEYEPCMCIA_CSC_GPI |
535		   MMEYEPCMCIA_CSC_CD |
536		   MMEYEPCMCIA_CSC_READY |
537		   MMEYEPCMCIA_CSC_BATTWARN |
538		   MMEYEPCMCIA_CSC_BATTDEAD);
539
540	if (cscreg & MMEYEPCMCIA_CSC_GPI) {
541		DPRINTF(("%s: GPI\n", device_xname(h->sc->dev)));
542	}
543	if (cscreg & MMEYEPCMCIA_CSC_CD) {
544		int statreg;
545
546		statreg = mmeyepcmcia_read(h, MMEYEPCMCIA_IF_STATUS);
547
548		DPRINTF(("%s: CD %x\n", device_xname(h->sc->dev), statreg));
549
550		if ((statreg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) ==
551		    MMEYEPCMCIA_IF_STATUS_CARDDETECT_PRESENT) {
552			if (h->laststate != MMEYEPCMCIA_LASTSTATE_PRESENT) {
553				DPRINTF(("%s: enqueuing INSERTION event\n",
554						 device_xname(h->sc->dev)));
555				mmeyepcmcia_queue_event(h, MMEYEPCMCIA_EVENT_INSERTION);
556			}
557			h->laststate = MMEYEPCMCIA_LASTSTATE_PRESENT;
558		} else {
559			if (h->laststate == MMEYEPCMCIA_LASTSTATE_PRESENT) {
560				/* Deactivate the card now. */
561				DPRINTF(("%s: deactivating card\n",
562						 device_xname(h->sc->dev)));
563				mmeyepcmcia_deactivate_card(h);
564
565				DPRINTF(("%s: enqueuing REMOVAL event\n",
566						 device_xname(h->sc->dev)));
567				mmeyepcmcia_queue_event(h, MMEYEPCMCIA_EVENT_REMOVAL);
568			}
569			h->laststate = ((statreg & MMEYEPCMCIA_IF_STATUS_CARDDETECT_MASK) == 0)
570				? MMEYEPCMCIA_LASTSTATE_EMPTY : MMEYEPCMCIA_LASTSTATE_HALF;
571		}
572	}
573	if (cscreg & MMEYEPCMCIA_CSC_READY) {
574		DPRINTF(("%s: READY\n", device_xname(h->sc->dev)));
575		/* shouldn't happen */
576	}
577	if (cscreg & MMEYEPCMCIA_CSC_BATTWARN) {
578		DPRINTF(("%s: BATTWARN\n", device_xname(h->sc->dev)));
579	}
580	if (cscreg & MMEYEPCMCIA_CSC_BATTDEAD) {
581		DPRINTF(("%s: BATTDEAD\n", device_xname(h->sc->dev)));
582	}
583	return cscreg ? 1 : 0;
584}
585
586static void
587mmeyepcmcia_queue_event(struct mmeyepcmcia_handle *h, int event)
588{
589	struct mmeyepcmcia_event *pe;
590	int s;
591
592	pe = kmem_intr_alloc(sizeof(*pe), KM_NOSLEEP);
593	if (pe == NULL)
594		panic("mmeyepcmcia_queue_event: can't allocate event");
595
596	pe->pe_type = event;
597	s = splhigh();
598	SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q);
599	splx(s);
600	wakeup(&h->events);
601}
602
603static void
604mmeyepcmcia_attach_card(struct mmeyepcmcia_handle *h)
605{
606
607	if (!(h->flags & MMEYEPCMCIA_FLAG_CARDP)) {
608		/* call the MI attach function */
609		pcmcia_card_attach(h->pcmcia);
610
611		h->flags |= MMEYEPCMCIA_FLAG_CARDP;
612	} else {
613		DPRINTF(("mmeyepcmcia_attach_card: already attached"));
614	}
615}
616
617static void
618mmeyepcmcia_detach_card(struct mmeyepcmcia_handle *h, int flags)
619{
620
621	if (h->flags & MMEYEPCMCIA_FLAG_CARDP) {
622		h->flags &= ~MMEYEPCMCIA_FLAG_CARDP;
623
624		/* call the MI detach function */
625		pcmcia_card_detach(h->pcmcia, flags);
626	} else {
627		DPRINTF(("mmeyepcmcia_detach_card: already detached"));
628	}
629}
630
631static void
632mmeyepcmcia_deactivate_card(struct mmeyepcmcia_handle *h)
633{
634
635	/* call the MI deactivate function */
636	pcmcia_card_deactivate(h->pcmcia);
637
638	/* Power down and reset XXX notyet */
639}
640
641static int
642mmeyepcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
643    struct pcmcia_mem_handle *pcmhp)
644{
645	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
646	bus_addr_t addr;
647	bus_size_t sizepg;
648	int i, mask, mhandle;
649
650	/* out of sc->memh, allocate as many pages as necessary */
651#define	MMEYEPCMCIA_MEM_ALIGN	MMEYEPCMCIA_MEM_PAGESIZE
652	/* convert size to PCIC pages */
653	sizepg = (size + (MMEYEPCMCIA_MEM_ALIGN - 1)) / MMEYEPCMCIA_MEM_ALIGN;
654	if (sizepg > MMEYEPCMCIA_MAX_MEM_PAGES)
655		return 1;
656
657	mask = (1 << sizepg) - 1;
658
659	addr = 0;		/* XXX gcc -Wuninitialized */
660	mhandle = 0;		/* XXX gcc -Wuninitialized */
661
662	for (i = 0; i <= MMEYEPCMCIA_MAX_MEM_PAGES - sizepg; i++) {
663		if ((h->sc->subregionmask & (mask << i)) == (mask << i)) {
664			mhandle = mask << i;
665			addr = h->sc->iobase + (i * MMEYEPCMCIA_MEM_PAGESIZE);
666			h->sc->subregionmask &= ~(mhandle);
667			pcmhp->memt = h->sc->memt;
668			pcmhp->memh = 0;
669			pcmhp->addr = addr;
670			pcmhp->size = size;
671			pcmhp->mhandle = mhandle;
672			pcmhp->realsize = sizepg * MMEYEPCMCIA_MEM_PAGESIZE;
673			return 0;
674		}
675	}
676
677	return 1;
678}
679
680static void
681mmeyepcmcia_chip_mem_free(pcmcia_chipset_handle_t pch,
682    struct pcmcia_mem_handle *pcmhp)
683{
684	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
685
686	h->sc->subregionmask |= pcmhp->mhandle;
687}
688
689static int
690mmeyepcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind,
691    bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp,
692    bus_size_t *offsetp, int *windowp)
693{
694	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
695	bus_addr_t busaddr;
696	int i, win;
697
698	win = -1;
699	for (i = 0; i < MMEYEPCMCIA_WINS; i++) {
700		if ((h->memalloc & (1 << i)) == 0) {
701			win = i;
702			h->memalloc |= (1 << i);
703			break;
704		}
705	}
706
707	if (win == -1)
708		return 1;
709
710	*windowp = win;
711
712	/* XXX this is pretty gross */
713
714	busaddr = pcmhp->addr + card_addr;
715
716#if defined(SH7750R)
717	switch (kind) {
718	case PCMCIA_MEM_ATTR:
719	case PCMCIA_MEM_ATTR | PCMCIA_WIDTH_MEM16:
720		pcmhp->memt = SH3_BUS_SPACE_PCMCIA_ATT;
721		break;
722
723	case PCMCIA_MEM_ATTR | PCMCIA_WIDTH_MEM8:
724		pcmhp->memt = SH3_BUS_SPACE_PCMCIA_ATT8;
725		break;
726
727	case PCMCIA_MEM_COMMON:
728	case PCMCIA_MEM_COMMON | PCMCIA_WIDTH_MEM16:
729		pcmhp->memt = SH3_BUS_SPACE_PCMCIA_MEM;
730		break;
731
732	case PCMCIA_MEM_COMMON | PCMCIA_WIDTH_MEM8:
733		pcmhp->memt = SH3_BUS_SPACE_PCMCIA_MEM8;
734		break;
735
736	default:
737		panic("mmeyepcmcia_chip_mem_map kind is bogus: 0x%x", kind);
738	}
739#else
740	if (!bus_space_is_equal(h->sc->memt, pcmhp->memt))
741		panic("mmeyepcmcia_chip_mem_map memt is bogus");
742	if (kind != PCMCIA_MEM_ATTR)
743		busaddr += MMEYEPCMCIA_ATTRMEM_SIZE;
744#endif
745	if (bus_space_map(pcmhp->memt, busaddr, pcmhp->size, 0, &pcmhp->memh))
746		return 1;
747
748	/*
749	 * compute the address offset to the pcmcia address space for the
750	 * pcic.  this is intentionally signed.  The masks and shifts below
751	 * will cause TRT to happen in the pcic registers.  Deal with making
752	 * sure the address is aligned, and return the alignment offset.
753	 */
754
755	*offsetp = 0;
756
757	DPRINTF(("mmeyepcmcia_chip_mem_map window %d bus %lx+%lx+%lx at card addr "
758	    "%lx\n", win, (u_long) busaddr, (u_long) * offsetp, (u_long) size,
759	    (u_long) card_addr));
760
761	/*
762	 * include the offset in the size, and decrement size by one, since
763	 * the hw wants start/stop
764	 */
765	h->mem[win].addr = busaddr;
766	h->mem[win].size = size - 1;
767	h->mem[win].kind = kind;
768	h->mem[win].memt = pcmhp->memt;
769	h->mem[win].memh = pcmhp->memh;
770
771	return 0;
772}
773
774static void
775mmeyepcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window)
776{
777	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
778
779	if (window >= MMEYEPCMCIA_WINS)
780		panic("mmeyepcmcia_chip_mem_unmap: window out of range");
781
782	h->memalloc &= ~(1 << window);
783
784	bus_space_unmap(h->mem[window].memt, h->mem[window].memh,
785	    h->mem[window].size);
786}
787
788static int
789mmeyepcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
790    bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
791{
792	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
793	bus_addr_t ioaddr;
794
795	/*
796	 * Allocate some arbitrary I/O space.
797	 */
798       ioaddr = h->sc->iobase + start;
799       DPRINTF(("mmeyepcmcia_chip_io_alloc alloc port %lx+%lx\n",
800            ioaddr, size));
801
802	pcihp->iot = h->sc->memt;
803	pcihp->ioh = 0;
804	pcihp->addr = ioaddr;
805	pcihp->size = size;
806
807	return 0;
808}
809
810static void
811mmeyepcmcia_chip_io_free(pcmcia_chipset_handle_t pch,
812    struct pcmcia_io_handle *pcihp)
813{
814}
815
816static int
817mmeyepcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width,
818    bus_addr_t offset, bus_size_t size, struct pcmcia_io_handle *pcihp,
819    int *windowp)
820{
821	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
822	bus_addr_t busaddr;
823	int i, win;
824#ifdef MMEYEPCMCIADEBUG
825	static const char *width_names[] = { "auto", "io8", "io16" };
826#endif
827
828	/* I/O width is hardwired to 16bit mode on mmeye. */
829	width = PCMCIA_WIDTH_IO16;
830
831	win = -1;
832	for (i = 0; i < MMEYEPCMCIA_IOWINS; i++) {
833		if ((h->ioalloc & (1 << i)) == 0) {
834			win = i;
835			h->ioalloc |= (1 << i);
836			break;
837		}
838	}
839
840	if (win == -1)
841		return 1;
842
843	*windowp = win;
844
845	/* XXX this is pretty gross */
846
847	busaddr = pcihp->addr + offset;
848
849#if defined(SH7750R)
850	switch (width) {
851	case PCMCIA_WIDTH_IO8:
852		pcihp->iot = SH3_BUS_SPACE_PCMCIA_IO8;
853		break;
854
855	case PCMCIA_WIDTH_IO16:
856		pcihp->iot = SH3_BUS_SPACE_PCMCIA_IO;
857		break;
858
859	case PCMCIA_WIDTH_AUTO:
860	default:
861		panic("mmeyepcmcia_chip_io_map width is bogus: 0x%x", width);
862	}
863#else
864	if (!bus_space_is_equal(h->sc->iot, pcihp->iot))
865		panic("mmeyepcmcia_chip_io_map iot is bogus");
866	busaddr += MMEYEPCMCIA_ATTRMEM_SIZE;
867#endif
868	if (bus_space_map(pcihp->iot, busaddr, pcihp->size, 0, &pcihp->ioh))
869		return 1;
870
871	DPRINTF(("mmeyepcmcia_chip_io_map window %d %s port %lx+%lx\n",
872		 win, width_names[width], (u_long) offset, (u_long) size));
873
874	/* XXX wtf is this doing here? */
875
876	h->io[win].addr = busaddr;
877	h->io[win].size = size;
878	h->io[win].width = width;
879	h->io[win].iot = pcihp->iot;
880	h->io[win].ioh = pcihp->ioh;
881
882	return 0;
883}
884
885static void
886mmeyepcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window)
887{
888	struct mmeyepcmcia_handle *h = (struct mmeyepcmcia_handle *) pch;
889
890	if (window >= MMEYEPCMCIA_IOWINS)
891		panic("mmeyepcmcia_chip_io_unmap: window out of range");
892
893	h->ioalloc &= ~(1 << window);
894
895	bus_space_unmap(h->io[window].iot, h->io[window].ioh,
896	    h->io[window].size);
897}
898
899static void
900mmeyepcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch)
901{
902}
903
904static void
905mmeyepcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch)
906{
907}
908
909static void
910mmeyepcmcia_chip_socket_settype(pcmcia_chipset_handle_t pch, int type)
911{
912}
913