PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
tty.c
Go to the documentation of this file.
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
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
21int ttyinit = 0;
22
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
37static struct tty_packet wbuf __attribute__((aligned(16)));
38static struct tty_packet rbuf __attribute__((aligned(16)));
39
41{
42 u32 read;
43 u32 write;
44 char buf[256];
45};
46
47struct 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
58static 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
71static int QueueEmpty(struct tty_queue *q)
72{
73 return READ_ONCE(q->read) == READ_ONCE(q->write);
74}
75
76static 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
84static 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
95void 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
135int 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
190int 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
207int 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}
Definition tty.c:48