Skip to content

Commit d1a988c

Browse files
committed
kernel: DECI2 TTY support
1 parent e1d1c08 commit d1a988c

File tree

3 files changed

+258
-1
lines changed

3 files changed

+258
-1
lines changed

ee/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ KERNEL_OBJS = ResetEE.o SetGsCrt.o $(EXEC_SYSCALLS) \
225225
EE_OBJS = $(KERNEL_OBJS) $(SIFCMD_OBJS) $(SIFRPC_OBJS) $(FILEIO_OBJS) \
226226
$(LOADFILE_OBJS) $(IOPHEAP_OBJS) $(IOPCONTROL_OBJS) $(ROM0_OBJS) $(CONFIG_OBJS) \
227227
$(GLUE_OBJS) $(SIO_OBJS) $(TIMER_OBJS) $(TIMER_ALARM_OBJS) $(DELAYTHREAD_OBJS) $(GETKERNEL_OBJS) \
228-
$(INITSYS_OBJS) $(KERNEL_UTIL_OBJS) deci2.o erl-support.o
228+
$(INITSYS_OBJS) $(KERNEL_UTIL_OBJS) deci2.o tty.o erl-support.o
229229

230230

231231
EE_OBJS += $(THREAD_OBJS) $(LIBOSD_OBJS) $(TLBFUNC_OBJS) $(ALARM_OBJS) $(EXIT_OBJS) $(SETUP_OBJS) setup_syscalls.o debug.o

ee/kernel/include/tty.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
# _____ ___ ____ ___ ____
3+
# ____| | ____| | | |____|
4+
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5+
#-----------------------------------------------------------------------
6+
# Licenced under Academic Free License version 2.0
7+
# Review ps2sdk README & LICENSE files for further details.
8+
*/
9+
10+
/**
11+
* @file
12+
* DECI2 TTY
13+
*/
14+
15+
#ifndef TTY_H_
16+
#define TTY_H_
17+
18+
extern int ttyinit;
19+
20+
int sceTtyInit();
21+
int sceTtyWrite(const char *buf, int len);
22+
int sceTtyRead(char *buf, int len);
23+
24+
#endif // TTY_H_

ee/kernel/src/tty.c

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*
2+
# _____ ___ ____ ___ ____
3+
# ____| | ____| | | |____|
4+
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5+
#-----------------------------------------------------------------------
6+
# Licenced under Academic Free License version 2.0
7+
# Review ps2sdk README & LICENSE files for further details.
8+
*/
9+
10+
/**
11+
* @file
12+
* DECI2 TTY
13+
*/
14+
15+
#include "kernel.h"
16+
#include "deci2.h"
17+
18+
#define READ_ONCE(x) (*(const volatile typeof(x) *)(&x))
19+
#define WRITE_ONCE(x, val) (*(volatile typeof(x) *)(&x) = (val))
20+
21+
int ttyinit = 0;
22+
23+
struct tty_packet
24+
{
25+
/* standard deci2 header */
26+
u16 length;
27+
u16 reserved;
28+
u16 protocol;
29+
u8 source;
30+
u8 destination;
31+
32+
/* TTYP */
33+
u32 ttyp_reserved;
34+
char buf[256];
35+
};
36+
37+
static struct tty_packet wbuf __attribute__((aligned(16)));
38+
static struct tty_packet rbuf __attribute__((aligned(16)));
39+
40+
struct tty_queue
41+
{
42+
u32 read;
43+
u32 write;
44+
char buf[256];
45+
};
46+
47+
struct tinfo
48+
{
49+
int socket;
50+
int wlen;
51+
int rlen;
52+
int writing;
53+
char *wptr;
54+
char *rptr;
55+
struct tty_queue *read_queue;
56+
} tinfo;
57+
58+
static struct tty_queue *QueueInit()
59+
{
60+
static struct tty_queue q;
61+
62+
q.read = 0;
63+
q.write = 0;
64+
65+
return &q;
66+
}
67+
68+
/* Attempt at safe spsc fifo without disabling interrupts
69+
* User thread spins on QueueEmpty waiting for Handler to push data */
70+
71+
static int QueueEmpty(struct tty_queue *q)
72+
{
73+
return READ_ONCE(q->read) == READ_ONCE(q->write);
74+
}
75+
76+
static void QueuePush(struct tty_queue *q, char c)
77+
{
78+
int w = READ_ONCE(q->write);
79+
80+
q->buf[w & 0xff] = c;
81+
WRITE_ONCE(q->write, w + 1);
82+
}
83+
84+
static char QueuePop(struct tty_queue *q)
85+
{
86+
int r = READ_ONCE(q->read);
87+
char ret;
88+
89+
ret = q->buf[r & 0xff];
90+
WRITE_ONCE(q->read, r + 1);
91+
92+
return ret;
93+
}
94+
95+
void sceTtyHandler(int event, int param, void *opt)
96+
{
97+
struct tinfo *tinfo = opt;
98+
struct tty_packet *pkt;
99+
int ret;
100+
101+
switch (event) {
102+
case DECI2_READ:
103+
case DECI2_READ_DONE:
104+
if (param) {
105+
ret = sceDeci2ExRecv(tinfo->socket, tinfo->rptr + tinfo->rlen, param);
106+
tinfo->rlen += ret;
107+
break;
108+
}
109+
110+
pkt = (struct tty_packet *)tinfo->rptr;
111+
if (pkt->length > offsetof(struct tty_packet, buf)) {
112+
for (int i = 0; i < pkt->length - offsetof(struct tty_packet, buf); i++) {
113+
QueuePush(tinfo->read_queue, pkt->buf[i]);
114+
}
115+
}
116+
117+
tinfo->rlen = 0;
118+
break;
119+
case DECI2_WRITE:
120+
ret = sceDeci2ExSend(tinfo->socket, tinfo->wptr, tinfo->wlen);
121+
if (ret < 0) {
122+
tinfo->writing = 0;
123+
break;
124+
}
125+
126+
tinfo->wptr += ret;
127+
tinfo->wlen -= ret;
128+
break;
129+
case DECI2_WRITE_DONE:
130+
tinfo->writing = 0;
131+
break;
132+
}
133+
}
134+
135+
int sceTtyWrite(char *buf, int len)
136+
{
137+
struct tty_packet *pkt;
138+
int oldintr, ret, ssize;
139+
char *wp;
140+
141+
if (tinfo.writing) {
142+
return -1;
143+
}
144+
145+
oldintr = DIntr();
146+
147+
tinfo.writing = 1;
148+
tinfo.wptr = UNCACHED_SEG(&wbuf);
149+
pkt = UNCACHED_SEG(&wbuf);
150+
151+
ssize = 0;
152+
wp = pkt->buf;
153+
for (ret = 0; ret < len; ret++) {
154+
if (*buf == '\n') {
155+
*wp++ = '\r';
156+
ssize++;
157+
if (ssize >= 256)
158+
break;
159+
}
160+
161+
*wp++ = *buf++;
162+
ssize++;
163+
if (ssize >= 256)
164+
break;
165+
}
166+
167+
tinfo.wlen = ssize + offsetof(struct tty_packet, buf);
168+
pkt->length = tinfo.wlen;
169+
if (sceDeci2ReqSend(tinfo.socket, pkt->destination) < 0) {
170+
tinfo.writing = 0;
171+
if (oldintr) {
172+
EIntr();
173+
}
174+
175+
return -1;
176+
}
177+
178+
while (READ_ONCE(tinfo.writing)) {
179+
sceDeci2Poll(tinfo.socket);
180+
}
181+
182+
if (oldintr) {
183+
EIntr();
184+
}
185+
186+
return ret;
187+
}
188+
189+
190+
int sceTtyRead(char *buf, int len)
191+
{
192+
int i;
193+
194+
for (i = 0; i < len; i++) {
195+
while (QueueEmpty(tinfo.read_queue))
196+
;
197+
198+
buf[i] = QueuePop(tinfo.read_queue);
199+
if (buf[i] == '\n' || buf[i] == '\r') {
200+
break;
201+
}
202+
}
203+
204+
return i;
205+
}
206+
207+
int sceTtyInit()
208+
{
209+
struct tty_packet *pkt;
210+
211+
FlushCache(0);
212+
tinfo.socket = sceDeci2Open(0x210, &tinfo, sceTtyHandler);
213+
if (tinfo.socket < 0) {
214+
return 0;
215+
}
216+
217+
tinfo.writing = 0;
218+
tinfo.wlen = 0;
219+
tinfo.rptr = UNCACHED_SEG(&rbuf);
220+
tinfo.wptr = UNCACHED_SEG(&wbuf);
221+
222+
pkt = UNCACHED_SEG(&wbuf);
223+
pkt->protocol = 0x210;
224+
pkt->source = 'E';
225+
pkt->destination = 'H';
226+
227+
pkt->reserved = 0;
228+
pkt->ttyp_reserved = 0;
229+
230+
tinfo.read_queue = QueueInit();
231+
232+
return 1;
233+
}

0 commit comments

Comments
 (0)