1219b2ee8SDavid du Colombier #include "u.h"
2219b2ee8SDavid du Colombier #include "../port/lib.h"
3219b2ee8SDavid du Colombier #include "mem.h"
4219b2ee8SDavid du Colombier #include "dat.h"
5219b2ee8SDavid du Colombier #include "fns.h"
6219b2ee8SDavid du Colombier #include "../port/error.h"
7219b2ee8SDavid du Colombier #include "io.h"
8219b2ee8SDavid du Colombier
9219b2ee8SDavid du Colombier /*
109a747e4fSDavid du Colombier * Intel 82365SL PCIC controller and compatibles.
11219b2ee8SDavid du Colombier */
12219b2ee8SDavid du Colombier enum
13219b2ee8SDavid du Colombier {
14219b2ee8SDavid du Colombier /*
15219b2ee8SDavid du Colombier * registers indices
16219b2ee8SDavid du Colombier */
17219b2ee8SDavid du Colombier Rid= 0x0, /* identification and revision */
18219b2ee8SDavid du Colombier Ris= 0x1, /* interface status */
19219b2ee8SDavid du Colombier Rpc= 0x2, /* power control */
20219b2ee8SDavid du Colombier Foutena= (1<<7), /* output enable */
21219b2ee8SDavid du Colombier Fautopower= (1<<5), /* automatic power switching */
22219b2ee8SDavid du Colombier Fcardena= (1<<4), /* PC card enable */
23219b2ee8SDavid du Colombier Rigc= 0x3, /* interrupt and general control */
24219b2ee8SDavid du Colombier Fiocard= (1<<5), /* I/O card (vs memory) */
25219b2ee8SDavid du Colombier Fnotreset= (1<<6), /* reset if not set */
26219b2ee8SDavid du Colombier FSMIena= (1<<4), /* enable change interrupt on SMI */
27219b2ee8SDavid du Colombier Rcsc= 0x4, /* card status change */
28219b2ee8SDavid du Colombier Rcscic= 0x5, /* card status change interrupt config */
29219b2ee8SDavid du Colombier Fchangeena= (1<<3), /* card changed */
30219b2ee8SDavid du Colombier Fbwarnena= (1<<1), /* card battery warning */
31219b2ee8SDavid du Colombier Fbdeadena= (1<<0), /* card battery dead */
32219b2ee8SDavid du Colombier Rwe= 0x6, /* address window enable */
33219b2ee8SDavid du Colombier Fmem16= (1<<5), /* use A23-A12 to decode address */
34219b2ee8SDavid du Colombier Rio= 0x7, /* I/O control */
35219b2ee8SDavid du Colombier Fwidth16= (1<<0), /* 16 bit data width */
36219b2ee8SDavid du Colombier Fiocs16= (1<<1), /* IOCS16 determines data width */
377dd7cddfSDavid du Colombier Fzerows= (1<<2), /* zero wait state */
38219b2ee8SDavid du Colombier Ftiming= (1<<3), /* timing register to use */
39219b2ee8SDavid du Colombier Riobtm0lo= 0x8, /* I/O address 0 start low byte */
40219b2ee8SDavid du Colombier Riobtm0hi= 0x9, /* I/O address 0 start high byte */
41219b2ee8SDavid du Colombier Riotop0lo= 0xa, /* I/O address 0 stop low byte */
42219b2ee8SDavid du Colombier Riotop0hi= 0xb, /* I/O address 0 stop high byte */
43219b2ee8SDavid du Colombier Riobtm1lo= 0xc, /* I/O address 1 start low byte */
44219b2ee8SDavid du Colombier Riobtm1hi= 0xd, /* I/O address 1 start high byte */
45219b2ee8SDavid du Colombier Riotop1lo= 0xe, /* I/O address 1 stop low byte */
46219b2ee8SDavid du Colombier Riotop1hi= 0xf, /* I/O address 1 stop high byte */
47219b2ee8SDavid du Colombier Rmap= 0x10, /* map 0 */
48219b2ee8SDavid du Colombier
49219b2ee8SDavid du Colombier /*
50219b2ee8SDavid du Colombier * CL-PD67xx extension registers
51219b2ee8SDavid du Colombier */
52219b2ee8SDavid du Colombier Rmisc1= 0x16, /* misc control 1 */
53219b2ee8SDavid du Colombier F5Vdetect= (1<<0),
54219b2ee8SDavid du Colombier Fvcc3V= (1<<1),
55219b2ee8SDavid du Colombier Fpmint= (1<<2),
56219b2ee8SDavid du Colombier Fpsirq= (1<<3),
57219b2ee8SDavid du Colombier Fspeaker= (1<<4),
58219b2ee8SDavid du Colombier Finpack= (1<<7),
59219b2ee8SDavid du Colombier Rfifo= 0x17, /* fifo control */
60219b2ee8SDavid du Colombier Fflush= (1<<7), /* flush fifo */
61219b2ee8SDavid du Colombier Rmisc2= 0x1E, /* misc control 2 */
62219b2ee8SDavid du Colombier Flowpow= (1<<1), /* low power mode */
63219b2ee8SDavid du Colombier Rchipinfo= 0x1F, /* chip information */
64219b2ee8SDavid du Colombier Ratactl= 0x26, /* ATA control */
65219b2ee8SDavid du Colombier
66219b2ee8SDavid du Colombier /*
67219b2ee8SDavid du Colombier * offsets into the system memory address maps
68219b2ee8SDavid du Colombier */
69219b2ee8SDavid du Colombier Mbtmlo= 0x0, /* System mem addr mapping start low byte */
70219b2ee8SDavid du Colombier Mbtmhi= 0x1, /* System mem addr mapping start high byte */
71219b2ee8SDavid du Colombier F16bit= (1<<7), /* 16-bit wide data path */
72219b2ee8SDavid du Colombier Mtoplo= 0x2, /* System mem addr mapping stop low byte */
73219b2ee8SDavid du Colombier Mtophi= 0x3, /* System mem addr mapping stop high byte */
74219b2ee8SDavid du Colombier Ftimer1= (1<<6), /* timer set 1 */
75219b2ee8SDavid du Colombier Mofflo= 0x4, /* Card memory offset address low byte */
76219b2ee8SDavid du Colombier Moffhi= 0x5, /* Card memory offset address high byte */
77219b2ee8SDavid du Colombier Fregactive= (1<<6), /* attribute memory */
78219b2ee8SDavid du Colombier
79219b2ee8SDavid du Colombier /*
80219b2ee8SDavid du Colombier * configuration registers - they start at an offset in attribute
81219b2ee8SDavid du Colombier * memory found in the CIS.
82219b2ee8SDavid du Colombier */
83219b2ee8SDavid du Colombier Rconfig= 0,
84219b2ee8SDavid du Colombier Creset= (1<<7), /* reset device */
85219b2ee8SDavid du Colombier Clevel= (1<<6), /* level sensitive interrupt line */
8615174232SDavid du Colombier Cirq= (1<<2), /* IRQ enable */
8715174232SDavid du Colombier Cdecode= (1<<1), /* address decode */
8815174232SDavid du Colombier Cfunc= (1<<0), /* function enable */
8915174232SDavid du Colombier Riobase0= 5,
9015174232SDavid du Colombier Riobase1= 6,
9115174232SDavid du Colombier Riosize= 9,
92219b2ee8SDavid du Colombier };
93219b2ee8SDavid du Colombier
94219b2ee8SDavid du Colombier #define MAP(x,o) (Rmap + (x)*0x8 + o)
95219b2ee8SDavid du Colombier
96219b2ee8SDavid du Colombier typedef struct I82365 I82365;
97219b2ee8SDavid du Colombier
98219b2ee8SDavid du Colombier /* a controller */
99219b2ee8SDavid du Colombier enum
100219b2ee8SDavid du Colombier {
101219b2ee8SDavid du Colombier Ti82365,
102219b2ee8SDavid du Colombier Tpd6710,
103219b2ee8SDavid du Colombier Tpd6720,
1047dd7cddfSDavid du Colombier Tvg46x,
105219b2ee8SDavid du Colombier };
106219b2ee8SDavid du Colombier struct I82365
107219b2ee8SDavid du Colombier {
108219b2ee8SDavid du Colombier int type;
109219b2ee8SDavid du Colombier int dev;
110219b2ee8SDavid du Colombier int nslot;
111219b2ee8SDavid du Colombier int xreg; /* index register address */
112219b2ee8SDavid du Colombier int dreg; /* data register address */
11359cc4ca5SDavid du Colombier int irq;
114219b2ee8SDavid du Colombier };
115219b2ee8SDavid du Colombier static I82365 *controller[4];
116219b2ee8SDavid du Colombier static int ncontroller;
11780ee5cbfSDavid du Colombier static PCMslot *slot;
11880ee5cbfSDavid du Colombier static PCMslot *lastslot;
119219b2ee8SDavid du Colombier static nslot;
120219b2ee8SDavid du Colombier
121219b2ee8SDavid du Colombier static void i82365intr(Ureg*, void*);
122219b2ee8SDavid du Colombier static int pcmio(int, ISAConf*);
1237dd7cddfSDavid du Colombier static long pcmread(int, int, void*, long, vlong);
1247dd7cddfSDavid du Colombier static long pcmwrite(int, int, void*, long, vlong);
1257dd7cddfSDavid du Colombier
12680ee5cbfSDavid du Colombier static void i82365dump(PCMslot*);
127219b2ee8SDavid du Colombier
128219b2ee8SDavid du Colombier /*
129219b2ee8SDavid du Colombier * reading and writing card registers
130219b2ee8SDavid du Colombier */
131219b2ee8SDavid du Colombier static uchar
rdreg(PCMslot * pp,int index)13280ee5cbfSDavid du Colombier rdreg(PCMslot *pp, int index)
133219b2ee8SDavid du Colombier {
13480ee5cbfSDavid du Colombier outb(((I82365*)pp->cp)->xreg, pp->base + index);
13580ee5cbfSDavid du Colombier return inb(((I82365*)pp->cp)->dreg);
136219b2ee8SDavid du Colombier }
137219b2ee8SDavid du Colombier static void
wrreg(PCMslot * pp,int index,uchar val)13880ee5cbfSDavid du Colombier wrreg(PCMslot *pp, int index, uchar val)
139219b2ee8SDavid du Colombier {
14080ee5cbfSDavid du Colombier outb(((I82365*)pp->cp)->xreg, pp->base + index);
14180ee5cbfSDavid du Colombier outb(((I82365*)pp->cp)->dreg, val);
142219b2ee8SDavid du Colombier }
143219b2ee8SDavid du Colombier
144219b2ee8SDavid du Colombier /*
145219b2ee8SDavid du Colombier * get info about card
146219b2ee8SDavid du Colombier */
147219b2ee8SDavid du Colombier static void
slotinfo(PCMslot * pp)14880ee5cbfSDavid du Colombier slotinfo(PCMslot *pp)
149219b2ee8SDavid du Colombier {
150219b2ee8SDavid du Colombier uchar isr;
151219b2ee8SDavid du Colombier
152219b2ee8SDavid du Colombier isr = rdreg(pp, Ris);
153219b2ee8SDavid du Colombier pp->occupied = (isr & (3<<2)) == (3<<2);
154219b2ee8SDavid du Colombier pp->powered = isr & (1<<6);
155219b2ee8SDavid du Colombier pp->battery = (isr & 3) == 3;
156219b2ee8SDavid du Colombier pp->wrprot = isr & (1<<4);
157219b2ee8SDavid du Colombier pp->busy = isr & (1<<5);
15880ee5cbfSDavid du Colombier pp->msec = TK2MS(MACHP(0)->ticks);
159219b2ee8SDavid du Colombier }
160219b2ee8SDavid du Colombier
161219b2ee8SDavid du Colombier static int
vcode(int volt)162219b2ee8SDavid du Colombier vcode(int volt)
163219b2ee8SDavid du Colombier {
164219b2ee8SDavid du Colombier switch(volt){
165219b2ee8SDavid du Colombier case 5:
166219b2ee8SDavid du Colombier return 1;
167219b2ee8SDavid du Colombier case 12:
168219b2ee8SDavid du Colombier return 2;
169219b2ee8SDavid du Colombier default:
170219b2ee8SDavid du Colombier return 0;
171219b2ee8SDavid du Colombier }
172219b2ee8SDavid du Colombier }
173219b2ee8SDavid du Colombier
174219b2ee8SDavid du Colombier /*
175219b2ee8SDavid du Colombier * enable the slot card
176219b2ee8SDavid du Colombier */
177219b2ee8SDavid du Colombier static void
slotena(PCMslot * pp)17880ee5cbfSDavid du Colombier slotena(PCMslot *pp)
179219b2ee8SDavid du Colombier {
180219b2ee8SDavid du Colombier if(pp->enabled)
181219b2ee8SDavid du Colombier return;
182219b2ee8SDavid du Colombier
183219b2ee8SDavid du Colombier /* power up and unreset, wait's are empirical (???) */
184219b2ee8SDavid du Colombier wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
185219b2ee8SDavid du Colombier delay(300);
186219b2ee8SDavid du Colombier wrreg(pp, Rigc, 0);
187219b2ee8SDavid du Colombier delay(100);
188219b2ee8SDavid du Colombier wrreg(pp, Rigc, Fnotreset);
18964c7f6b6SDavid du Colombier delay(500);
190219b2ee8SDavid du Colombier
191219b2ee8SDavid du Colombier /* get configuration */
192219b2ee8SDavid du Colombier slotinfo(pp);
193219b2ee8SDavid du Colombier if(pp->occupied){
19480ee5cbfSDavid du Colombier pcmcisread(pp);
195219b2ee8SDavid du Colombier pp->enabled = 1;
196219b2ee8SDavid du Colombier } else
197219b2ee8SDavid du Colombier wrreg(pp, Rpc, Fautopower);
198219b2ee8SDavid du Colombier }
199219b2ee8SDavid du Colombier
200219b2ee8SDavid du Colombier /*
201219b2ee8SDavid du Colombier * disable the slot card
202219b2ee8SDavid du Colombier */
203219b2ee8SDavid du Colombier static void
slotdis(PCMslot * pp)20480ee5cbfSDavid du Colombier slotdis(PCMslot *pp)
205219b2ee8SDavid du Colombier {
206219b2ee8SDavid du Colombier wrreg(pp, Rpc, 0); /* turn off card power */
207219b2ee8SDavid du Colombier wrreg(pp, Rwe, 0); /* no windows */
208219b2ee8SDavid du Colombier pp->enabled = 0;
209219b2ee8SDavid du Colombier }
210219b2ee8SDavid du Colombier
211219b2ee8SDavid du Colombier /*
212219b2ee8SDavid du Colombier * status change interrupt
213219b2ee8SDavid du Colombier */
214219b2ee8SDavid du Colombier static void
i82365intr(Ureg *,void *)2157dd7cddfSDavid du Colombier i82365intr(Ureg *, void *)
216219b2ee8SDavid du Colombier {
217219b2ee8SDavid du Colombier uchar csc, was;
21880ee5cbfSDavid du Colombier PCMslot *pp;
219219b2ee8SDavid du Colombier
220219b2ee8SDavid du Colombier if(slot == 0)
221219b2ee8SDavid du Colombier return;
222219b2ee8SDavid du Colombier
223219b2ee8SDavid du Colombier for(pp = slot; pp < lastslot; pp++){
224219b2ee8SDavid du Colombier csc = rdreg(pp, Rcsc);
225219b2ee8SDavid du Colombier was = pp->occupied;
226219b2ee8SDavid du Colombier slotinfo(pp);
227219b2ee8SDavid du Colombier if(csc & (1<<3) && was != pp->occupied){
2287dd7cddfSDavid du Colombier if(!pp->occupied)
229219b2ee8SDavid du Colombier slotdis(pp);
230219b2ee8SDavid du Colombier }
231219b2ee8SDavid du Colombier }
232219b2ee8SDavid du Colombier }
233219b2ee8SDavid du Colombier
234219b2ee8SDavid du Colombier enum
235219b2ee8SDavid du Colombier {
236219b2ee8SDavid du Colombier Mshift= 12,
237219b2ee8SDavid du Colombier Mgran= (1<<Mshift), /* granularity of maps */
238219b2ee8SDavid du Colombier Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
239219b2ee8SDavid du Colombier };
240219b2ee8SDavid du Colombier
241219b2ee8SDavid du Colombier /*
242219b2ee8SDavid du Colombier * get a map for pc card region, return corrected len
243219b2ee8SDavid du Colombier */
244219b2ee8SDavid du Colombier PCMmap*
pcmmap(int slotno,ulong offset,int len,int attr)245219b2ee8SDavid du Colombier pcmmap(int slotno, ulong offset, int len, int attr)
246219b2ee8SDavid du Colombier {
24780ee5cbfSDavid du Colombier PCMslot *pp;
248219b2ee8SDavid du Colombier uchar we, bit;
249219b2ee8SDavid du Colombier PCMmap *m, *nm;
250219b2ee8SDavid du Colombier int i;
251219b2ee8SDavid du Colombier ulong e;
252219b2ee8SDavid du Colombier
253219b2ee8SDavid du Colombier pp = slot + slotno;
254219b2ee8SDavid du Colombier lock(&pp->mlock);
255219b2ee8SDavid du Colombier
256219b2ee8SDavid du Colombier /* convert offset to granularity */
257219b2ee8SDavid du Colombier if(len <= 0)
258219b2ee8SDavid du Colombier len = 1;
259219b2ee8SDavid du Colombier e = ROUND(offset+len, Mgran);
260219b2ee8SDavid du Colombier offset &= Mmask;
261219b2ee8SDavid du Colombier len = e - offset;
262219b2ee8SDavid du Colombier
263219b2ee8SDavid du Colombier /* look for a map that covers the right area */
264219b2ee8SDavid du Colombier we = rdreg(pp, Rwe);
265219b2ee8SDavid du Colombier bit = 1;
266219b2ee8SDavid du Colombier nm = 0;
26780ee5cbfSDavid du Colombier for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
268219b2ee8SDavid du Colombier if((we & bit))
269219b2ee8SDavid du Colombier if(m->attr == attr)
270219b2ee8SDavid du Colombier if(offset >= m->ca && e <= m->cea){
271219b2ee8SDavid du Colombier
272219b2ee8SDavid du Colombier m->ref++;
273219b2ee8SDavid du Colombier unlock(&pp->mlock);
274219b2ee8SDavid du Colombier return m;
275219b2ee8SDavid du Colombier }
276219b2ee8SDavid du Colombier bit <<= 1;
277219b2ee8SDavid du Colombier if(nm == 0 && m->ref == 0)
278219b2ee8SDavid du Colombier nm = m;
279219b2ee8SDavid du Colombier }
280219b2ee8SDavid du Colombier m = nm;
281219b2ee8SDavid du Colombier if(m == 0){
282219b2ee8SDavid du Colombier unlock(&pp->mlock);
283219b2ee8SDavid du Colombier return 0;
284219b2ee8SDavid du Colombier }
285219b2ee8SDavid du Colombier
286219b2ee8SDavid du Colombier /* if isa space isn't big enough, free it and get more */
287219b2ee8SDavid du Colombier if(m->len < len){
288219b2ee8SDavid du Colombier if(m->isa){
2897dd7cddfSDavid du Colombier umbfree(m->isa, m->len);
290219b2ee8SDavid du Colombier m->len = 0;
291219b2ee8SDavid du Colombier }
2927dd7cddfSDavid du Colombier m->isa = PADDR(umbmalloc(0, len, Mgran));
293219b2ee8SDavid du Colombier if(m->isa == 0){
2949a747e4fSDavid du Colombier print("pcmmap: out of isa space\n");
295219b2ee8SDavid du Colombier unlock(&pp->mlock);
296219b2ee8SDavid du Colombier return 0;
297219b2ee8SDavid du Colombier }
298219b2ee8SDavid du Colombier m->len = len;
299219b2ee8SDavid du Colombier }
300219b2ee8SDavid du Colombier
301219b2ee8SDavid du Colombier /* set up new map */
302219b2ee8SDavid du Colombier m->ca = offset;
303219b2ee8SDavid du Colombier m->cea = m->ca + m->len;
304219b2ee8SDavid du Colombier m->attr = attr;
305219b2ee8SDavid du Colombier i = m-pp->mmap;
306219b2ee8SDavid du Colombier bit = 1<<i;
307219b2ee8SDavid du Colombier wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */
308219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
309219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
310219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
311219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
312219b2ee8SDavid du Colombier offset -= m->isa;
313219b2ee8SDavid du Colombier offset &= (1<<25)-1;
314219b2ee8SDavid du Colombier offset >>= Mshift;
315219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Mofflo), offset);
316219b2ee8SDavid du Colombier wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
317219b2ee8SDavid du Colombier wrreg(pp, Rwe, we | bit); /* enable map */
318219b2ee8SDavid du Colombier m->ref = 1;
319219b2ee8SDavid du Colombier
320219b2ee8SDavid du Colombier unlock(&pp->mlock);
321219b2ee8SDavid du Colombier return m;
322219b2ee8SDavid du Colombier }
323219b2ee8SDavid du Colombier
324219b2ee8SDavid du Colombier void
pcmunmap(int slotno,PCMmap * m)325219b2ee8SDavid du Colombier pcmunmap(int slotno, PCMmap* m)
326219b2ee8SDavid du Colombier {
32780ee5cbfSDavid du Colombier PCMslot *pp;
328219b2ee8SDavid du Colombier
329219b2ee8SDavid du Colombier pp = slot + slotno;
330219b2ee8SDavid du Colombier lock(&pp->mlock);
331219b2ee8SDavid du Colombier m->ref--;
332219b2ee8SDavid du Colombier unlock(&pp->mlock);
333219b2ee8SDavid du Colombier }
334219b2ee8SDavid du Colombier
335219b2ee8SDavid du Colombier static void
increfp(PCMslot * pp)33680ee5cbfSDavid du Colombier increfp(PCMslot *pp)
337219b2ee8SDavid du Colombier {
338219b2ee8SDavid du Colombier lock(pp);
339219b2ee8SDavid du Colombier if(pp->ref++ == 0)
340219b2ee8SDavid du Colombier slotena(pp);
341219b2ee8SDavid du Colombier unlock(pp);
342219b2ee8SDavid du Colombier }
343219b2ee8SDavid du Colombier
344219b2ee8SDavid du Colombier static void
decrefp(PCMslot * pp)34580ee5cbfSDavid du Colombier decrefp(PCMslot *pp)
346219b2ee8SDavid du Colombier {
347219b2ee8SDavid du Colombier lock(pp);
348219b2ee8SDavid du Colombier if(pp->ref-- == 1)
349219b2ee8SDavid du Colombier slotdis(pp);
350219b2ee8SDavid du Colombier unlock(pp);
351219b2ee8SDavid du Colombier }
352219b2ee8SDavid du Colombier
353219b2ee8SDavid du Colombier /*
354219b2ee8SDavid du Colombier * look for a card whose version contains 'idstr'
355219b2ee8SDavid du Colombier */
3569a747e4fSDavid du Colombier static int
pcmcia_pcmspecial(char * idstr,ISAConf * isa)3579a747e4fSDavid du Colombier pcmcia_pcmspecial(char *idstr, ISAConf *isa)
358219b2ee8SDavid du Colombier {
35980ee5cbfSDavid du Colombier PCMslot *pp;
360219b2ee8SDavid du Colombier extern char *strstr(char*, char*);
36180ee5cbfSDavid du Colombier int enabled;
362219b2ee8SDavid du Colombier
363219b2ee8SDavid du Colombier for(pp = slot; pp < lastslot; pp++){
364219b2ee8SDavid du Colombier if(pp->special)
365219b2ee8SDavid du Colombier continue; /* already taken */
36680ee5cbfSDavid du Colombier
36780ee5cbfSDavid du Colombier /*
36880ee5cbfSDavid du Colombier * make sure we don't power on cards when we already know what's
36980ee5cbfSDavid du Colombier * in them. We'll reread every two minutes if necessary
37080ee5cbfSDavid du Colombier */
37180ee5cbfSDavid du Colombier enabled = 0;
37280ee5cbfSDavid du Colombier if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
373219b2ee8SDavid du Colombier increfp(pp);
37480ee5cbfSDavid du Colombier enabled++;
37580ee5cbfSDavid du Colombier }
376219b2ee8SDavid du Colombier
37759cc4ca5SDavid du Colombier if(pp->occupied) {
37880ee5cbfSDavid du Colombier if(strstr(pp->verstr, idstr)){
37980ee5cbfSDavid du Colombier if (!enabled){
38080ee5cbfSDavid du Colombier enabled = 1;
38180ee5cbfSDavid du Colombier increfp(pp);
38280ee5cbfSDavid du Colombier }
383219b2ee8SDavid du Colombier if(isa == 0 || pcmio(pp->slotno, isa) == 0){
384219b2ee8SDavid du Colombier pp->special = 1;
385219b2ee8SDavid du Colombier return pp->slotno;
386219b2ee8SDavid du Colombier }
38780ee5cbfSDavid du Colombier }
38859cc4ca5SDavid du Colombier } else
38959cc4ca5SDavid du Colombier pp->special = 1;
39080ee5cbfSDavid du Colombier if (enabled)
391219b2ee8SDavid du Colombier decrefp(pp);
392219b2ee8SDavid du Colombier }
393219b2ee8SDavid du Colombier return -1;
394219b2ee8SDavid du Colombier }
395219b2ee8SDavid du Colombier
3969a747e4fSDavid du Colombier static void
pcmcia_pcmspecialclose(int slotno)3979a747e4fSDavid du Colombier pcmcia_pcmspecialclose(int slotno)
398219b2ee8SDavid du Colombier {
39980ee5cbfSDavid du Colombier PCMslot *pp;
400219b2ee8SDavid du Colombier
401219b2ee8SDavid du Colombier if(slotno >= nslot)
402219b2ee8SDavid du Colombier panic("pcmspecialclose");
403219b2ee8SDavid du Colombier pp = slot + slotno;
404219b2ee8SDavid du Colombier pp->special = 0;
405219b2ee8SDavid du Colombier decrefp(pp);
406219b2ee8SDavid du Colombier }
407219b2ee8SDavid du Colombier
408219b2ee8SDavid du Colombier enum
409219b2ee8SDavid du Colombier {
410219b2ee8SDavid du Colombier Qdir,
411219b2ee8SDavid du Colombier Qmem,
412219b2ee8SDavid du Colombier Qattr,
413219b2ee8SDavid du Colombier Qctl,
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier Nents = 3,
416219b2ee8SDavid du Colombier };
417219b2ee8SDavid du Colombier
4189a747e4fSDavid du Colombier #define SLOTNO(c) ((ulong)((c->qid.path>>8)&0xff))
4199a747e4fSDavid du Colombier #define TYPE(c) ((ulong)(c->qid.path&0xff))
420219b2ee8SDavid du Colombier #define QID(s,t) (((s)<<8)|(t))
421219b2ee8SDavid du Colombier
422219b2ee8SDavid du Colombier static int
pcmgen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)4239a747e4fSDavid du Colombier pcmgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
424219b2ee8SDavid du Colombier {
425219b2ee8SDavid du Colombier int slotno;
426219b2ee8SDavid du Colombier Qid qid;
427219b2ee8SDavid du Colombier long len;
42880ee5cbfSDavid du Colombier PCMslot *pp;
429219b2ee8SDavid du Colombier
4307dd7cddfSDavid du Colombier if(i == DEVDOTDOT){
4319a747e4fSDavid du Colombier mkqid(&qid, Qdir, 0, QTDIR);
4329a747e4fSDavid du Colombier devdir(c, qid, "#y", 0, eve, 0555, dp);
4337dd7cddfSDavid du Colombier return 1;
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier if(i >= Nents*nslot)
437219b2ee8SDavid du Colombier return -1;
4387dd7cddfSDavid du Colombier slotno = i/Nents;
439219b2ee8SDavid du Colombier pp = slot + slotno;
440219b2ee8SDavid du Colombier len = 0;
4417dd7cddfSDavid du Colombier switch(i%Nents){
442219b2ee8SDavid du Colombier case 0:
443219b2ee8SDavid du Colombier qid.path = QID(slotno, Qmem);
4449a747e4fSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
445219b2ee8SDavid du Colombier len = pp->memlen;
446219b2ee8SDavid du Colombier break;
447219b2ee8SDavid du Colombier case 1:
448219b2ee8SDavid du Colombier qid.path = QID(slotno, Qattr);
4499a747e4fSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
450219b2ee8SDavid du Colombier len = pp->memlen;
451219b2ee8SDavid du Colombier break;
452219b2ee8SDavid du Colombier case 2:
453219b2ee8SDavid du Colombier qid.path = QID(slotno, Qctl);
4549a747e4fSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
455219b2ee8SDavid du Colombier break;
456219b2ee8SDavid du Colombier }
457219b2ee8SDavid du Colombier qid.vers = 0;
4589a747e4fSDavid du Colombier qid.type = QTFILE;
4599a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, len, eve, 0660, dp);
460219b2ee8SDavid du Colombier return 1;
461219b2ee8SDavid du Colombier }
462219b2ee8SDavid du Colombier
463219b2ee8SDavid du Colombier static char *chipname[] =
464219b2ee8SDavid du Colombier {
465219b2ee8SDavid du Colombier [Ti82365] "Intel 82365SL",
4669a747e4fSDavid du Colombier [Tpd6710] "Cirrus Logic CL-PD6710",
4679a747e4fSDavid du Colombier [Tpd6720] "Cirrus Logic CL-PD6720",
4687dd7cddfSDavid du Colombier [Tvg46x] "Vadem VG-46x",
469219b2ee8SDavid du Colombier };
470219b2ee8SDavid du Colombier
471219b2ee8SDavid du Colombier static I82365*
i82365probe(int x,int d,int dev)47259cc4ca5SDavid du Colombier i82365probe(int x, int d, int dev)
473219b2ee8SDavid du Colombier {
4747dd7cddfSDavid du Colombier uchar c, id;
475219b2ee8SDavid du Colombier I82365 *cp;
47659cc4ca5SDavid du Colombier ISAConf isa;
47759cc4ca5SDavid du Colombier int i, nslot;
478219b2ee8SDavid du Colombier
479219b2ee8SDavid du Colombier outb(x, Rid + (dev<<7));
4807dd7cddfSDavid du Colombier id = inb(d);
4817dd7cddfSDavid du Colombier if((id & 0xf0) != 0x80)
48280ee5cbfSDavid du Colombier return 0; /* not a memory & I/O card */
48380ee5cbfSDavid du Colombier if((id & 0x0f) == 0x00)
48480ee5cbfSDavid du Colombier return 0; /* no revision number, not possible */
485219b2ee8SDavid du Colombier
486219b2ee8SDavid du Colombier cp = xalloc(sizeof(I82365));
487219b2ee8SDavid du Colombier cp->xreg = x;
488219b2ee8SDavid du Colombier cp->dreg = d;
489219b2ee8SDavid du Colombier cp->dev = dev;
490219b2ee8SDavid du Colombier cp->type = Ti82365;
491219b2ee8SDavid du Colombier cp->nslot = 2;
492219b2ee8SDavid du Colombier
4937dd7cddfSDavid du Colombier switch(id){
494219b2ee8SDavid du Colombier case 0x82:
495219b2ee8SDavid du Colombier case 0x83:
4967dd7cddfSDavid du Colombier case 0x84:
497219b2ee8SDavid du Colombier /* could be a cirrus */
498219b2ee8SDavid du Colombier outb(x, Rchipinfo + (dev<<7));
499219b2ee8SDavid du Colombier outb(d, 0);
500219b2ee8SDavid du Colombier c = inb(d);
5017dd7cddfSDavid du Colombier if((c & 0xc0) != 0xc0)
502219b2ee8SDavid du Colombier break;
5037dd7cddfSDavid du Colombier c = inb(d);
5047dd7cddfSDavid du Colombier if((c & 0xc0) != 0x00)
5057dd7cddfSDavid du Colombier break;
5067dd7cddfSDavid du Colombier if(c & 0x20){
507219b2ee8SDavid du Colombier cp->type = Tpd6720;
508219b2ee8SDavid du Colombier } else {
509219b2ee8SDavid du Colombier cp->type = Tpd6710;
510219b2ee8SDavid du Colombier cp->nslot = 1;
511219b2ee8SDavid du Colombier }
5129a747e4fSDavid du Colombier
5139a747e4fSDavid du Colombier /* low power mode */
5149a747e4fSDavid du Colombier outb(x, Rmisc2 + (dev<<7));
5159a747e4fSDavid du Colombier c = inb(d);
5169a747e4fSDavid du Colombier outb(d, c & ~Flowpow);
517219b2ee8SDavid du Colombier break;
518219b2ee8SDavid du Colombier }
519219b2ee8SDavid du Colombier
52080ee5cbfSDavid du Colombier /* if it's not a Cirrus, it could be a Vadem... */
5217dd7cddfSDavid du Colombier if(cp->type == Ti82365){
52280ee5cbfSDavid du Colombier /* unlock the Vadem extended regs */
5237dd7cddfSDavid du Colombier outb(x, 0x0E + (dev<<7));
5247dd7cddfSDavid du Colombier outb(x, 0x37 + (dev<<7));
52580ee5cbfSDavid du Colombier
52680ee5cbfSDavid du Colombier /* make the id register show the Vadem id */
5277dd7cddfSDavid du Colombier outb(x, 0x3A + (dev<<7));
5287dd7cddfSDavid du Colombier c = inb(d);
5297dd7cddfSDavid du Colombier outb(d, c|0xC0);
5307dd7cddfSDavid du Colombier outb(x, Rid + (dev<<7));
5317dd7cddfSDavid du Colombier c = inb(d);
5327dd7cddfSDavid du Colombier if(c & 0x08)
5337dd7cddfSDavid du Colombier cp->type = Tvg46x;
53480ee5cbfSDavid du Colombier
53580ee5cbfSDavid du Colombier /* go back to Intel compatible id */
5367dd7cddfSDavid du Colombier outb(x, 0x3A + (dev<<7));
5377dd7cddfSDavid du Colombier c = inb(d);
5387dd7cddfSDavid du Colombier outb(d, c & ~0xC0);
5397dd7cddfSDavid du Colombier }
540219b2ee8SDavid du Colombier
54159cc4ca5SDavid du Colombier memset(&isa, 0, sizeof(ISAConf));
54259cc4ca5SDavid du Colombier if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq)
54359cc4ca5SDavid du Colombier cp->irq = isa.irq;
54459cc4ca5SDavid du Colombier else
54559cc4ca5SDavid du Colombier cp->irq = IrqPCMCIA;
54659cc4ca5SDavid du Colombier
54759cc4ca5SDavid du Colombier for(i = 0; i < isa.nopt; i++){
54859cc4ca5SDavid du Colombier if(cistrncmp(isa.opt[i], "nslot=", 6))
54959cc4ca5SDavid du Colombier continue;
55059cc4ca5SDavid du Colombier nslot = strtol(&isa.opt[i][6], nil, 0);
55159cc4ca5SDavid du Colombier if(nslot > 0 && nslot <= 2)
55259cc4ca5SDavid du Colombier cp->nslot = nslot;
55359cc4ca5SDavid du Colombier }
55459cc4ca5SDavid du Colombier
555219b2ee8SDavid du Colombier controller[ncontroller++] = cp;
556219b2ee8SDavid du Colombier return cp;
557219b2ee8SDavid du Colombier }
558219b2ee8SDavid du Colombier
559219b2ee8SDavid du Colombier static void
i82365dump(PCMslot * pp)56080ee5cbfSDavid du Colombier i82365dump(PCMslot *pp)
561219b2ee8SDavid du Colombier {
562219b2ee8SDavid du Colombier int i;
563219b2ee8SDavid du Colombier
564219b2ee8SDavid du Colombier for(i = 0; i < 0x40; i++){
5657dd7cddfSDavid du Colombier if((i&0x0F) == 0)
5667dd7cddfSDavid du Colombier print("\n%2.2uX: ", i);
5679a747e4fSDavid du Colombier print("%2.2uX ", rdreg(pp, i));
5687dd7cddfSDavid du Colombier if(((i+1) & 0x0F) == 0x08)
5697dd7cddfSDavid du Colombier print(" - ");
570219b2ee8SDavid du Colombier }
571219b2ee8SDavid du Colombier print("\n");
572219b2ee8SDavid du Colombier }
573219b2ee8SDavid du Colombier
574219b2ee8SDavid du Colombier /*
575219b2ee8SDavid du Colombier * set up for slot cards
576219b2ee8SDavid du Colombier */
5779a747e4fSDavid du Colombier void
devi82365link(void)5789a747e4fSDavid du Colombier devi82365link(void)
579219b2ee8SDavid du Colombier {
580219b2ee8SDavid du Colombier static int already;
58159cc4ca5SDavid du Colombier int i, j;
582219b2ee8SDavid du Colombier I82365 *cp;
58380ee5cbfSDavid du Colombier PCMslot *pp;
584b7b24591SDavid du Colombier char buf[32], *p;
585219b2ee8SDavid du Colombier
586219b2ee8SDavid du Colombier if(already)
587219b2ee8SDavid du Colombier return;
588219b2ee8SDavid du Colombier already = 1;
589219b2ee8SDavid du Colombier
590b7b24591SDavid du Colombier if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0)
591b7b24591SDavid du Colombier return;
592b7b24591SDavid du Colombier
5939a747e4fSDavid du Colombier if(_pcmspecial)
5949a747e4fSDavid du Colombier return;
5959a747e4fSDavid du Colombier
5967dd7cddfSDavid du Colombier /* look for controllers if the ports aren't already taken */
59759cc4ca5SDavid du Colombier if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
59859cc4ca5SDavid du Colombier i82365probe(0x3E0, 0x3E1, 0);
59959cc4ca5SDavid du Colombier i82365probe(0x3E0, 0x3E1, 1);
6007dd7cddfSDavid du Colombier if(ncontroller == 0)
6017dd7cddfSDavid du Colombier iofree(0x3E0);
6027dd7cddfSDavid du Colombier }
60359cc4ca5SDavid du Colombier if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
6047dd7cddfSDavid du Colombier i = ncontroller;
60559cc4ca5SDavid du Colombier i82365probe(0x3E2, 0x3E3, 0);
60659cc4ca5SDavid du Colombier i82365probe(0x3E2, 0x3E3, 1);
6077dd7cddfSDavid du Colombier if(ncontroller == i)
6087dd7cddfSDavid du Colombier iofree(0x3E2);
6097dd7cddfSDavid du Colombier }
6109a747e4fSDavid du Colombier
6119a747e4fSDavid du Colombier if(ncontroller == 0)
6129a747e4fSDavid du Colombier return;
6139a747e4fSDavid du Colombier
6149a747e4fSDavid du Colombier _pcmspecial = pcmcia_pcmspecial;
6159a747e4fSDavid du Colombier _pcmspecialclose = pcmcia_pcmspecialclose;
6169a747e4fSDavid du Colombier
617219b2ee8SDavid du Colombier for(i = 0; i < ncontroller; i++)
618219b2ee8SDavid du Colombier nslot += controller[i]->nslot;
61980ee5cbfSDavid du Colombier slot = xalloc(nslot * sizeof(PCMslot));
620219b2ee8SDavid du Colombier
621219b2ee8SDavid du Colombier lastslot = slot;
622219b2ee8SDavid du Colombier for(i = 0; i < ncontroller; i++){
623219b2ee8SDavid du Colombier cp = controller[i];
6247dd7cddfSDavid du Colombier print("#y%d: %d slot %s: port 0x%uX irq %d\n",
62559cc4ca5SDavid du Colombier i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq);
626219b2ee8SDavid du Colombier for(j = 0; j < cp->nslot; j++){
627219b2ee8SDavid du Colombier pp = lastslot++;
628219b2ee8SDavid du Colombier pp->slotno = pp - slot;
629219b2ee8SDavid du Colombier pp->memlen = 64*MB;
630219b2ee8SDavid du Colombier pp->base = (cp->dev<<7) | (j<<6);
631219b2ee8SDavid du Colombier pp->cp = cp;
63280ee5cbfSDavid du Colombier pp->msec = ~0;
63380ee5cbfSDavid du Colombier pp->verstr[0] = 0;
634219b2ee8SDavid du Colombier slotdis(pp);
635219b2ee8SDavid du Colombier
636219b2ee8SDavid du Colombier /* interrupt on status change */
63759cc4ca5SDavid du Colombier wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena);
6387dd7cddfSDavid du Colombier rdreg(pp, Rcsc);
639219b2ee8SDavid du Colombier }
640219b2ee8SDavid du Colombier
641219b2ee8SDavid du Colombier /* for card management interrupts */
6429a747e4fSDavid du Colombier snprint(buf, sizeof buf, "i82365.%d", i);
64359cc4ca5SDavid du Colombier intrenable(cp->irq, i82365intr, 0, BUSUNKNOWN, buf);
64459cc4ca5SDavid du Colombier }
645219b2ee8SDavid du Colombier }
646219b2ee8SDavid du Colombier
6477dd7cddfSDavid du Colombier static Chan*
i82365attach(char * spec)648219b2ee8SDavid du Colombier i82365attach(char *spec)
649219b2ee8SDavid du Colombier {
650219b2ee8SDavid du Colombier return devattach('y', spec);
651219b2ee8SDavid du Colombier }
652219b2ee8SDavid du Colombier
6539a747e4fSDavid du Colombier static Walkqid*
i82365walk(Chan * c,Chan * nc,char ** name,int nname)6549a747e4fSDavid du Colombier i82365walk(Chan *c, Chan *nc, char **name, int nname)
655219b2ee8SDavid du Colombier {
6569a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, 0, 0, pcmgen);
657219b2ee8SDavid du Colombier }
658219b2ee8SDavid du Colombier
6599a747e4fSDavid du Colombier static int
i82365stat(Chan * c,uchar * db,int n)6609a747e4fSDavid du Colombier i82365stat(Chan *c, uchar *db, int n)
661219b2ee8SDavid du Colombier {
6629a747e4fSDavid du Colombier return devstat(c, db, n, 0, 0, pcmgen);
663219b2ee8SDavid du Colombier }
664219b2ee8SDavid du Colombier
6657dd7cddfSDavid du Colombier static Chan*
i82365open(Chan * c,int omode)666219b2ee8SDavid du Colombier i82365open(Chan *c, int omode)
667219b2ee8SDavid du Colombier {
6689a747e4fSDavid du Colombier if(c->qid.type & QTDIR){
669219b2ee8SDavid du Colombier if(omode != OREAD)
670219b2ee8SDavid du Colombier error(Eperm);
671219b2ee8SDavid du Colombier } else
672219b2ee8SDavid du Colombier increfp(slot + SLOTNO(c));
673219b2ee8SDavid du Colombier c->mode = openmode(omode);
674219b2ee8SDavid du Colombier c->flag |= COPEN;
675219b2ee8SDavid du Colombier c->offset = 0;
676219b2ee8SDavid du Colombier return c;
677219b2ee8SDavid du Colombier }
678219b2ee8SDavid du Colombier
6797dd7cddfSDavid du Colombier static void
i82365close(Chan * c)680219b2ee8SDavid du Colombier i82365close(Chan *c)
681219b2ee8SDavid du Colombier {
682219b2ee8SDavid du Colombier if(c->flag & COPEN)
6839a747e4fSDavid du Colombier if((c->qid.type & QTDIR) == 0)
684219b2ee8SDavid du Colombier decrefp(slot+SLOTNO(c));
685219b2ee8SDavid du Colombier }
686219b2ee8SDavid du Colombier
687219b2ee8SDavid du Colombier /* a memmove using only bytes */
688219b2ee8SDavid du Colombier static void
memmoveb(uchar * to,uchar * from,int n)689219b2ee8SDavid du Colombier memmoveb(uchar *to, uchar *from, int n)
690219b2ee8SDavid du Colombier {
691219b2ee8SDavid du Colombier while(n-- > 0)
692219b2ee8SDavid du Colombier *to++ = *from++;
693219b2ee8SDavid du Colombier }
694219b2ee8SDavid du Colombier
695219b2ee8SDavid du Colombier /* a memmove using only shorts & bytes */
696219b2ee8SDavid du Colombier static void
memmoves(uchar * to,uchar * from,int n)697219b2ee8SDavid du Colombier memmoves(uchar *to, uchar *from, int n)
698219b2ee8SDavid du Colombier {
699219b2ee8SDavid du Colombier ushort *t, *f;
700219b2ee8SDavid du Colombier
701219b2ee8SDavid du Colombier if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
702219b2ee8SDavid du Colombier while(n-- > 0)
703219b2ee8SDavid du Colombier *to++ = *from++;
704219b2ee8SDavid du Colombier } else {
705219b2ee8SDavid du Colombier n = n/2;
706219b2ee8SDavid du Colombier t = (ushort*)to;
707219b2ee8SDavid du Colombier f = (ushort*)from;
708219b2ee8SDavid du Colombier while(n-- > 0)
709219b2ee8SDavid du Colombier *t++ = *f++;
710219b2ee8SDavid du Colombier }
711219b2ee8SDavid du Colombier }
712219b2ee8SDavid du Colombier
713219b2ee8SDavid du Colombier static long
pcmread(int slotno,int attr,void * a,long n,vlong off)7147dd7cddfSDavid du Colombier pcmread(int slotno, int attr, void *a, long n, vlong off)
715219b2ee8SDavid du Colombier {
716219b2ee8SDavid du Colombier int i, len;
717219b2ee8SDavid du Colombier PCMmap *m;
718219b2ee8SDavid du Colombier uchar *ac;
71980ee5cbfSDavid du Colombier PCMslot *pp;
7207dd7cddfSDavid du Colombier ulong offset = off;
721219b2ee8SDavid du Colombier
722219b2ee8SDavid du Colombier pp = slot + slotno;
723219b2ee8SDavid du Colombier if(pp->memlen < offset)
724219b2ee8SDavid du Colombier return 0;
725219b2ee8SDavid du Colombier if(pp->memlen < offset + n)
726219b2ee8SDavid du Colombier n = pp->memlen - offset;
727219b2ee8SDavid du Colombier
728219b2ee8SDavid du Colombier m = 0;
729219b2ee8SDavid du Colombier if(waserror()){
730219b2ee8SDavid du Colombier if(m)
731219b2ee8SDavid du Colombier pcmunmap(pp->slotno, m);
732219b2ee8SDavid du Colombier nexterror();
733219b2ee8SDavid du Colombier }
734219b2ee8SDavid du Colombier
735219b2ee8SDavid du Colombier ac = a;
736219b2ee8SDavid du Colombier for(len = n; len > 0; len -= i){
737219b2ee8SDavid du Colombier m = pcmmap(pp->slotno, offset, 0, attr);
738219b2ee8SDavid du Colombier if(m == 0)
7398cd4f5a6SDavid du Colombier error("cannot map PCMCIA card");
740219b2ee8SDavid du Colombier if(offset + len > m->cea)
741219b2ee8SDavid du Colombier i = m->cea - offset;
742219b2ee8SDavid du Colombier else
743219b2ee8SDavid du Colombier i = len;
7447dd7cddfSDavid du Colombier memmoveb(ac, KADDR(m->isa + offset - m->ca), i);
745219b2ee8SDavid du Colombier pcmunmap(pp->slotno, m);
746219b2ee8SDavid du Colombier offset += i;
747219b2ee8SDavid du Colombier ac += i;
748219b2ee8SDavid du Colombier }
749219b2ee8SDavid du Colombier
750219b2ee8SDavid du Colombier poperror();
751219b2ee8SDavid du Colombier return n;
752219b2ee8SDavid du Colombier }
753219b2ee8SDavid du Colombier
7547dd7cddfSDavid du Colombier static long
i82365read(Chan * c,void * a,long n,vlong off)7557dd7cddfSDavid du Colombier i82365read(Chan *c, void *a, long n, vlong off)
756219b2ee8SDavid du Colombier {
75780ee5cbfSDavid du Colombier char *p, *buf, *e;
75880ee5cbfSDavid du Colombier PCMslot *pp;
7597dd7cddfSDavid du Colombier ulong offset = off;
760219b2ee8SDavid du Colombier
7617dd7cddfSDavid du Colombier switch(TYPE(c)){
762219b2ee8SDavid du Colombier case Qdir:
763219b2ee8SDavid du Colombier return devdirread(c, a, n, 0, 0, pcmgen);
764219b2ee8SDavid du Colombier case Qmem:
765219b2ee8SDavid du Colombier case Qattr:
7667dd7cddfSDavid du Colombier return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
767219b2ee8SDavid du Colombier case Qctl:
76880ee5cbfSDavid du Colombier buf = p = malloc(READSTR);
769*aa72973aSDavid du Colombier if(p == nil)
770*aa72973aSDavid du Colombier error(Enomem);
77180ee5cbfSDavid du Colombier e = p + READSTR;
772219b2ee8SDavid du Colombier pp = slot + SLOTNO(c);
773219b2ee8SDavid du Colombier
77480ee5cbfSDavid du Colombier buf[0] = 0;
77580ee5cbfSDavid du Colombier if(pp->occupied){
77680ee5cbfSDavid du Colombier p = seprint(p, e, "occupied\n");
77780ee5cbfSDavid du Colombier if(pp->verstr[0])
77880ee5cbfSDavid du Colombier p = seprint(p, e, "version %s\n", pp->verstr);
77980ee5cbfSDavid du Colombier }
7807dd7cddfSDavid du Colombier if(pp->enabled)
78180ee5cbfSDavid du Colombier p = seprint(p, e, "enabled\n");
7827dd7cddfSDavid du Colombier if(pp->powered)
78380ee5cbfSDavid du Colombier p = seprint(p, e, "powered\n");
7847dd7cddfSDavid du Colombier if(pp->configed)
78580ee5cbfSDavid du Colombier p = seprint(p, e, "configed\n");
7867dd7cddfSDavid du Colombier if(pp->wrprot)
78780ee5cbfSDavid du Colombier p = seprint(p, e, "write protected\n");
7887dd7cddfSDavid du Colombier if(pp->busy)
78980ee5cbfSDavid du Colombier p = seprint(p, e, "busy\n");
79080ee5cbfSDavid du Colombier seprint(p, e, "battery lvl %d\n", pp->battery);
7917dd7cddfSDavid du Colombier
79280ee5cbfSDavid du Colombier n = readstr(offset, a, n, buf);
79380ee5cbfSDavid du Colombier free(buf);
7947dd7cddfSDavid du Colombier
795219b2ee8SDavid du Colombier return n;
796219b2ee8SDavid du Colombier }
7977dd7cddfSDavid du Colombier error(Ebadarg);
7987dd7cddfSDavid du Colombier return -1; /* not reached */
7997dd7cddfSDavid du Colombier }
800219b2ee8SDavid du Colombier
801219b2ee8SDavid du Colombier static long
pcmwrite(int dev,int attr,void * a,long n,vlong off)8027dd7cddfSDavid du Colombier pcmwrite(int dev, int attr, void *a, long n, vlong off)
803219b2ee8SDavid du Colombier {
804219b2ee8SDavid du Colombier int i, len;
805219b2ee8SDavid du Colombier PCMmap *m;
806219b2ee8SDavid du Colombier uchar *ac;
80780ee5cbfSDavid du Colombier PCMslot *pp;
8087dd7cddfSDavid du Colombier ulong offset = off;
809219b2ee8SDavid du Colombier
810219b2ee8SDavid du Colombier pp = slot + dev;
811219b2ee8SDavid du Colombier if(pp->memlen < offset)
812219b2ee8SDavid du Colombier return 0;
813219b2ee8SDavid du Colombier if(pp->memlen < offset + n)
814219b2ee8SDavid du Colombier n = pp->memlen - offset;
815219b2ee8SDavid du Colombier
816219b2ee8SDavid du Colombier m = 0;
817219b2ee8SDavid du Colombier if(waserror()){
818219b2ee8SDavid du Colombier if(m)
819219b2ee8SDavid du Colombier pcmunmap(pp->slotno, m);
820219b2ee8SDavid du Colombier nexterror();
821219b2ee8SDavid du Colombier }
822219b2ee8SDavid du Colombier
823219b2ee8SDavid du Colombier ac = a;
824219b2ee8SDavid du Colombier for(len = n; len > 0; len -= i){
825219b2ee8SDavid du Colombier m = pcmmap(pp->slotno, offset, 0, attr);
826219b2ee8SDavid du Colombier if(m == 0)
8278cd4f5a6SDavid du Colombier error("cannot map PCMCIA card");
828219b2ee8SDavid du Colombier if(offset + len > m->cea)
829219b2ee8SDavid du Colombier i = m->cea - offset;
830219b2ee8SDavid du Colombier else
831219b2ee8SDavid du Colombier i = len;
8327dd7cddfSDavid du Colombier memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
833219b2ee8SDavid du Colombier pcmunmap(pp->slotno, m);
834219b2ee8SDavid du Colombier offset += i;
835219b2ee8SDavid du Colombier ac += i;
836219b2ee8SDavid du Colombier }
837219b2ee8SDavid du Colombier
838219b2ee8SDavid du Colombier poperror();
839219b2ee8SDavid du Colombier return n;
840219b2ee8SDavid du Colombier }
841219b2ee8SDavid du Colombier
8427dd7cddfSDavid du Colombier static long
i82365write(Chan * c,void * a,long n,vlong off)8437dd7cddfSDavid du Colombier i82365write(Chan *c, void *a, long n, vlong off)
844219b2ee8SDavid du Colombier {
84580ee5cbfSDavid du Colombier PCMslot *pp;
8467dd7cddfSDavid du Colombier char buf[32];
847219b2ee8SDavid du Colombier
8487dd7cddfSDavid du Colombier switch(TYPE(c)){
8497dd7cddfSDavid du Colombier case Qctl:
8507dd7cddfSDavid du Colombier if(n >= sizeof(buf))
8517dd7cddfSDavid du Colombier n = sizeof(buf) - 1;
8527dd7cddfSDavid du Colombier strncpy(buf, a, n);
8537dd7cddfSDavid du Colombier buf[n] = 0;
8547dd7cddfSDavid du Colombier pp = slot + SLOTNO(c);
8557dd7cddfSDavid du Colombier if(!pp->occupied)
8567dd7cddfSDavid du Colombier error(Eio);
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier /* set vpp on card */
8597dd7cddfSDavid du Colombier if(strncmp(buf, "vpp", 3) == 0)
8607dd7cddfSDavid du Colombier wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
8617dd7cddfSDavid du Colombier return n;
862219b2ee8SDavid du Colombier case Qmem:
863219b2ee8SDavid du Colombier case Qattr:
864219b2ee8SDavid du Colombier pp = slot + SLOTNO(c);
865219b2ee8SDavid du Colombier if(pp->occupied == 0 || pp->enabled == 0)
866219b2ee8SDavid du Colombier error(Eio);
8677dd7cddfSDavid du Colombier n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
868219b2ee8SDavid du Colombier if(n < 0)
869219b2ee8SDavid du Colombier error(Eio);
870219b2ee8SDavid du Colombier return n;
871219b2ee8SDavid du Colombier }
8727dd7cddfSDavid du Colombier error(Ebadarg);
8737dd7cddfSDavid du Colombier return -1; /* not reached */
8747dd7cddfSDavid du Colombier }
8757dd7cddfSDavid du Colombier
8767dd7cddfSDavid du Colombier Dev i82365devtab = {
8777dd7cddfSDavid du Colombier 'y',
8787dd7cddfSDavid du Colombier "i82365",
8797dd7cddfSDavid du Colombier
8809a747e4fSDavid du Colombier devreset,
8817dd7cddfSDavid du Colombier devinit,
8829a747e4fSDavid du Colombier devshutdown,
8837dd7cddfSDavid du Colombier i82365attach,
8847dd7cddfSDavid du Colombier i82365walk,
8857dd7cddfSDavid du Colombier i82365stat,
8867dd7cddfSDavid du Colombier i82365open,
8877dd7cddfSDavid du Colombier devcreate,
8887dd7cddfSDavid du Colombier i82365close,
8897dd7cddfSDavid du Colombier i82365read,
8907dd7cddfSDavid du Colombier devbread,
8917dd7cddfSDavid du Colombier i82365write,
8927dd7cddfSDavid du Colombier devbwrite,
8937dd7cddfSDavid du Colombier devremove,
8947dd7cddfSDavid du Colombier devwstat,
8957dd7cddfSDavid du Colombier };
896219b2ee8SDavid du Colombier
897219b2ee8SDavid du Colombier /*
89880ee5cbfSDavid du Colombier * configure the PCMslot for IO. We assume very heavily that we can read
8997dd7cddfSDavid du Colombier * configuration info from the CIS. If not, we won't set up correctly.
900219b2ee8SDavid du Colombier */
901219b2ee8SDavid du Colombier static int
pcmio(int slotno,ISAConf * isa)902219b2ee8SDavid du Colombier pcmio(int slotno, ISAConf *isa)
903219b2ee8SDavid du Colombier {
904219b2ee8SDavid du Colombier uchar we, x, *p;
90580ee5cbfSDavid du Colombier PCMslot *pp;
90680ee5cbfSDavid du Colombier PCMconftab *ct, *et, *t;
907219b2ee8SDavid du Colombier PCMmap *m;
9087dd7cddfSDavid du Colombier int i, index, irq;
9097dd7cddfSDavid du Colombier char *cp;
910219b2ee8SDavid du Colombier
911219b2ee8SDavid du Colombier irq = isa->irq;
912219b2ee8SDavid du Colombier if(irq == 2)
913219b2ee8SDavid du Colombier irq = 9;
914219b2ee8SDavid du Colombier
915219b2ee8SDavid du Colombier if(slotno > nslot)
916219b2ee8SDavid du Colombier return -1;
917219b2ee8SDavid du Colombier pp = slot + slotno;
918219b2ee8SDavid du Colombier
919219b2ee8SDavid du Colombier if(!pp->occupied)
920219b2ee8SDavid du Colombier return -1;
921219b2ee8SDavid du Colombier
9227dd7cddfSDavid du Colombier et = &pp->ctab[pp->nctab];
9237dd7cddfSDavid du Colombier
9247dd7cddfSDavid du Colombier ct = 0;
9257dd7cddfSDavid du Colombier for(i = 0; i < isa->nopt; i++){
9267dd7cddfSDavid du Colombier if(strncmp(isa->opt[i], "index=", 6))
9277dd7cddfSDavid du Colombier continue;
9287dd7cddfSDavid du Colombier index = strtol(&isa->opt[i][6], &cp, 0);
9297dd7cddfSDavid du Colombier if(cp == &isa->opt[i][6] || index >= pp->nctab)
9307dd7cddfSDavid du Colombier return -1;
9317dd7cddfSDavid du Colombier ct = &pp->ctab[index];
9327dd7cddfSDavid du Colombier }
9337dd7cddfSDavid du Colombier
93415174232SDavid du Colombier if(ct == 0){
9357dd7cddfSDavid du Colombier /* assume default is right */
9367dd7cddfSDavid du Colombier if(pp->def)
9377dd7cddfSDavid du Colombier ct = pp->def;
9387dd7cddfSDavid du Colombier else
9397dd7cddfSDavid du Colombier ct = pp->ctab;
9407dd7cddfSDavid du Colombier
9417dd7cddfSDavid du Colombier /* try for best match */
9427dd7cddfSDavid du Colombier if(ct->nio == 0
9437dd7cddfSDavid du Colombier || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
9447dd7cddfSDavid du Colombier for(t = pp->ctab; t < et; t++)
9457dd7cddfSDavid du Colombier if(t->nio
9467dd7cddfSDavid du Colombier && t->io[0].start == isa->port
9477dd7cddfSDavid du Colombier && ((1<<irq) & t->irqs)){
9487dd7cddfSDavid du Colombier ct = t;
949219b2ee8SDavid du Colombier break;
950219b2ee8SDavid du Colombier }
9517dd7cddfSDavid du Colombier }
9527dd7cddfSDavid du Colombier if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
9537dd7cddfSDavid du Colombier for(t = pp->ctab; t < et; t++)
9547dd7cddfSDavid du Colombier if(t->nio && ((1<<irq) & t->irqs)){
9557dd7cddfSDavid du Colombier ct = t;
956219b2ee8SDavid du Colombier break;
9577dd7cddfSDavid du Colombier }
9587dd7cddfSDavid du Colombier }
9597dd7cddfSDavid du Colombier if(ct->nio == 0){
9607dd7cddfSDavid du Colombier for(t = pp->ctab; t < et; t++)
9617dd7cddfSDavid du Colombier if(t->nio){
9627dd7cddfSDavid du Colombier ct = t;
9637dd7cddfSDavid du Colombier break;
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier }
9667dd7cddfSDavid du Colombier }
967219b2ee8SDavid du Colombier
9687dd7cddfSDavid du Colombier if(ct == et || ct->nio == 0)
9697dd7cddfSDavid du Colombier return -1;
9707dd7cddfSDavid du Colombier if(isa->port == 0 && ct->io[0].start == 0)
971219b2ee8SDavid du Colombier return -1;
972219b2ee8SDavid du Colombier
973219b2ee8SDavid du Colombier /* route interrupts */
974219b2ee8SDavid du Colombier isa->irq = irq;
975219b2ee8SDavid du Colombier wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
976219b2ee8SDavid du Colombier
977219b2ee8SDavid du Colombier /* set power and enable device */
978219b2ee8SDavid du Colombier x = vcode(ct->vpp1);
979219b2ee8SDavid du Colombier wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
980219b2ee8SDavid du Colombier
981219b2ee8SDavid du Colombier /* 16-bit data path */
982219b2ee8SDavid du Colombier if(ct->bit16)
9837dd7cddfSDavid du Colombier x = Ftiming|Fiocs16|Fwidth16;
984219b2ee8SDavid du Colombier else
9857dd7cddfSDavid du Colombier x = Ftiming;
9867dd7cddfSDavid du Colombier if(ct->nio == 2 && ct->io[1].start)
9877dd7cddfSDavid du Colombier x |= x<<4;
9887dd7cddfSDavid du Colombier wrreg(pp, Rio, x);
989219b2ee8SDavid du Colombier
9909a747e4fSDavid du Colombier /*
9919a747e4fSDavid du Colombier * enable io port map 0
9929a747e4fSDavid du Colombier * the 'top' register value includes the last valid address
9939a747e4fSDavid du Colombier */
994219b2ee8SDavid du Colombier if(isa->port == 0)
9957dd7cddfSDavid du Colombier isa->port = ct->io[0].start;
996219b2ee8SDavid du Colombier we = rdreg(pp, Rwe);
997219b2ee8SDavid du Colombier wrreg(pp, Riobtm0lo, isa->port);
998219b2ee8SDavid du Colombier wrreg(pp, Riobtm0hi, isa->port>>8);
9997dd7cddfSDavid du Colombier i = isa->port+ct->io[0].len-1;
10007dd7cddfSDavid du Colombier wrreg(pp, Riotop0lo, i);
10017dd7cddfSDavid du Colombier wrreg(pp, Riotop0hi, i>>8);
10027dd7cddfSDavid du Colombier we |= 1<<6;
100315174232SDavid du Colombier if(ct->nio >= 2 && ct->io[1].start){
10047dd7cddfSDavid du Colombier wrreg(pp, Riobtm1lo, ct->io[1].start);
10057dd7cddfSDavid du Colombier wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
10067dd7cddfSDavid du Colombier i = ct->io[1].start+ct->io[1].len-1;
10077dd7cddfSDavid du Colombier wrreg(pp, Riotop1lo, i);
10087dd7cddfSDavid du Colombier wrreg(pp, Riotop1hi, i>>8);
10097dd7cddfSDavid du Colombier we |= 1<<7;
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier wrreg(pp, Rwe, we);
1012219b2ee8SDavid du Colombier
1013219b2ee8SDavid du Colombier /* only touch Rconfig if it is present */
101415174232SDavid du Colombier m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1);
101515174232SDavid du Colombier p = KADDR(m->isa + pp->cfg[0].caddr - m->ca);
101615174232SDavid du Colombier if(pp->cfg[0].cpresent & (1<<Rconfig)){
1017219b2ee8SDavid du Colombier /* Reset adapter */
1018219b2ee8SDavid du Colombier
10199a747e4fSDavid du Colombier /* set configuration and interrupt type.
10209a747e4fSDavid du Colombier * if level is possible on the card, use it.
10219a747e4fSDavid du Colombier */
1022219b2ee8SDavid du Colombier x = ct->index;
10239a747e4fSDavid du Colombier if(ct->irqtype & 0x20)
1024219b2ee8SDavid du Colombier x |= Clevel;
1025219b2ee8SDavid du Colombier
102615174232SDavid du Colombier /* enable the device, enable address decode and
102715174232SDavid du Colombier * irq enable.
102815174232SDavid du Colombier */
102915174232SDavid du Colombier x |= Cfunc|Cdecode|Cirq;
103015174232SDavid du Colombier
103115174232SDavid du Colombier p[0] = x;
103215174232SDavid du Colombier //delay(5);
103315174232SDavid du Colombier microdelay(40);
1034219b2ee8SDavid du Colombier }
103515174232SDavid du Colombier
103615174232SDavid du Colombier if(pp->cfg[0].cpresent & (1<<Riobase0)){
103715174232SDavid du Colombier /* set up the iobase 0 */
103815174232SDavid du Colombier p[Riobase0 << 1] = isa->port;
103915174232SDavid du Colombier p[Riobase1 << 1] = isa->port >> 8;
104015174232SDavid du Colombier }
104115174232SDavid du Colombier
104215174232SDavid du Colombier if(pp->cfg[0].cpresent & (1<<Riosize))
104315174232SDavid du Colombier p[Riosize << 1] = ct->io[0].len;
104415174232SDavid du Colombier pcmunmap(slotno, m);
1045219b2ee8SDavid du Colombier return 0;
1046219b2ee8SDavid du Colombier }
1047