PS2SDK
PS2 Homebrew Libraries
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 
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 }
kernel.h
tty_packet
Definition: tty.c:23
event
Definition: thcommon.h:71
tinfo
Definition: tty.c:47
deci2.h
__attribute__
Definition: gif_registers.h:38
tty_queue
Definition: tty.c:40