Diff markup
001 001
002 002
003 003
004 004
005 005
006 006
007 007
008 008
009 009
010 010
011 011
012 012
013 013
014 014
015 015
016 016
017 017
018 018
019 #include <sos/types.h> 019 #include <sos/types.h>
020 #include <sos/assert.h> 020 #include <sos/assert.h>
021 #include <sos/errno.h> 021 #include <sos/errno.h>
022 #include <sos/fs.h> 022 #include <sos/fs.h>
023 #include <sos/ksynch.h> 023 #include <sos/ksynch.h>
024 #include <sos/kwaitq.h> 024 #include <sos/kwaitq.h>
025 #include <sos/uaccess.h> 025 #include <sos/uaccess.h>
026 #include <sos/kmalloc.h> 026 #include <sos/kmalloc.h>
027 #include <sos/list.h> 027 #include <sos/list.h>
028 #include <sos/chardev.h> 028 #include <sos/chardev.h>
029 #include <drivers/devices.h> 029 #include <drivers/devices.h>
030 030
031 #include "tty.h" 031 #include "tty.h"
032 032
033 #define TTY_BUFFER_LEN 64 033 #define TTY_BUFFER_LEN 64
034 #define TTY_NAME_LEN 16 034 #define TTY_NAME_LEN 16
035 035
036 struct tty_device { 036 struct tty_device {
037 sos_ui32_t instance; 037 sos_ui32_t instance;
038 unsigned int open_count; 038 unsigned int open_count;
039 char buffer[TTY_BUFFER_LEN]; 039 char buffer[TTY_BUFFER_LEN];
040 unsigned int buffer_read; 040 unsigned int buffer_read;
041 unsigned int buffer_write; 041 unsigned int buffer_write;
042 struct sos_ksema sem; 042 struct sos_ksema sem;
043 struct sos_kwaitq wq; 043 struct sos_kwaitq wq;
044 sos_ret_t (*write)(char c); 044 sos_ret_t (*write)(char c);
045 unsigned int param; 045 unsigned int param;
046 struct tty_device *next, *prev; 046 struct tty_device *next, *prev;
047 }; 047 };
048 048
049 static struct tty_device *tty_device_list; 049 static struct tty_device *tty_device_list;
050 050
051 static struct tty_device * 051 static struct tty_device *
052 tty_device_find (sos_ui32_t instance) 052 tty_device_find (sos_ui32_t instance)
053 { 053 {
054 struct tty_device *t; 054 struct tty_device *t;
055 int n; 055 int n;
056 056
057 list_foreach (tty_device_list, t, n) 057 list_foreach (tty_device_list, t, n)
058 { 058 {
059 if (t->instance == instance) 059 if (t->instance == instance)
060 return t; 060 return t;
061 } 061 }
062 062
063 return NULL; 063 return NULL;
064 } 064 }
065 065
066 static sos_ret_t tty_read(struct sos_fs_opened 066 static sos_ret_t tty_read(struct sos_fs_opened_file *this,
067 sos_uaddr_t dest_buf 067 sos_uaddr_t dest_buf, sos_size_t *len)
068 { 068 {
069 sos_size_t count = 0; 069 sos_size_t count = 0;
070 struct tty_device *t; 070 struct tty_device *t;
071 sos_ret_t ret; 071 sos_ret_t ret;
072 072
073 t = (struct tty_device *) this->custom_data; 073 t = (struct tty_device *) this->custom_data;
074 074
075 if (*len == 0) 075 if (*len == 0)
076 return SOS_OK; 076 return SOS_OK;
077 077
078 while (1) 078 while (1)
079 { 079 {
080 char c; 080 char c;
081 081
082 082
083 sos_ksema_down (& t->sem, NULL); 083 sos_ksema_down (& t->sem, NULL);
084 084
085 085
086 086
087 if (t->buffer_read == t->buffer_write) 087 if (t->buffer_read == t->buffer_write)
088 { 088 {
089 sos_ksema_up (& t->sem); 089 sos_ksema_up (& t->sem);
090 sos_kwaitq_wait (& t->wq, NULL); 090 sos_kwaitq_wait (& t->wq, NULL);
091 091
092 092
093 093
094 continue; 094 continue;
095 } 095 }
096 096
097 c = t->buffer[t->buffer_read]; 097 c = t->buffer[t->buffer_read];
098 098
099 099
100 100
101 ret = sos_memcpy_to_user (dest_buf, 101 ret = sos_memcpy_to_user (dest_buf,
102 (sos_vaddr_t) 102 (sos_vaddr_t) & t->buffer[t->buffer_read],
103 sizeof (char)) 103 sizeof (char));
104 if (sizeof(char) != ret) 104 if (sizeof(char) != ret)
105 { 105 {
106 *len = count; 106 *len = count;
107 sos_ksema_up (& t->sem); 107 sos_ksema_up (& t->sem);
108 return ret; 108 return ret;
109 } 109 }
110 110
111 dest_buf++; 111 dest_buf++;
112 112
113 113
114 t->buffer_read++; 114 t->buffer_read++;
115 if (t->buffer_read == TTY_BUFFER_LEN) 115 if (t->buffer_read == TTY_BUFFER_LEN)
116 t->buffer_read = 0; 116 t->buffer_read = 0;
117 117
118 count++; 118 count++;
119 119
120 if (t->param & SOS_IOCTLPARAM_TTY_ECHO) 120 if (t->param & SOS_IOCTLPARAM_TTY_ECHO)
121 t->write (c); 121 t->write (c);
122 122
123 sos_ksema_up (& t->sem); 123 sos_ksema_up (& t->sem);
124 124
125 125
126 if (count == *len 126 if (count == *len
127 || (c == '\n' && t->param & SOS_IOCT 127 || (c == '\n' && t->param & SOS_IOCTLPARAM_TTY_CANON))
128 break; 128 break;
129 } 129 }
130 130
131 *len = count; 131 *len = count;
132 return SOS_OK; 132 return SOS_OK;
133 } 133 }
134 134
135 135
136 static sos_ret_t tty_write(struct sos_fs_opene 136 static sos_ret_t tty_write(struct sos_fs_opened_file *this,
137 sos_uaddr_t src_buf 137 sos_uaddr_t src_buf, sos_size_t *len)
138 { 138 {
139 struct tty_device *t; 139 struct tty_device *t;
140 char c; 140 char c;
141 int i; !! 141 unsigned int i;
142 sos_ret_t ret; 142 sos_ret_t ret;
143 143
144 t = (struct tty_device *) this->custom_data; 144 t = (struct tty_device *) this->custom_data;
145 145
146 for (i = 0; i < *len; i++) 146 for (i = 0; i < *len; i++)
147 { 147 {
148 ret = sos_memcpy_from_user ((sos_vaddr_t 148 ret = sos_memcpy_from_user ((sos_vaddr_t) & c, src_buf, sizeof(char));
149 if (sizeof(char) != ret) 149 if (sizeof(char) != ret)
150 { 150 {
151 *len = i; 151 *len = i;
152 return ret; 152 return ret;
153 } 153 }
154 154
155 sos_ksema_down (& t->sem, NULL); 155 sos_ksema_down (& t->sem, NULL);
156 t->write (c); 156 t->write (c);
157 sos_ksema_up (& t->sem); 157 sos_ksema_up (& t->sem);
158 158
159 src_buf++; 159 src_buf++;
160 } 160 }
161 161
162 return SOS_OK; 162 return SOS_OK;
163 } 163 }
164 164
165 165
166 static sos_ret_t tty_ioctl(struct sos_fs_opene 166 static sos_ret_t tty_ioctl(struct sos_fs_opened_file *this, int req_id,
167 sos_ui32_t req_arg) 167 sos_ui32_t req_arg)
168 { 168 {
169 struct tty_device *t; 169 struct tty_device *t;
170 170
171 if (req_arg != SOS_IOCTLPARAM_TTY_ECHO 171 if (req_arg != SOS_IOCTLPARAM_TTY_ECHO
172 && req_arg != SOS_IOCTLPARAM_TTY_CANON) 172 && req_arg != SOS_IOCTLPARAM_TTY_CANON)
173 return -SOS_EINVAL; 173 return -SOS_EINVAL;
174 174
175 t = (struct tty_device *) this->custom_data; 175 t = (struct tty_device *) this->custom_data;
176 176
177 sos_ksema_down (& t->sem, NULL); 177 sos_ksema_down (& t->sem, NULL);
178 178
179 switch (req_id) 179 switch (req_id)
180 { 180 {
181 case SOS_IOCTL_TTY_SETPARAM: 181 case SOS_IOCTL_TTY_SETPARAM:
182 t->param |= req_arg; 182 t->param |= req_arg;
183 break; 183 break;
184 184
185 case SOS_IOCTL_TTY_RESETPARAM: 185 case SOS_IOCTL_TTY_RESETPARAM:
186 t->param &= ~req_arg; 186 t->param &= ~req_arg;
187 break; 187 break;
188 188
189 default: 189 default:
190 sos_ksema_up (& t->sem); 190 sos_ksema_up (& t->sem);
191 return -SOS_EINVAL; 191 return -SOS_EINVAL;
192 } 192 }
193 193
194 sos_ksema_up (& t->sem); 194 sos_ksema_up (& t->sem);
195 195
196 return SOS_OK; 196 return SOS_OK;
197 } 197 }
198 198
199 static sos_ret_t tty_open(struct sos_fs_node 199 static sos_ret_t tty_open(struct sos_fs_node * fsnode,
200 struct sos_fs_opened 200 struct sos_fs_opened_file * of,
201 void * chardev_class 201 void * chardev_class_custom_data)
202 { 202 {
203 struct tty_device *t; 203 struct tty_device *t;
204 204
205 t = tty_device_find (fsnode->dev_id.device_i 205 t = tty_device_find (fsnode->dev_id.device_instance);
206 if (t == NULL) 206 if (t == NULL)
207 return -SOS_ENOENT; 207 return -SOS_ENOENT;
208 208
209 sos_ksema_down (& t->sem, NULL); 209 sos_ksema_down (& t->sem, NULL);
210 of->custom_data = t; 210 of->custom_data = t;
211 t->open_count ++; 211 t->open_count ++;
212 sos_ksema_up (& t->sem); 212 sos_ksema_up (& t->sem);
213 213
214 return SOS_OK; 214 return SOS_OK;
215 } 215 }
216 216
217 217
218 static sos_ret_t tty_close(struct sos_fs_opene 218 static sos_ret_t tty_close(struct sos_fs_opened_file *of,
219 void *custom_data) 219 void *custom_data)
220 { 220 {
221 struct tty_device *t; 221 struct tty_device *t;
222 222
223 t = (struct tty_device *) of->custom_data; 223 t = (struct tty_device *) of->custom_data;
224 224
225 sos_ksema_down (& t->sem, NULL); 225 sos_ksema_down (& t->sem, NULL);
226 t->open_count --; 226 t->open_count --;
227 sos_ksema_up (& t->sem); 227 sos_ksema_up (& t->sem);
228 228
229 return SOS_OK; 229 return SOS_OK;
230 } 230 }
231 231
232 void tty_add_chars (struct tty_device *t, cons 232 void tty_add_chars (struct tty_device *t, const char *s)
233 { 233 {
234 sos_ksema_down (& t->sem, NULL); 234 sos_ksema_down (& t->sem, NULL);
235 while (*s) 235 while (*s)
236 { 236 {
237 237
238 t->buffer[t->buffer_write] = *s; 238 t->buffer[t->buffer_write] = *s;
239 t->buffer_write++; 239 t->buffer_write++;
240 if (t->buffer_write == TTY_BUFFER_LEN) 240 if (t->buffer_write == TTY_BUFFER_LEN)
241 t->buffer_write = 0; 241 t->buffer_write = 0;
242 s++; 242 s++;
243 } 243 }
244 sos_ksema_up (& t->sem); 244 sos_ksema_up (& t->sem);
245 245
246 246
247 sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_A 247 sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_ALL, SOS_OK);
248 } 248 }
249 249
250 struct sos_chardev_ops tty_ops = { 250 struct sos_chardev_ops tty_ops = {
251 .read = tty_read, 251 .read = tty_read,
252 .write = tty_write, 252 .write = tty_write,
253 .open = tty_open, 253 .open = tty_open,
254 .close = tty_close, 254 .close = tty_close,
255 .ioctl = tty_ioctl 255 .ioctl = tty_ioctl
256 }; 256 };
257 257
258 sos_ret_t tty_create (sos_ui32_t device_instan 258 sos_ret_t tty_create (sos_ui32_t device_instance,
259 sos_ret_t (*write_func) 259 sos_ret_t (*write_func) (char c),
260 struct tty_device **tty_ 260 struct tty_device **tty_out)
261 { 261 {
262 struct tty_device *tty; 262 struct tty_device *tty;
263 263
264 if (tty_device_find (device_instance) != NUL 264 if (tty_device_find (device_instance) != NULL)
265 return -SOS_EBUSY; 265 return -SOS_EBUSY;
266 266
267 tty = (struct tty_device *) sos_kmalloc (siz 267 tty = (struct tty_device *) sos_kmalloc (sizeof(struct tty_device), 0);
268 if (tty == NULL) 268 if (tty == NULL)
269 return -SOS_ENOMEM; 269 return -SOS_ENOMEM;
270 270
271 memset (tty->buffer, 0, sizeof(tty->buffer)) 271 memset (tty->buffer, 0, sizeof(tty->buffer));
272 tty->open_count = 0; 272 tty->open_count = 0;
273 tty->instance = device_instance; 273 tty->instance = device_instance;
274 tty->write = write_func; 274 tty->write = write_func;
275 tty->buffer_read = 0; 275 tty->buffer_read = 0;
276 tty->buffer_write = 0; 276 tty->buffer_write = 0;
277 tty->param = SOS_IOCTLPARAM_TTY_CANON 277 tty->param = SOS_IOCTLPARAM_TTY_CANON;
278 sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_OR 278 sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_ORDER_FIFO);
279 sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ 279 sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ_ORDER_FIFO);
280 280
281 list_add_tail (tty_device_list, tty); 281 list_add_tail (tty_device_list, tty);
282 282
283 *tty_out = tty; 283 *tty_out = tty;
284 284
285 return SOS_OK; 285 return SOS_OK;
286 } 286 }
287 287
288 sos_ret_t tty_remove (struct tty_device *tty) 288 sos_ret_t tty_remove (struct tty_device *tty)
289 { 289 {
290 if (tty == NULL) 290 if (tty == NULL)
291 return -SOS_EINVAL; 291 return -SOS_EINVAL;
292 292
293 if (SOS_OK != sos_ksema_trydown (& tty->sem) 293 if (SOS_OK != sos_ksema_trydown (& tty->sem))
294 return -SOS_EBUSY; 294 return -SOS_EBUSY;
295 295
296 if (tty->open_count != 0) 296 if (tty->open_count != 0)
297 return -SOS_EBUSY; 297 return -SOS_EBUSY;
298 298
299 sos_kwaitq_dispose (& tty->wq); 299 sos_kwaitq_dispose (& tty->wq);
300 list_delete (tty_device_list, tty); 300 list_delete (tty_device_list, tty);
301 301
302 sos_kfree ((sos_vaddr_t) tty); 302 sos_kfree ((sos_vaddr_t) tty);
303 303
304 return SOS_OK; 304 return SOS_OK;
305 } 305 }
306 306
307 sos_ret_t tty_subsystem_setup (void) 307 sos_ret_t tty_subsystem_setup (void)
308 { 308 {
309 list_init (tty_device_list); 309 list_init (tty_device_list);
310 return sos_chardev_register_class (SOS_CHARD 310 return sos_chardev_register_class (SOS_CHARDEV_TTY_MAJOR,
311 & tty_ops 311 & tty_ops, NULL);
312 } 312 }
313 313
314 sos_ret_t tty_subsystem_cleanup (void) 314 sos_ret_t tty_subsystem_cleanup (void)
315 { 315 {
316 return sos_chardev_unregister_class (SOS_CHA 316 return sos_chardev_unregister_class (SOS_CHARDEV_TTY_MAJOR);
317 } 317 }
318 318