SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2005  Thomas Petazzoni, David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007 
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012 
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA.
017 */
018 
019 #include <sos/types.h>
020 #include <sos/assert.h>
021 #include <sos/errno.h>
022 #include <sos/fs.h>
023 #include <sos/ksynch.h>
024 #include <sos/kwaitq.h>
025 #include <sos/uaccess.h>
026 #include <sos/kmalloc.h>
027 #include <sos/list.h>
028 #include <sos/chardev.h>
029 #include <drivers/devices.h>
030 
031 #include "tty.h"
032 
033 #define TTY_BUFFER_LEN 64
034 #define TTY_NAME_LEN   16
035 
036 struct tty_device {
037   sos_ui32_t        instance;
038   unsigned int      open_count;
039   char              buffer[TTY_BUFFER_LEN];
040   unsigned int      buffer_read;
041   unsigned int      buffer_write;
042   struct sos_ksema  sem;
043   struct sos_kwaitq wq;
044   sos_ret_t         (*write)(char c);
045   unsigned int      param;
046   struct tty_device *next, *prev;
047 };
048 
049 static struct tty_device *tty_device_list;
050 
051 static struct tty_device *
052 tty_device_find (sos_ui32_t instance)
053 {
054   struct tty_device *t;
055   int n;
056 
057   list_foreach (tty_device_list, t, n)
058     {
059       if (t->instance == instance)
060         return t;
061     }
062 
063   return NULL;
064 }
065 
066 static sos_ret_t tty_read(struct sos_fs_opened_file *this,
067                           sos_uaddr_t dest_buf, sos_size_t *len)
068 {
069   sos_size_t count = 0;
070   struct tty_device *t;
071   sos_ret_t ret;
072 
073   t = (struct tty_device *) this->custom_data;
074 
075   if (*len == 0)
076     return SOS_OK;
077 
078   while (1)
079     {
080       char c;
081 
082       /* Take the semaphore */
083       sos_ksema_down (& t->sem, NULL);
084 
085       /* No keys available in the ring buffer, wait until the
086          add_chars callback wakes us up */
087       if (t->buffer_read == t->buffer_write)
088         {
089           sos_ksema_up (& t->sem);
090           sos_kwaitq_wait (& t->wq, NULL);
091 
092           /* Go back to begining of loop: maybe someone else stole the
093              semaphore */
094           continue;
095         }
096 
097       c = t->buffer[t->buffer_read];
098 
099       /* Copy the received character from the ring buffer to the
100          destination buffer */
101       ret = sos_memcpy_to_user (dest_buf,
102                                 (sos_vaddr_t) & t->buffer[t->buffer_read],
103                                 sizeof (char));
104       if (sizeof(char) != ret)
105         {
106           *len = count;
107           sos_ksema_up (& t->sem);
108           return ret;
109         }
110 
111       dest_buf++;
112 
113       /* Update the ring buffer read pointer */
114       t->buffer_read++;
115       if (t->buffer_read == TTY_BUFFER_LEN)
116         t->buffer_read = 0;
117 
118       count++;
119 
120       if (t->param & SOS_IOCTLPARAM_TTY_ECHO)
121         t->write (c);
122 
123       sos_ksema_up (& t->sem);
124 
125       /* Did we read enough bytes ? */
126       if (count == *len
127           || (c == '\n' && t->param & SOS_IOCTLPARAM_TTY_CANON))
128         break;
129     }
130 
131   *len = count;
132   return SOS_OK;
133 }
134 
135 
136 static sos_ret_t tty_write(struct sos_fs_opened_file *this,
137                            sos_uaddr_t src_buf, sos_size_t *len)
138 {
139   struct tty_device *t;
140   char c;
141   unsigned int i;
142   sos_ret_t ret;
143 
144   t = (struct tty_device *) this->custom_data;
145 
146   for (i = 0; i < *len; i++)
147     {
148       ret = sos_memcpy_from_user ((sos_vaddr_t) & c, src_buf, sizeof(char));
149       if (sizeof(char) != ret)
150         {
151           *len = i;
152           return ret;
153         }
154 
155       sos_ksema_down (& t->sem, NULL);
156       t->write (c);
157       sos_ksema_up (& t->sem);
158 
159       src_buf++;
160     }
161 
162   return SOS_OK;
163 }
164 
165 
166 static sos_ret_t tty_ioctl(struct sos_fs_opened_file *this, int req_id,
167                            sos_ui32_t req_arg)
168 {
169   struct tty_device *t;
170 
171   if (req_arg != SOS_IOCTLPARAM_TTY_ECHO
172       && req_arg != SOS_IOCTLPARAM_TTY_CANON)
173     return -SOS_EINVAL;
174 
175   t = (struct tty_device *) this->custom_data;
176 
177   sos_ksema_down (& t->sem, NULL);
178 
179   switch (req_id)
180     {
181     case SOS_IOCTL_TTY_SETPARAM:
182       t->param |= req_arg;
183       break;
184 
185     case SOS_IOCTL_TTY_RESETPARAM:
186       t->param &= ~req_arg;
187       break;
188 
189     default:
190       sos_ksema_up (& t->sem);
191       return -SOS_EINVAL;
192     }
193 
194   sos_ksema_up (& t->sem);
195 
196   return SOS_OK;
197 }
198 
199 static sos_ret_t tty_open(struct sos_fs_node        * fsnode,
200                           struct sos_fs_opened_file * of,
201                           void * chardev_class_custom_data)
202 {
203   struct tty_device *t;
204 
205   t = tty_device_find (fsnode->dev_id.device_instance);
206   if (t == NULL)
207     return -SOS_ENOENT;
208 
209   sos_ksema_down (& t->sem, NULL);
210   of->custom_data = t;
211   t->open_count ++;
212   sos_ksema_up (& t->sem);
213 
214   return SOS_OK;
215 }
216 
217 
218 static sos_ret_t tty_close(struct sos_fs_opened_file *of,
219                            void *custom_data)
220 {
221   struct tty_device *t;
222 
223   t = (struct tty_device *) of->custom_data;
224 
225   sos_ksema_down (& t->sem, NULL);
226   t->open_count --;
227   sos_ksema_up (& t->sem);
228 
229   return SOS_OK;
230 }
231 
232 void tty_add_chars (struct tty_device *t, const char *s)
233 {
234   sos_ksema_down (& t->sem, NULL);
235   while (*s)
236     {
237       /* Add all characters to the ring buffer */
238       t->buffer[t->buffer_write] = *s;
239       t->buffer_write++;
240       if (t->buffer_write == TTY_BUFFER_LEN)
241         t->buffer_write = 0;
242       s++;
243     }
244   sos_ksema_up (& t->sem);
245 
246   /* Wake up a possibly waiting thread */
247   sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_ALL, SOS_OK);
248 }
249 
250 struct sos_chardev_ops tty_ops = {
251   .read    = tty_read,
252   .write   = tty_write,
253   .open    = tty_open,
254   .close   = tty_close,
255   .ioctl   = tty_ioctl
256 };
257 
258 sos_ret_t tty_create (sos_ui32_t device_instance,
259                       sos_ret_t (*write_func) (char c),
260                       struct tty_device **tty_out)
261 {
262   struct tty_device *tty;
263 
264   if (tty_device_find (device_instance) != NULL)
265     return -SOS_EBUSY;
266 
267   tty = (struct tty_device *) sos_kmalloc (sizeof(struct tty_device), 0);
268   if (tty == NULL)
269     return -SOS_ENOMEM;
270 
271   memset (tty->buffer, 0, sizeof(tty->buffer));
272   tty->open_count   = 0;
273   tty->instance     = device_instance;
274   tty->write        = write_func;
275   tty->buffer_read  = 0;
276   tty->buffer_write = 0;
277   tty->param        = SOS_IOCTLPARAM_TTY_CANON;
278   sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_ORDER_FIFO);
279   sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ_ORDER_FIFO);
280 
281   list_add_tail (tty_device_list, tty);
282 
283   *tty_out = tty;
284 
285   return SOS_OK;
286 }
287 
288 sos_ret_t tty_remove (struct tty_device *tty)
289 {
290   if (tty == NULL)
291     return -SOS_EINVAL;
292 
293   if (SOS_OK != sos_ksema_trydown (& tty->sem))
294     return -SOS_EBUSY;
295 
296   if (tty->open_count != 0)
297     return -SOS_EBUSY;
298 
299   sos_kwaitq_dispose (& tty->wq);
300   list_delete (tty_device_list, tty);
301 
302   sos_kfree ((sos_vaddr_t) tty);
303 
304   return SOS_OK;
305 }
306 
307 sos_ret_t tty_subsystem_setup (void)
308 {
309   list_init (tty_device_list);
310   return sos_chardev_register_class (SOS_CHARDEV_TTY_MAJOR,
311                                      & tty_ops, NULL);
312 }
313 
314 sos_ret_t tty_subsystem_cleanup (void)
315 {
316   return sos_chardev_unregister_class (SOS_CHARDEV_TTY_MAJOR);
317 }
318 

source navigation ] diff markup ] identifier search ] general search ]