root/Whitix/trunk/video/virtual.c

Revision 2035, 8.0 KB (checked in by mwhitworth, 3 years ago)

Fix object type.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19/* TODO: Needs to be tightened up and rewritten in parts. sprintf'ing on user buffers
20 * is not a good idea. */
21
22/* In the future, code that wants to use virtual terminals will do SysMakeDir
23 * in Bus/Virtual. For now, use attributes on a VirtualMaster device. */
24#include <console.h>
25#include <fs/devfs.h>
26#include <fs/vfs.h>
27#include <module.h>
28#include <error.h>
29#include <malloc.h>
30#include <i386/ioports.h>
31#include <task.h>
32#include <print.h>
33#include <devices/device.h>
34#include <devices/class.h>
35#include <console.h>
36
37#define VIRTUAL_MAX             10
38#define VIRTUAL_BUFFER_SIZE             4096 /* TEST */
39
40/* At most there will be two digits after Virtual, plus the null terminator. */
41#define VIRTUAL_NAME_SIZE       sizeof("Virtual")+3
42#define VIRTUAL_MASTER_INVALID (-1)
43#define VIRTUAL_FILE_MASTER     1
44#define VIRTUAL_FILE_SLAVE      2
45
46/* Device number */
47#define VIRTUAL_MAJOR   255
48
49/* TEMP */
50extern struct DevClass consoleClass;
51
52struct VirtualMaster
53{
54        struct KeDevice device;
55};
56
57struct VirtualTerm
58{
59        struct KeDevice device;
60       
61        int masterFlag;
62        int flags;
63        int slaveCount;
64        char* masterOutput;
65        int masterHead, masterTail;
66        WaitQueue masterQueue;
67        char* slavesOutput;
68        int slaveHead, slaveTail;
69        WaitQueue slaveQueue;
70};
71
72KE_OBJECT_TYPE(vMasterType, NULL);
73KE_OBJECT_TYPE(vTermType, NULL);
74
75struct VirtualMaster vMaster;
76
77struct FileOps vChildOps;
78struct VirtualTerm virtualT[VIRTUAL_MAX];
79
80static inline int VirtualIsMaster(struct File* file)
81{
82        return ((int)file->filePriv == VIRTUAL_FILE_MASTER);
83}
84
85struct VirtualTerm* VirtualTermGet(struct File* file)
86{
87        struct KeDevice* device;
88       
89        device = DevFsGetDevice(file->vNode);
90       
91        if (!device)
92                return NULL;
93               
94        return ContainerOf(device, struct VirtualTerm, device);
95}
96
97int VirtualChildOpen(struct File* file)
98{
99        struct VirtualTerm* term;
100       
101        term = VirtualTermGet(file);
102       
103        if (!term)
104                return -EINVAL;
105       
106        if (term->masterFlag == VIRTUAL_MASTER_INVALID)
107        {
108                term->masterFlag = VIRTUAL_FILE_MASTER; /* Now taken. */
109                file->filePriv = (void*)VIRTUAL_FILE_MASTER;
110                term->masterOutput=(char*)MemAlloc(VIRTUAL_BUFFER_SIZE);
111                term->slavesOutput=(char*)MemAlloc(VIRTUAL_BUFFER_SIZE);
112                term->masterHead = term->masterTail = 0;
113                term->slaveHead = term->slaveTail = 0;
114
115                INIT_WAITQUEUE_HEAD(&term->masterQueue);
116                INIT_WAITQUEUE_HEAD(&term->slaveQueue);
117        }else{
118                file->filePriv = (void*)VIRTUAL_FILE_SLAVE;
119                term->slaveCount++;
120        }
121               
122        return 0;
123}
124
125int VirtualChildRead(struct File* file, BYTE* data, DWORD length)
126{
127        struct VirtualTerm* vTerm;
128        DWORD size=0, oldSize;
129        DWORD flags;
130
131        vTerm=VirtualTermGet(file);
132       
133        if (!vTerm)
134                return -ENOENT;
135               
136//      KePrint("%s: VirtualChildRead(%#X)\n", current->name, length);
137                       
138        if (VirtualIsMaster(file))
139        {
140                WAIT_ON(&vTerm->slaveQueue, vTerm->slaveHead != vTerm->slaveTail);
141
142                IrqSaveFlags(flags);
143                size=MIN((DWORD)(vTerm->slaveHead-vTerm->slaveTail), length);
144                oldSize=size;
145
146                while (size--)
147                {
148                        *data++=vTerm->slavesOutput[vTerm->slaveTail++];
149                        vTerm->slaveTail &= VIRTUAL_BUFFER_SIZE-1;
150                }
151        }else{
152                WAIT_ON(&vTerm->masterQueue, vTerm->masterHead != vTerm->masterTail);
153
154                IrqSaveFlags(flags);
155                size=MIN((DWORD)(vTerm->masterHead-vTerm->masterTail), length);
156                oldSize=size;
157
158                while (size--)
159                {
160                        *data++=vTerm->masterOutput[vTerm->masterTail++];
161                        vTerm->masterTail &= VIRTUAL_BUFFER_SIZE-1;
162                }
163        }
164
165        IrqRestoreFlags(flags);
166
167        return oldSize;
168}
169
170int VirtualChildWrite(struct File* file, BYTE* data, DWORD length)
171{
172        struct VirtualTerm* vTerm;
173        unsigned int tempLength;
174        vTerm=VirtualTermGet(file);
175
176        if (!vTerm)
177                return -ENOENT;
178
179        PreemptDisable();
180       
181        tempLength=length;
182       
183//      KePrint("%s: VirtualChildWrite(%s, %d), %#X\n", current->name, data, length, VirtualIsMaster(file));
184               
185        if (VirtualIsMaster(file))
186        {
187                /* TODO: Limit length */
188               
189                memcpy(&vTerm->masterOutput[vTerm->masterHead], data, length);
190               
191                vTerm->masterHead+=length;
192                vTerm->masterHead &= VIRTUAL_BUFFER_SIZE-1;
193
194                PreemptEnable();
195
196                WakeUp(&vTerm->masterQueue);
197        }else
198                while (length--)
199                {
200                        vTerm->slavesOutput[vTerm->slaveHead++]=*data++;
201                        vTerm->slaveHead &= VIRTUAL_BUFFER_SIZE-1;
202                }
203               
204                PreemptEnable();
205
206                WakeUp(&vTerm->slaveQueue);
207        }
208
209        return tempLength;
210}
211
212int VirtualChildPoll(struct File* file, struct PollItem* item, struct PollQueue* pollQueue)
213{
214        struct VirtualTerm* vTerm;
215
216        vTerm = VirtualTermGet(file);
217       
218        if (VirtualIsMaster(file))
219        {
220                if (vTerm->slaveHead != vTerm->slaveTail)
221                        item->revents |= POLL_IN;
222
223                if (vTerm->masterTail != ((vTerm->masterHead - 1) % VIRTUAL_BUFFER_SIZE))
224                        item->revents |= POLL_OUT;
225                       
226                if (vTerm->slaveCount <= 0)
227                        item->revents |= POLL_ERR;
228
229                PollAddWait(pollQueue, &vTerm->slaveQueue);
230        }else{
231                if (vTerm->masterHead != vTerm->masterTail)
232                        item->revents |= POLL_IN;
233                       
234                if (vTerm->slaveTail != ((vTerm->slaveHead - 1) %
235                        VIRTUAL_BUFFER_SIZE))
236                        item->revents |= POLL_OUT;
237                       
238                if (vTerm->masterFlag == VIRTUAL_MASTER_INVALID)
239                        item->revents |= POLL_ERR;
240
241                PollAddWait(pollQueue, &vTerm->masterQueue);
242        }
243
244        return 0;
245}
246
247int VirtualChildClose(struct File* file)
248{
249        struct VirtualTerm* vTerm;
250       
251        vTerm = VirtualTermGet(file);
252       
253        if (VirtualIsMaster(file))
254        {
255                vTerm->masterFlag = VIRTUAL_MASTER_INVALID;
256        }else{
257                vTerm->slaveCount--;
258        }
259       
260        if (vTerm->masterFlag == VIRTUAL_MASTER_INVALID && vTerm->slaveCount == 0)
261        {
262                /* FIXME: Free terminal. */
263        }
264       
265        return 0;
266}
267
268struct FileOps vChildOps=
269{
270        .read = VirtualChildRead,
271        .write = VirtualChildWrite,
272        .poll = VirtualChildPoll,
273        .open = VirtualChildOpen,
274        .close = VirtualChildClose,
275};
276
277int VirtualNewTerminal(BYTE* data, unsigned long size, DWORD position)
278{
279        int i, total, err;
280        struct VirtualTerm* term;
281       
282        if (size < VIRTUAL_NAME_SIZE)
283                return -EFAULT;
284               
285        /* Can only do one read to find out the terminal name. */
286        if (position != 0)
287                return 0;
288
289        PreemptDisable();
290       
291        /* Find a free virtual terminal. */
292        for (i = 0; i < VIRTUAL_MAX; i++)
293                if (!virtualT[i].masterFlag)
294                        break;
295                       
296        if (i == VIRTUAL_MAX)
297        {
298                PreemptEnable();
299                return -EMFILE;
300        }
301       
302        term = &virtualT[i];
303        total = snprintf(data, VIRTUAL_NAME_SIZE, "Virtual%d", i);
304       
305        /* Create the master device */
306        KeDeviceInit(&term->device, &consoleClass.set, DEV_ID_MAKE(0, 0), &vChildOps, DEVICE_CHAR);
307        err = KeDeviceAttach(&term->device, "Virtual%d", i);
308       
309        if (err)
310        {
311                PreemptEnable();
312                return err;
313        }
314       
315        term->masterFlag = VIRTUAL_MASTER_INVALID;
316        term->flags = 0;
317        term->slaveCount = 0;
318
319        /* TODO: Change to ICFS attributes with a common Console structure. */
320        struct KeFsEntry* dir=KeDeviceGetConfDir(&term->device);
321        IcFsAddIntEntry(dir, "flags", &term->flags, VFS_ATTR_RW);
322       
323        PreemptEnable();
324       
325        return total;
326}
327
328/* FIXME: Check if Close can handle removing a terminal. */
329int VirtualRemoveTerminal(BYTE* data, unsigned long size, DWORD position)
330{
331        KePrint("VirtualRemoveTerminal\n");
332        return 0;
333}
334
335int VirtualInit()
336{
337        ZeroMemory(virtualT, VIRTUAL_MAX * sizeof(struct VirtualTerm));
338       
339        KeDeviceInit(&vMaster.device, &consoleClass.set, DEV_ID_MAKE(0, 0), NULL, DEVICE_CHAR);
340        KeDeviceAttach(&vMaster.device, "VirtualMaster");
341       
342        /* Register the master's configuration options. TODO: Change to ICFS attributes. */
343        struct KeFsEntry* dir=KeDeviceGetConfDir(&vMaster.device);
344       
345        /* newTerminal returns a string to the reader with the name of the new terminal.
346         * It doesn't have a write function. */
347        IcFsAddFuncEntry(dir, "newTerminal", VirtualNewTerminal, NULL);
348        IcFsAddFuncEntry(dir, "delTerminal", NULL, VirtualRemoveTerminal);
349       
350        return 0;
351}
352
353ModuleInit(VirtualInit);
Note: See TracBrowser for help on using the browser.