tinysmb devoptab fix - allow fread sizes > 7236
[libogc.git] / libogc / exi.c
blob0cf2bdbf1e98f853c0353121f93cd4515b49f05b
1 /*-------------------------------------------------------------
3 exi.c -- EXI subsystem
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include "asm.h"
35 #include "irq.h"
36 #include "processor.h"
37 #include "spinlock.h"
38 #include "exi.h"
40 //#define _EXI_DEBUG
42 #define EXI_LOCK_DEVS 32
44 #define EXI_MAX_CHANNELS 3
45 #define EXI_MAX_DEVICES 3
47 #define EXI_DEVICE0 0x0080
48 #define EXI_DEVICE1 0x0100
49 #define EXI_DEVICE2 0x0200
51 #define EXI_EXI_IRQ 0x0002
52 #define EXI_TC_IRQ 0x0008
53 #define EXI_EXT_IRQ 0x0800
54 #define EXI_EXT_BIT 0x1000
56 #define _SHIFTL(v, s, w) \
57 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
58 #define _SHIFTR(v, s, w) \
59 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
62 struct _lck_dev {
63 lwp_node node;
64 u32 dev;
65 EXICallback unlockcb;
68 typedef struct _exibus_priv {
69 EXICallback CallbackEXI;
70 EXICallback CallbackTC;
71 EXICallback CallbackEXT;
73 u32 imm_len;
74 void *imm_buff;
75 u32 lockeddev;
76 u32 flags;
77 u32 lck_cnt;
78 u32 exi_id;
79 u64 exi_idtime;
80 lwp_queue lckd_dev;
81 u32 lckd_dev_bits;
82 } exibus_priv;
84 static lwp_queue _lckdev_queue;
85 static struct _lck_dev lckdevs[EXI_LOCK_DEVS];
86 static exibus_priv eximap[EXI_MAX_CHANNELS];
87 static u64 last_exi_idtime[EXI_MAX_CHANNELS];
89 static u32 exi_id_serport1 = 0;
91 static u32 exi_uart_chan = EXI_CHANNEL_0;
92 static u32 exi_uart_dev = EXI_DEVICE_0;
93 static u32 exi_uart_barnacle_enabled = 0;
94 static u32 exi_uart_enabled = 0;
96 static void __exi_irq_handler(u32,void *);
97 static void __tc_irq_handler(u32,void *);
98 static void __ext_irq_handler(u32,void *);
100 #if defined(HW_DOL)
101 static vu32* const _exiReg = (u32*)0xCC006800;
102 #elif defined(HW_RVL)
103 static vu32* const _exiReg = (u32*)0xCD006800;
104 #else
105 #error HW model unknown.
106 #endif
108 extern void __UnmaskIrq(u32);
109 extern void __MaskIrq(u32);
111 static __inline__ void __exi_clearirqs(s32 nChn,u32 nEXIIrq,u32 nTCIrq,u32 nEXTIrq)
113 u32 d;
114 #ifdef _EXI_DEBUG
115 printf("__exi_clearirqs(%d,%d,%d,%d)\n",nChn,nEXIIrq,nTCIrq,nEXTIrq);
116 #endif
117 d = (_exiReg[nChn*5]&~(EXI_EXI_IRQ|EXI_TC_IRQ|EXI_EXT_IRQ));
118 if(nEXIIrq) d |= EXI_EXI_IRQ;
119 if(nTCIrq) d |= EXI_TC_IRQ;
120 if(nEXTIrq) d |= EXI_EXT_IRQ;
121 _exiReg[nChn*5] = d;
124 static __inline__ void __exi_setinterrupts(s32 nChn,exibus_priv *exi)
126 exibus_priv *pexi = &eximap[EXI_CHANNEL_2];
127 #ifdef _EXI_DEBUG
128 printf("__exi_setinterrupts(%d,%p)\n",nChn,exi);
129 #endif
130 if(nChn==EXI_CHANNEL_0) {
131 __MaskIrq((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI2_EXI)));
132 if(!(exi->flags&EXI_FLAG_LOCKED) && (exi->CallbackEXI || pexi->CallbackEXI))
133 __UnmaskIrq((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI2_EXI)));
134 } else if(nChn==EXI_CHANNEL_1) {
135 __MaskIrq(IRQMASK(IRQ_EXI1_EXI));
136 if(!(exi->flags&EXI_FLAG_LOCKED) && exi->CallbackEXI) __UnmaskIrq(IRQMASK(IRQ_EXI1_EXI));
137 } else if(nChn==EXI_CHANNEL_2) { //explicitly use of channel 2 only if debugger is attached.
138 __MaskIrq(IRQMASK(IRQ_EXI0_EXI));
139 if(!(exi->flags&EXI_FLAG_LOCKED) && IRQ_GetHandler(IRQ_PI_DEBUG)) __UnmaskIrq(IRQMASK(IRQ_EXI2_EXI));
143 static void __exi_initmap(exibus_priv *exim)
145 s32 i;
146 exibus_priv *m;
148 __lwp_queue_initialize(&_lckdev_queue,lckdevs,EXI_LOCK_DEVS,sizeof(struct _lck_dev));
150 for(i=0;i<EXI_MAX_CHANNELS;i++) {
151 m = &exim[i];
152 m->CallbackEXI = NULL;
153 m->CallbackEXT = NULL;
154 m->CallbackTC = NULL;
155 m->imm_buff = NULL;
156 m->exi_id = 0;
157 m->exi_idtime = 0;
158 m->flags = 0;
159 m->imm_len = 0;
160 m->lck_cnt = 0;
161 m->lockeddev = 0;
162 m->lckd_dev_bits = 0;
163 __lwp_queue_init_empty(&m->lckd_dev);
167 static s32 __exi_probe(s32 nChn)
169 u64 time;
170 s32 ret = 1;
171 u32 level;
172 u32 val;
173 exibus_priv *exi = &eximap[nChn];
174 #ifdef _EXI_DEBUG
175 printf("__exi_probe(%d)\n",nChn);
176 #endif
177 _CPU_ISR_Disable(level);
178 val = _exiReg[nChn*5];
179 if(!(exi->flags&EXI_FLAG_ATTACH)) {
180 if(val&EXI_EXT_IRQ) {
181 __exi_clearirqs(nChn,0,0,1);
182 exi->exi_idtime = 0;
183 last_exi_idtime[nChn] = 0;
185 if(_exiReg[nChn*5]&EXI_EXT_BIT) {
186 time = gettime();
187 if(last_exi_idtime[nChn]==0) last_exi_idtime[nChn] = time;
188 if((val=diff_usec(last_exi_idtime[nChn],time)+10)<30) ret = 0;
189 else ret = 1;
190 #ifdef _EXI_DEBUG
191 printf("val = %u, ret = %d, last_exi_idtime[chn] = %llu\n",val,ret,last_exi_idtime[nChn]);
192 #endif
193 _CPU_ISR_Restore(level);
194 return ret;
195 } else {
196 exi->exi_idtime = 0;
197 last_exi_idtime[nChn] = 0;
198 _CPU_ISR_Restore(level);
199 return 0;
203 if(!(_exiReg[nChn*5]&EXI_EXT_BIT) || (_exiReg[nChn*5]&EXI_EXT_IRQ)) {
204 exi->exi_idtime = 0;
205 last_exi_idtime[nChn] = 0;
206 ret = 0;
208 _CPU_ISR_Restore(level);
209 return ret;
212 static s32 __exi_attach(s32 nChn,EXICallback ext_cb)
214 s32 ret;
215 u32 level;
216 exibus_priv *exi = &eximap[nChn];
217 #ifdef _EXI_DEBUG
218 printf("__exi_attach(%d,%p)\n",nChn,ext_cb);
219 #endif
220 _CPU_ISR_Disable(level);
221 ret = 0;
222 if(!(exi->flags&EXI_FLAG_ATTACH)) {
223 if(__exi_probe(nChn)==1) {
224 __exi_clearirqs(nChn,1,0,0);
225 exi->CallbackEXT = ext_cb;
226 __UnmaskIrq(((IRQMASK(IRQ_EXI0_EXT))>>(nChn*3)));
227 exi->flags |= EXI_FLAG_ATTACH;
228 ret = 1;
231 _CPU_ISR_Restore(level);
232 return ret;
235 s32 EXI_Lock(s32 nChn,s32 nDev,EXICallback unlockCB)
237 u32 level;
238 struct _lck_dev *lckd;
239 exibus_priv *exi = &eximap[nChn];
240 #ifdef _EXI_DEBUG
241 printf("EXI_Lock(%d,%d,%p)\n",nChn,nDev,unlockCB);
242 #endif
243 _CPU_ISR_Disable(level);
244 if(exi->flags&EXI_FLAG_LOCKED) {
245 if(unlockCB && !(exi->lckd_dev_bits&(1<<nDev))) {
246 lckd = (struct _lck_dev*)__lwp_queue_getI(&_lckdev_queue);
247 if(lckd) {
248 exi->lck_cnt++;
249 exi->lckd_dev_bits |= (1<<nDev);
250 lckd->dev = nDev;
251 lckd->unlockcb = unlockCB;
252 __lwp_queue_appendI(&exi->lckd_dev,&lckd->node);
255 _CPU_ISR_Restore(level);
256 return 0;
259 exi->lockeddev = nDev;
260 exi->flags |= EXI_FLAG_LOCKED;
261 __exi_setinterrupts(nChn,exi);
263 _CPU_ISR_Restore(level);
264 return 1;
267 s32 EXI_Unlock(s32 nChn)
269 u32 level,dev;
270 EXICallback cb;
271 struct _lck_dev *lckd;
272 exibus_priv *exi = &eximap[nChn];
273 #ifdef _EXI_DEBUG
274 printf("EXI_Unlock(%d)\n",nChn);
275 #endif
276 _CPU_ISR_Disable(level);
277 if(!(exi->flags&EXI_FLAG_LOCKED)) {
278 _CPU_ISR_Restore(level);
279 return 0;
282 exi->flags &= ~EXI_FLAG_LOCKED;
283 __exi_setinterrupts(nChn,exi);
285 if(!exi->lck_cnt) {
286 _CPU_ISR_Restore(level);
287 return 1;
290 exi->lck_cnt--;
291 lckd = (struct _lck_dev*)__lwp_queue_getI(&exi->lckd_dev);
292 __lwp_queue_appendI(&_lckdev_queue,&lckd->node);
294 cb = lckd->unlockcb;
295 dev = lckd->dev;
296 exi->lckd_dev_bits &= ~(1<<dev);
297 if(cb) cb(nChn,dev);
299 _CPU_ISR_Restore(level);
300 return 1;
303 s32 EXI_Select(s32 nChn,s32 nDev,s32 nFrq)
305 u32 val;
306 u32 level;
307 exibus_priv *exi = &eximap[nChn];
308 #ifdef _EXI_DEBUG
309 printf("EXI_Select(%d,%d,%d)\n",nChn,nDev,nFrq);
310 #endif
311 _CPU_ISR_Disable(level);
313 if(exi->flags&EXI_FLAG_SELECT) {
314 #ifdef _EXI_DEBUG
315 printf("EXI_Select(): allready selected.\n");
316 #endif
317 _CPU_ISR_Restore(level);
318 return 0;
321 if(nChn!=EXI_CHANNEL_2) {
322 if(nDev==EXI_DEVICE_0 && !(exi->flags&EXI_FLAG_ATTACH)) {
323 if(__exi_probe(nChn)==0) {
324 _CPU_ISR_Restore(level);
325 return 0;
328 if(!(exi->flags&EXI_FLAG_LOCKED) || exi->lockeddev!=nDev) {
329 #ifdef _EXI_DEBUG
330 printf("EXI_Select(): not locked or wrong dev(%d).\n",exi->lockeddev);
331 #endif
332 _CPU_ISR_Restore(level);
333 return 0;
337 exi->flags |= EXI_FLAG_SELECT;
338 val = _exiReg[nChn*5];
339 val = (val&0x405)|(0x80<<nDev)|(nFrq<<4);
340 _exiReg[nChn*5] = val;
342 if(exi->flags&EXI_FLAG_ATTACH) {
343 if(nChn==EXI_CHANNEL_0) __MaskIrq(IRQMASK(IRQ_EXI0_EXT));
344 else if(nChn==EXI_CHANNEL_1) __MaskIrq(IRQMASK(IRQ_EXI1_EXT));
347 _CPU_ISR_Restore(level);
348 return 1;
351 s32 EXI_SelectSD(s32 nChn,s32 nDev,s32 nFrq)
353 u32 val,id;
354 s32 ret;
355 u32 level;
356 exibus_priv *exi = &eximap[nChn];
357 #ifdef _EXI_DEBUG
358 printf("EXI_SelectSD(%d,%d,%d)\n",nChn,nDev,nFrq);
359 #endif
360 _CPU_ISR_Disable(level);
362 if(exi->flags&EXI_FLAG_SELECT) {
363 #ifdef _EXI_DEBUG
364 printf("EXI_SelectSD(): allready selected.\n");
365 #endif
366 _CPU_ISR_Restore(level);
367 return 0;
370 if(nChn!=EXI_CHANNEL_2) {
371 if(nDev==EXI_DEVICE_0 && !(exi->flags&EXI_FLAG_ATTACH)) {
372 if((ret=__exi_probe(nChn))==1) {
373 if(!exi->exi_idtime) ret = EXI_GetID(nChn,EXI_DEVICE_0,&id);
375 if(ret==0) {
376 _CPU_ISR_Restore(level);
377 return 0;
380 if(!(exi->flags&EXI_FLAG_LOCKED) || exi->lockeddev!=nDev) {
381 #ifdef _EXI_DEBUG
382 printf("EXI_SelectSD(): not locked or wrong dev(%d).\n",exi->lockeddev);
383 #endif
384 _CPU_ISR_Restore(level);
385 return 0;
389 exi->flags |= EXI_FLAG_SELECT;
390 val = _exiReg[nChn*5];
391 val = (val&0x405)|(nFrq<<4);
392 _exiReg[nChn*5] = val;
394 if(exi->flags&EXI_FLAG_ATTACH) {
395 if(nChn==EXI_CHANNEL_0) __MaskIrq(IRQMASK(IRQ_EXI0_EXT));
396 else if(nChn==EXI_CHANNEL_1) __MaskIrq(IRQMASK(IRQ_EXI1_EXT));
399 _CPU_ISR_Restore(level);
400 return 1;
403 s32 EXI_Deselect(s32 nChn)
405 u32 val;
406 u32 level;
407 exibus_priv *exi = &eximap[nChn];
408 #ifdef _EXI_DEBUG
409 printf("EXI_Deselect(%d)\n",nChn);
410 #endif
411 _CPU_ISR_Disable(level);
413 if(!(exi->flags&EXI_FLAG_SELECT)) {
414 _CPU_ISR_Restore(level);
415 return 0;
418 exi->flags &= ~EXI_FLAG_SELECT;
419 val = _exiReg[nChn*5];
420 _exiReg[nChn*5] = (val&0x405);
422 if(exi->flags&EXI_FLAG_ATTACH) {
423 if(nChn==EXI_CHANNEL_0) __UnmaskIrq(IRQMASK(IRQ_EXI0_EXT));
424 else if(nChn==EXI_CHANNEL_1) __UnmaskIrq(IRQMASK(IRQ_EXI1_EXT));
427 if(nChn!=EXI_CHANNEL_2 && val&EXI_DEVICE0) {
428 if(__exi_probe(nChn)==0) {
429 _CPU_ISR_Restore(level);
430 return 0;
433 _CPU_ISR_Restore(level);
434 return 1;
437 s32 EXI_Sync(s32 nChn)
439 u8 *buf;
440 s32 ret;
441 u32 level,i,cnt,val;
442 exibus_priv *exi = &eximap[nChn];
443 #ifdef _EXI_DEBUG
444 printf("EXI_Sync(%d)\n",nChn);
445 #endif
446 while(_exiReg[nChn*5+3]&0x0001);
448 _CPU_ISR_Disable(level);
450 ret = 0;
451 if(exi->flags&EXI_FLAG_SELECT && exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM)) {
452 if(exi->flags&EXI_FLAG_IMM) {
453 cnt = exi->imm_len;
454 buf = exi->imm_buff;
455 if(buf && cnt>0) {
456 val = _exiReg[nChn*5+4];
457 for(i=0;i<cnt;i++) ((u8*)buf)[i] = (val>>((3-i)*8))&0xFF;
460 exi->flags &= ~(EXI_FLAG_DMA|EXI_FLAG_IMM);
461 ret = 1;
463 _CPU_ISR_Restore(level);
464 return ret;
467 s32 EXI_Imm(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb)
469 u32 level;
470 u32 value,i;
471 exibus_priv *exi = &eximap[nChn];
472 #ifdef _EXI_DEBUG
473 printf("EXI_Imm(%d,%p,%d,%d,%p)\n",nChn,pData,nLen,nMode,tc_cb);
474 #endif
475 _CPU_ISR_Disable(level);
477 if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM) || !(exi->flags&EXI_FLAG_SELECT)) {
478 _CPU_ISR_Restore(level);
479 return 0;
482 exi->CallbackTC = tc_cb;
483 if(tc_cb) {
484 __exi_clearirqs(nChn,0,1,0);
485 __UnmaskIrq(IRQMASK((IRQ_EXI0_TC+(nChn*3))));
487 exi->flags |= EXI_FLAG_IMM;
489 exi->imm_buff = pData;
490 exi->imm_len = nLen;
491 if(nMode!=EXI_READ) {
492 for(i=0,value=0;i<nLen;i++) value |= (((u8*)pData)[i])<<((3-i)*8);
493 _exiReg[nChn*5+4] = value;
495 if(nMode==EXI_WRITE) exi->imm_len = 0;
497 _exiReg[nChn*5+3] = (((nLen-1)&0x03)<<4)|((nMode&0x03)<<2)|0x01;
499 _CPU_ISR_Restore(level);
500 return 1;
503 s32 EXI_ImmEx(s32 nChn,void *pData,u32 nLen,u32 nMode)
505 u8 *buf = pData;
506 u32 tc;
507 s32 ret = 0;
508 #ifdef _EXI_DEBUG
509 printf("EXI_ImmEx(%d,%p,%d,%d)\n",nChn,pData,nLen,nMode);
510 #endif
511 while(nLen) {
512 ret = 0;
513 tc = nLen;
514 if(tc>4) tc = 4;
516 if(!EXI_Imm(nChn,buf,tc,nMode,NULL)) break;
517 if(!EXI_Sync(nChn)) break;
518 nLen -= tc;
519 buf += tc;
521 ret = 1;
523 return ret;
526 s32 EXI_Dma(s32 nChn,void *pData,u32 nLen,u32 nMode,EXICallback tc_cb)
528 u32 level;
529 exibus_priv *exi = &eximap[nChn];
530 #ifdef _EXI_DEBUG
531 printf("EXI_Dma(%d,%p,%d,%d,%p)\n",nChn,pData,nLen,nMode,tc_cb);
532 #endif
533 _CPU_ISR_Disable(level);
535 if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM) || !(exi->flags&EXI_FLAG_SELECT)) {
536 #ifdef _EXI_DEBUG
537 printf("EXI_Dma(%04x): abort\n",exi->flags);
538 #endif
539 _CPU_ISR_Restore(level);
540 return 0;
542 #ifdef _EXI_DEBUG
543 printf("EXI_Dma(tccb: %p)\n",tc_cb);
544 #endif
545 exi->CallbackTC = tc_cb;
546 if(tc_cb) {
547 __exi_clearirqs(nChn,0,1,0);
548 __UnmaskIrq((IRQMASK((IRQ_EXI0_TC+(nChn*3)))));
551 exi->imm_buff = NULL;
552 exi->imm_len = 0;
553 exi->flags |= EXI_FLAG_DMA;
555 _exiReg[nChn*5+1] = (u32)pData&0x03FFFFE0;
556 _exiReg[nChn*5+2] = nLen;
557 _exiReg[nChn*5+3] = ((nMode&0x03)<<2)|0x03;
559 _CPU_ISR_Restore(level);
560 return 1;
563 s32 EXI_GetState(s32 nChn)
565 exibus_priv *exi = &eximap[nChn];
566 return exi->flags;
569 static s32 __unlocked_handler(s32 nChn,s32 nDev)
571 u32 nId;
572 #ifdef _EXI_DEBUG
573 printf("__unlocked_handler(%d,%d)\n",nChn,nDev);
574 #endif
575 EXI_GetID(nChn,nDev,&nId);
576 return 1;
579 s32 EXI_GetID(s32 nChn,s32 nDev,u32 *nId)
581 u64 idtime = 0;
582 s32 ret,lck;
583 u32 reg,level;
584 exibus_priv *exi = &eximap[nChn];
586 #ifdef _EXI_DEBUG
587 printf("EXI_GetID(exi_id = %d)\n",exi->exi_id);
588 #endif
589 if(nChn<EXI_CHANNEL_2 && nDev==EXI_DEVICE_0) {
590 if(__exi_probe(nChn)==0) return 0;
591 if(exi->exi_idtime==last_exi_idtime[nChn]) {
592 #ifdef _EXI_DEBUG
593 printf("EXI_GetID(exi_id = %d)\n",exi->exi_id);
594 #endif
595 *nId = exi->exi_id;
596 return 1;
598 #ifdef _EXI_DEBUG
599 printf("EXI_GetID(setting interrupts,%08x)\n",exi->flags);
600 #endif
601 if(__exi_attach(nChn,NULL)==0) return 0;
602 idtime = last_exi_idtime[nChn];
604 #ifdef _EXI_DEBUG
605 printf("EXI_GetID(interrupts set)\n");
606 #endif
607 lck = 0;
608 if(nChn<EXI_CHANNEL_2 && nDev==EXI_DEVICE_0) lck = 1;
610 if(lck) ret = EXI_Lock(nChn,nDev,__unlocked_handler);
611 else ret = EXI_Lock(nChn,nDev,NULL);
613 if(ret) {
614 if(EXI_Select(nChn,nDev,EXI_SPEED1MHZ)==1) {
615 reg = 0;
616 EXI_Imm(nChn,&reg,2,EXI_WRITE,NULL);
617 EXI_Sync(nChn);
618 EXI_Imm(nChn,nId,4,EXI_READ,NULL);
619 EXI_Sync(nChn);
620 EXI_Deselect(nChn);
621 EXI_Unlock(nChn);
625 if(nChn<EXI_CHANNEL_2 && nDev==EXI_DEVICE_0) {
626 ret = 0;
627 EXI_Detach(nChn);
629 _CPU_ISR_Disable(level);
630 if(idtime==last_exi_idtime[nChn]) {
631 exi->exi_idtime = idtime;
632 exi->exi_id = *nId;
633 ret = 1;
635 _CPU_ISR_Restore(level);
636 #ifdef _EXI_DEBUG
637 printf("EXI_GetID(exi_id = %d)\n",exi->exi_id);
638 #endif
640 return ret;
643 s32 EXI_Attach(s32 nChn,EXICallback ext_cb)
645 s32 ret;
646 u32 level;
647 exibus_priv *exi = &eximap[nChn];
648 #ifdef _EXI_DEBUG
649 printf("EXI_Attach(%d)\n",nChn);
650 #endif
651 EXI_Probe(nChn);
653 _CPU_ISR_Disable(level);
654 if(exi->exi_idtime) {
655 ret = __exi_attach(nChn,ext_cb);
656 } else
657 ret = 0;
658 _CPU_ISR_Restore(level);
659 return ret;
662 s32 EXI_Detach(s32 nChn)
664 u32 level;
665 s32 ret = 1;
666 exibus_priv *exi = &eximap[nChn];
667 #ifdef _EXI_DEBUG
668 printf("EXI_Detach(%d)\n",nChn);
669 #endif
670 _CPU_ISR_Disable(level);
671 if(exi->flags&EXI_FLAG_ATTACH) {
672 if(exi->flags&EXI_FLAG_LOCKED && exi->lockeddev!=EXI_DEVICE_0) ret = 0;
673 else {
674 exi->flags &= ~EXI_FLAG_ATTACH;
675 __MaskIrq(((IRQMASK(IRQ_EXI0_EXI)|IRQMASK(IRQ_EXI0_TC)|IRQMASK(IRQ_EXI0_EXT))>>(nChn*3)));
678 _CPU_ISR_Restore(level);
679 return ret;
682 EXICallback EXI_RegisterEXICallback(s32 nChn,EXICallback exi_cb)
684 u32 level;
685 EXICallback old = NULL;
686 exibus_priv *exi = &eximap[nChn];
687 #ifdef _EXI_DEBUG
688 printf("EXI_RegisterEXICallback(%d,%p)\n",nChn,exi_cb);
689 #endif
690 _CPU_ISR_Disable(level);
691 old = exi->CallbackEXI;
692 exi->CallbackEXI = exi_cb;
693 if(nChn==EXI_CHANNEL_2) __exi_setinterrupts(EXI_CHANNEL_0,&eximap[EXI_CHANNEL_0]);
694 else __exi_setinterrupts(nChn,exi);
695 _CPU_ISR_Restore(level);
696 return old;
699 s32 EXI_Probe(s32 nChn)
701 s32 ret;
702 u32 id;
703 exibus_priv *exi = &eximap[nChn];
704 #ifdef _EXI_DEBUG
705 printf("EXI_Probe(%d)\n",nChn);
706 #endif
707 if((ret=__exi_probe(nChn))==1) {
708 if(exi->exi_idtime==0) {
709 if(EXI_GetID(nChn,EXI_DEVICE_0,&id)==0) ret = 0;
712 return ret;
715 s32 EXI_ProbeEx(s32 nChn)
717 if(EXI_Probe(nChn)==1) return 1;
718 if(last_exi_idtime[nChn]==0) return -1;
719 return 0;
722 void EXI_ProbeReset()
724 last_exi_idtime[0] = 0;
725 last_exi_idtime[1] = 0;
727 eximap[0].exi_idtime = 0;
728 eximap[1].exi_idtime = 0;
730 __exi_probe(0);
731 __exi_probe(1);
732 EXI_GetID(EXI_CHANNEL_0,EXI_DEVICE_2,&exi_id_serport1);
735 void __exi_init()
737 #ifdef _EXI_DEBUG
738 printf("__exi_init(): init expansion system.\n");
739 #endif
740 __MaskIrq(IM_EXI);
742 _exiReg[0] = 0;
743 _exiReg[5] = 0;
744 _exiReg[10] = 0;
746 _exiReg[0] = 0x2000;
748 __exi_initmap(eximap);
750 IRQ_Request(IRQ_EXI0_EXI,__exi_irq_handler,NULL);
751 IRQ_Request(IRQ_EXI0_TC,__tc_irq_handler,NULL);
752 IRQ_Request(IRQ_EXI0_EXT,__ext_irq_handler,NULL);
753 IRQ_Request(IRQ_EXI1_EXI,__exi_irq_handler,NULL);
754 IRQ_Request(IRQ_EXI1_TC,__tc_irq_handler,NULL);
755 IRQ_Request(IRQ_EXI1_EXT,__ext_irq_handler,NULL);
756 IRQ_Request(IRQ_EXI2_EXI,__exi_irq_handler,NULL);
757 IRQ_Request(IRQ_EXI2_TC,__tc_irq_handler,NULL);
759 EXI_ProbeReset();
762 void __exi_irq_handler(u32 nIrq,void *pCtx)
764 u32 chan,dev;
765 exibus_priv *exi = NULL;
766 const u32 fact = 0x55555556;
768 chan = ((fact*(nIrq-IRQ_EXI0_EXI))>>1)&0x0f;
769 dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2);
771 exi = &eximap[chan];
772 __exi_clearirqs(chan,1,0,0);
774 if(!exi->CallbackEXI) return;
775 #ifdef _EXI_DEBUG
776 printf("__exi_irq_handler(%p)\n",exi->CallbackEXI);
777 #endif
778 exi->CallbackEXI(chan,dev);
781 void __tc_irq_handler(u32 nIrq,void *pCtx)
783 u32 cnt,len,d,chan,dev;
784 EXICallback tccb;
785 void *buf = NULL;
786 exibus_priv *exi = NULL;
787 const u32 fact = 0x55555556;
789 chan = ((fact*(nIrq-IRQ_EXI0_TC))>>1)&0x0f;
790 dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2);
792 exi = &eximap[chan];
793 __MaskIrq(IRQMASK(nIrq));
794 __exi_clearirqs(chan,0,1,0);
796 tccb = exi->CallbackTC;
797 #ifdef _EXI_DEBUG
798 printf("__tc_irq_handler(%p)\n",tccb);
799 #endif
800 if(!tccb) return;
802 exi->CallbackTC = NULL;
803 if(exi->flags&(EXI_FLAG_DMA|EXI_FLAG_IMM)) {
804 if(exi->flags&EXI_FLAG_IMM) {
805 len = exi->imm_len;
806 buf = exi->imm_buff;
807 if(len>0 && buf) {
808 d = _exiReg[chan*5+4];
809 if(d>0) {
810 for(cnt=0;cnt<len;cnt++) ((u8*)buf)[cnt] = (d>>((3-cnt)*8))&0xFF;
814 exi->flags &= ~(EXI_FLAG_DMA|EXI_FLAG_IMM);
816 tccb(chan,dev);
819 void __ext_irq_handler(u32 nIrq,void *pCtx)
822 u32 chan,dev;
823 exibus_priv *exi = NULL;
824 const u32 fact = 0x55555556;
826 chan = ((fact*(nIrq-IRQ_EXI0_EXT))>>1)&0x0f;
827 dev = _SHIFTR((_exiReg[chan*5]&0x380),8,2);
829 exi = &eximap[chan];
830 __MaskIrq(IRQMASK(nIrq));
831 __exi_clearirqs(chan,0,0,1);
833 exi->flags &= ~EXI_FLAG_ATTACH;
834 if(exi->CallbackEXT) exi->CallbackEXT(chan,dev);
835 #ifdef _EXI_DEBUG
836 printf("__ext_irq_handler(%p)\n",exi->CallbackEXT);
837 #endif
841 /* EXI UART stuff */
842 static s32 __probebarnacle(s32 chn,u32 dev,u32 *rev)
844 u32 ret,reg;
846 if(chn!=EXI_CHANNEL_2 && dev==EXI_DEVICE_0) {
847 if(EXI_Attach(chn,NULL)==0) return 0;
850 ret = 0;
851 if(EXI_Lock(chn,dev,NULL)==1) {
852 if(EXI_Select(chn,dev,EXI_SPEED1MHZ)==1) {
853 reg = 0x20011300;
854 if(EXI_Imm(chn,&reg,sizeof(u32),EXI_WRITE,NULL)==0) ret |= 0x0001;
855 if(EXI_Sync(chn)==0) ret |= 0x0002;
856 if(EXI_Imm(chn,rev,sizeof(u32),EXI_READ,NULL)==0) ret |= 0x0004;
857 if(EXI_Sync(chn)==0) ret |= 0x0008;
858 if(EXI_Deselect(chn)==0) ret |= 0x0010;
861 EXI_Unlock(chn);
864 if(chn!=EXI_CHANNEL_2 && dev==EXI_DEVICE_0) EXI_Detach(chn);
866 if(ret) return 0;
867 if((*rev+0x00010000)==0xffff) return 0;
869 return 1;
872 static s32 __queuelength()
874 u32 reg;
875 u8 len = 0;
877 if(EXI_Select(exi_uart_chan,exi_uart_dev,EXI_SPEED8MHZ)==0) return -1;
879 reg = 0x20010000;
880 EXI_Imm(exi_uart_chan,&reg,sizeof(u32),EXI_WRITE,NULL);
881 EXI_Sync(exi_uart_chan);
882 EXI_Imm(exi_uart_chan,&len,sizeof(u8),EXI_READ,NULL);
883 EXI_Sync(exi_uart_chan);
885 EXI_Deselect(exi_uart_chan);
887 return (16-len);
890 void __SYS_EnableBarnacle(s32 chn,u32 dev)
892 u32 id,rev;
894 if(EXI_GetID(chn,dev,&id)==0) return;
896 if(id==0x01020000 || id==0x0004 || id==0x80000010 || id==0x80000008
897 || id==0x80000004 || id==0xffff || id==0x80000020 || id==0x0020
898 || id==0x0010 || id==0x0008 || id==0x01010000 || id==0x04040404
899 || id==0x04021000 || id==0x03010000 || id==0x02020000
900 || id==0x04020300 || id==0x04020200 || id==0x04130000
901 || id==0x04120000 || id==0x04060000 || id==0x04220000) return;
903 if(__probebarnacle(chn,dev,&rev)==0) return;
906 exi_uart_chan = chn;
907 exi_uart_dev = dev;
908 exi_uart_barnacle_enabled = 0xa5ff005a;
909 exi_uart_enabled = 0xa5ff005a;
912 s32 InitializeUART()
914 if((exi_uart_enabled+0x5a010000)==0x005a) return 0;
916 exi_uart_chan = EXI_CHANNEL_0;
917 exi_uart_dev = EXI_DEVICE_1;
919 exi_uart_enabled = 0xa5ff005a;
920 return 0;
923 s32 WriteUARTN(void *buf,u32 len)
925 u8 *ptr;
926 u32 reg;
927 s32 ret,qlen,cnt;
929 if((exi_uart_enabled+0x5a010000)!=0x005a) return 2;
930 if(EXI_Lock(exi_uart_chan,exi_uart_dev,NULL)==0) return 0;
932 ptr = buf;
933 while((ptr-(u8*)buf)<len) {
934 if(*ptr=='\n') *ptr = '\r';
935 ptr++;
938 ret = 0;
939 ptr = buf;
940 while(len) {
941 if((qlen=__queuelength())<0) {
942 ret = 3;
943 break;
944 } else if(qlen>=12 || qlen>=len) {
945 if(EXI_Select(exi_uart_chan,exi_uart_dev,EXI_SPEED8MHZ)==0) {
946 ret = 3;
947 break;
950 reg = 0xa0010000;
951 EXI_Imm(exi_uart_chan,&reg,sizeof(u32),EXI_WRITE,NULL);
952 EXI_Sync(exi_uart_chan);
954 while(qlen>0 && len>0) {
955 cnt = 4;
956 if(qlen>=0x0004) {
957 if(len<4) cnt = len;
958 if(qlen<len) break;
960 EXI_Imm(exi_uart_chan,ptr,cnt,EXI_WRITE,NULL);
961 EXI_Sync(exi_uart_chan);
962 qlen -= cnt;
963 len -= cnt;
968 EXI_Deselect(exi_uart_chan);
971 EXI_Unlock(exi_uart_chan);
972 return ret;