Add a printx lock
[akaros.git] / kern / src / devfs.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Devfs: filesystem interfaces to devices.  For now, we just create the
6  * needed/discovered devices in KFS in its /dev/ folder, and only do this for
7  * stdin and stdout. */
8
9 #include <devfs.h>
10 #include <kfs.h>
11 #include <error.h>
12 #include <syscall.h>
13 #include <process.h>
14 #include <smp.h>
15 #include <umem.h>
16 #include <kmalloc.h>
17 #include <console.h>
18
19 /* These structs are declared again and initialized farther down */
20 struct file_operations dev_f_op_stdin;
21 struct file_operations dev_f_op_stdout;
22 struct file_operations dev_f_op_null;
23
24 struct file *dev_stdin, *dev_stdout, *dev_stderr, *dev_null;
25
26 void devfs_init(void)
27 {
28         int mode;
29         /* Make sure there is a dev directory */
30         struct dentry *dentry = lookup_dentry("/dev/", 0);
31         if (!dentry) {
32                 assert(!do_mkdir("/dev/", S_IRWXU | S_IRWXG | S_IRWXO));
33         } else {
34                 kref_put(&dentry->d_kref);
35         }
36         /* Notice we don't kref_put().  We're storing the refs globally */
37         dev_stdin = make_device("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
38                                 __S_IFCHR, &dev_f_op_stdin);
39         dev_stdout = make_device("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
40                                  __S_IFCHR, &dev_f_op_stdout);
41         /* Note stderr uses the same f_op as stdout */
42         dev_stderr = make_device("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
43                                  __S_IFCHR, &dev_f_op_stdout);
44         dev_null = make_device("/dev/null", S_IWUSR | S_IWGRP | S_IWOTH,
45                                __S_IFCHR, &dev_f_op_null);
46 }
47
48 /* Creates a device node at a given location in the FS-tree */
49 /* TODO: consider making this only deal with the inode */
50 struct file *make_device(char *path, int mode, int type,
51                          struct file_operations *fop)
52 {
53         struct file *f_dev = do_file_open(path, O_CREAT | O_RDWR, mode);
54         assert(f_dev);
55         /* Overwrite the f_op with our own f_ops */
56         f_dev->f_dentry->d_inode->i_fop = fop;
57         f_dev->f_op = fop;
58         SET_FTYPE(f_dev->f_dentry->d_inode->i_mode, type);
59         return f_dev;
60 }
61
62 /* We provide a separate set of f_ops for devices (char and block), and the fops
63  * is the only thing that differs from the regular KFS.  We need to do some
64  * ghetto-overriding of these ops after we create them. */
65 int dev_c_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
66 {
67         set_errno(EINVAL);
68         return -1;
69 }
70
71 /* we don't allow mmapping of any device file */
72 int dev_mmap(struct file *file, struct vm_region *vmr)
73 {
74         set_errno(EINVAL);
75         return -1;
76 }
77
78 /* this is really /dev/console, and will need some tty work.  for now, no matter
79  * how much they ask for, we return one character at a time. */
80 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
81                        off64_t *offset)
82 {
83         char c;
84         extern struct kb_buffer cons_buf;
85
86         if (!count)
87                 return 0;
88         kb_get_from_buf(&cons_buf, &c, 1);
89         /* TODO UMEM */
90         if (current)
91                 memcpy_to_user_errno(current, buf, &c, 1);
92         else
93                 memcpy(buf, &c, 1);
94         return 1;
95 }
96
97 ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
98                          off64_t *offset)
99 {
100         char *t_buf;
101         struct proc *p = current;
102         if (p)
103                 t_buf = user_memdup_errno(p, buf, count);
104         else
105                 t_buf = (char*)buf;
106         if (!t_buf)
107                 return -1;
108         /* TODO: tty hack.  they are sending us an escape sequence, and the keyboard
109          * would try to print it (which it can't do yet).  The hack is even dirtier
110          * in that we only detect it if it is the first char, and we ignore
111          * everything else.  \033 is 0x1b. */
112         if (t_buf[0] != '\033') {
113                 px_lock();
114                 cputbuf(t_buf, count);
115                 px_unlock();
116         }
117         if (p)
118                 user_memdup_free(p, t_buf);
119         return count;
120 }
121
122 /* stdin/stdout/stderr file ops */
123 struct file_operations dev_f_op_stdin = {
124         dev_c_llseek,
125         dev_stdin_read,
126         0,      /* write - can't write to stdin */
127         kfs_readdir,    /* this will fail gracefully */
128         dev_mmap,
129         kfs_open,
130         kfs_flush,
131         kfs_release,
132         0,      /* fsync - makes no sense */
133         kfs_poll,
134         0,      /* readv */
135         0,      /* writev */
136         kfs_sendpage,
137         kfs_check_flags,
138 };
139
140 struct file_operations dev_f_op_stdout = {
141         dev_c_llseek,
142         0,      /* read - can't read stdout */
143         dev_stdout_write,
144         kfs_readdir,    /* this will fail gracefully */
145         dev_mmap,
146         kfs_open,
147         kfs_flush,
148         kfs_release,
149         0,      /* fsync - makes no sense */
150         kfs_poll,
151         0,      /* readv */
152         0,      /* writev */
153         kfs_sendpage,
154         kfs_check_flags,
155 };
156
157 ssize_t dev_null_read(struct file *file, char *buf, size_t count,
158                       off64_t *offset)
159 {
160         return 0;
161 }
162
163 /* /dev/null: just take whatever was given and pretend it was written */
164 ssize_t dev_null_write(struct file *file, const char *buf, size_t count,
165                        off64_t *offset)
166 {
167         return count;
168 }
169
170 struct file_operations dev_f_op_null = {
171         dev_c_llseek,
172         dev_null_read,
173         dev_null_write,
174         kfs_readdir,    /* this will fail gracefully */
175         dev_mmap,
176         kfs_open,
177         kfs_flush,
178         kfs_release,
179         0,      /* fsync - makes no sense */
180         kfs_poll,
181         0,      /* readv */
182         0,      /* writev */
183         kfs_sendpage,
184         kfs_check_flags,
185 };