AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
kdev.c
Go to the documentation of this file.
1
12
13#include <core/system.h>
14#include <dev/dev.h>
15#include <fs/vfs.h>
16#include <fs/posix.h>
17#include <dev/blkcache.h>
18
19MALLOC_DEFINE(M_KDEV_BLK, "kdev-blk", "kdev block buffer");
20
21struct dev *chrdev[256];
22struct dev *blkdev[256];
23
26static inline struct dev *kdev_get(struct devid *dd)
27{
28 struct dev *dev = NULL;
29
30 switch (dd->type) {
31 case S_IFCHR:
32 dev = chrdev[dd->major];
33 break;
34 case S_IFBLK:
35 dev = blkdev[dd->major];
36 break;
37 }
38
39 if (dev && dev->mux) { /* several devices, one per minor */
40 return dev->mux(dd);
41 }
42
43 return dev;
44}
45
52struct fops *kdev_fops(struct devid *dd)
53{
54 struct dev *dev = kdev_get(dd);
55 return dev ? &dev->fops : NULL;
56}
57
64int kdev_close(struct devid *dev __unused)
65{
66 return 0;
67}
68
80ssize_t kdev_bread(struct devid *dd, off_t offset, size_t size, void *buf)
81{
82 struct dev *dev = kdev_get(dd);
83
84 if (!dev || !dev->bread || !dev->getbs)
85 return -ENXIO;
86
87 size_t bs = dev->getbs(dd);
88 ssize_t ret = 0, r = 0;
89
90 char *cbuf = buf;
91 char *bbuf = NULL;
92
93 /* a driver's bread() returns how many blocks it read: if it read fewer
94 * than asked, the device ended there, and so does what is read */
95
96 /* the part up to the first block boundary */
97 if (offset % bs) {
98 if (!(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))
99 return -ENOMEM;
100
101 size_t start = MIN(bs - offset % bs, size);
102
103 if ((r = dev->bread(dd, offset/bs, 1, bbuf)) < 1)
104 goto done;
105
106 memcpy(cbuf, bbuf + (offset % bs), start);
107
108 ret += start;
109 size -= start;
110 cbuf += start;
111 offset += start;
112
113 if (!size)
114 goto done;
115 }
116
117 /* the whole blocks */
118 size_t count = size/bs;
119
120 if (count) {
121 if ((r = dev->bread(dd, offset/bs, count, cbuf)) < 0)
122 goto done;
123
124 ret += r * bs;
125 size -= r * bs;
126 cbuf += r * bs;
127 offset += r * bs;
128
129 if (!size || (size_t) r < count)
130 goto done;
131 }
132
133 size_t end = size % bs;
134
135 if (end) {
136 if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))
137 return ret ? ret : -ENOMEM;
138
139 if ((r = dev->bread(dd, offset/bs, 1, bbuf)) < 1)
140 goto done;
141
142 memcpy(cbuf, bbuf, end);
143 ret += end;
144 }
145
146done:
147 kfree(bbuf);
148
149 /* return the error only if nothing was read before it */
150 return r < 0 && !ret ? r : ret;
151}
152
165ssize_t kdev_bwrite(struct devid *dd, off_t offset, size_t size, void *buf)
166{
167 struct dev *dev = kdev_get(dd);
168
169 if (!dev || !dev->bread || !dev->bwrite || !dev->getbs)
170 return -ENXIO;
171
172 size_t bs = dev->getbs(dd);
173 ssize_t ret = 0, r = 0;
174
175 char *cbuf = buf;
176 char *bbuf = NULL;
177
178 /* as in kdev_bread(): fewer blocks than asked means the device ended
179 * there */
180
181 if (offset % bs) {
182 if (!(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))
183 return -ENOMEM;
184
185 /* the part up to the first block boundary */
186 size_t start = MIN(bs - offset % bs, size);
187
188 if ((r = dev->bread(dd, offset/bs, 1, bbuf)) < 1)
189 goto done;
190
191 memcpy(bbuf + (offset % bs), cbuf, start);
192
193 if ((r = dev->bwrite(dd, offset/bs, 1, bbuf)) < 1)
194 goto done;
195
196 ret += start;
197 size -= start;
198 cbuf += start;
199 offset += start;
200
201 if (!size)
202 goto done;
203 }
204
205 /* the whole blocks */
206 size_t count = size/bs;
207
208 if (count) {
209 if ((r = dev->bwrite(dd, offset/bs, count, cbuf)) < 0)
210 goto done;
211
212 ret += r * bs;
213 size -= r * bs;
214 cbuf += r * bs;
215 offset += r * bs;
216
217 if (!size || (size_t) r < count)
218 goto done;
219 }
220
221 size_t end = size % bs;
222
223 if (end) {
224 if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))
225 return ret ? ret : -ENOMEM;
226
227 if ((r = dev->bread(dd, offset/bs, 1, bbuf)) < 1)
228 goto done;
229
230 memcpy(bbuf, cbuf, end);
231
232 if ((r = dev->bwrite(dd, offset/bs, 1, bbuf)) < 1)
233 goto done;
234
235 ret += end;
236 }
237
238done:
239 kfree(bbuf);
240
241 /* return the error only if nothing was written before it; if nothing
242 * could be written at all, the device is full */
243 if (r < 0 && !ret)
244 return r;
245
246 return ret || !size ? ret : -ENOSPC;
247}
248
253static ssize_t kdev_blk_io(struct devid *dd, off_t offset, struct iobuf *io, int write)
254{
255 char *buf = kmalloc(PAGE_SIZE, &M_KDEV_BLK, 0);
256
257 if (!buf)
258 return -ENOMEM;
259
260 size_t size = io->resid, done = 0;
261 ssize_t r = 0;
262
263 while (done < size) {
264 size_t len = MIN(size - done, PAGE_SIZE);
265
266 if (write) {
267 if ((r = iobuf_in(io, buf, len)) > 0)
268 r = kdev_bwrite(dd, offset + done, r, buf);
269 } else {
270 if ((r = kdev_bread(dd, offset + done, len, buf)) > 0)
271 r = iobuf_out(io, buf, r);
272 }
273
274 if (r <= 0)
275 break;
276
277 done += r;
278
279 /* the device's end, or a fault in the iobuf */
280 if ((size_t) r < len)
281 break;
282 }
283
284 kfree(buf);
285 return done ? (ssize_t) done : r;
286}
287
297ssize_t kdev_read(struct devid *dd, off_t offset, struct iobuf *io)
298{
299 struct dev *dev = NULL;
300
301 if (!(dev = kdev_get(dd)))
302 return -ENXIO;
303
304 if (S_ISCHR(dd->type))
305 return dev->read ? dev->read(dd, offset, io) : -ENXIO;
306 else
307 return dev->bread ? kdev_blk_io(dd, offset, io, 0) : -ENXIO;
308}
309
319ssize_t kdev_write(struct devid *dd, off_t offset, struct iobuf *io)
320{
321 struct dev *dev = NULL;
322
323 if (!(dev = kdev_get(dd)))
324 return -ENXIO;
325
326 if (S_ISCHR(dd->type))
327 return dev->write ? dev->write(dd, offset, io) : -ENXIO;
328 else
329 return dev->bwrite ? kdev_blk_io(dd, offset, io, 1) : -ENXIO;
330}
331
340int kdev_ioctl(struct devid *dd, int request, void *argp)
341{
342 struct dev *dev = NULL;
343
344 if (!(dev = kdev_get(dd)))
345 return -ENXIO;
346
347 if (!dev->ioctl)
348 return -ENXIO;
349
350 return dev->ioctl(dd, request, argp);
351}
352
361int kdev_map(struct devid *dd, struct vm_space *vm_space, struct vm_entry *vm_entry)
362{
363 struct dev *dev = NULL;
364
365 if (!(dev = kdev_get(dd)))
366 return -ENXIO;
367
368 if (!dev->map)
369 return -ENXIO;
370
371 return dev->map(dd, vm_space, vm_entry);
372}
373
381int kdev_file_open(struct devid *dd, struct file *file)
382{
383 struct dev *dev = NULL;
384
385 if (!(dev = kdev_get(dd)))
386 return -ENXIO;
387
388 if (!dev->fops.open)
389 return -ENXIO;
390
391 return dev->fops.open(file);
392}
393
402ssize_t kdev_file_read(struct devid *dd, struct file *file, struct iobuf *io)
403{
404 struct dev *dev = NULL;
405
406 if (!(dev = kdev_get(dd)))
407 return -ENXIO;
408
409 if (!dev->fops.read)
410 return -ENXIO;
411
412 return dev->fops.read(file, io);
413}
414
423ssize_t kdev_file_write(struct devid *dd, struct file *file, struct iobuf *io)
424{
425 struct dev *dev = NULL;
426
427 if (!(dev = kdev_get(dd)))
428 return -ENXIO;
429
430 if (!dev->fops.write)
431 return -ENXIO;
432
433 return dev->fops.write(file, io);
434}
435
447off_t kdev_file_lseek(struct devid *dd, struct file *file, off_t offset, int whence)
448{
449 struct dev *dev = NULL;
450
451 if (!(dev = kdev_get(dd)))
452 return -ENXIO;
453
454 /* terminals and other streams can't seek */
455 if (!dev->fops.lseek)
456 return -ESPIPE;
457
458 return dev->fops.lseek(file, offset, whence);
459}
460
469{
470 struct dev *dev = NULL;
471
472 if (!(dev = kdev_get(dd)))
473 return -ENXIO;
474
475 /* by default, release the reference to the device's vnode */
476 if (!dev->fops.close)
477 return posix_file_close(file);
478
479 return dev->fops.close(file);
480}
481
492int kdev_file_ioctl(struct devid *dd, struct file *file, int request, void *argp)
493{
494 struct dev *dev = NULL;
495
496 if (!(dev = kdev_get(dd)))
497 return -ENXIO;
498
499 if (!dev->fops.ioctl)
500 return -ENXIO;
501
502 return dev->fops.ioctl(file, request, argp);
503}
504
513int kdev_file_can_read(struct devid *dd, struct file * file, size_t size)
514{
515 struct dev *dev = NULL;
516
517 if (!(dev = kdev_get(dd)))
518 return -ENXIO;
519
520 if (!dev->fops.can_read)
521 return -ENXIO;
522
523 return dev->fops.can_read(file, size);
524}
525
534int kdev_file_can_write(struct devid *dd, struct file * file, size_t size)
535{
536 struct dev *dev = NULL;
537
538 if (!(dev = kdev_get(dd)))
539 return -ENXIO;
540
541 if (!dev->fops.can_write)
542 return -ENXIO;
543
544 return dev->fops.can_write(file, size);
545}
546
555int kdev_file_eof(struct devid *dd, struct file *file)
556{
557 struct dev *dev = NULL;
558
559 if (!(dev = kdev_get(dd)))
560 return -ENXIO;
561
562 if (!dev->fops.eof)
563 return -ENXIO;
564
565 return dev->fops.eof(file);
566}
567
576{
577 chrdev[major] = dev;
578 printk("kdev: registered chrdev %d: %s\n", major, dev->name);
579}
580
587int kdev_sync(void)
588{
589 int err = blkcache_flush();
590
591 for (int i = 0; i < 256; ++i)
592 if (blkdev[i] && blkdev[i]->sync && blkdev[i]->sync())
593 err = -EIO;
594
595 return err;
596}
597
606{
607 blkdev[major] = dev;
608 printk("kdev: registered blkdev %d: %s\n", major, dev->name);
609}
610
616{
617 printk("kdev: initializing\n");
618}
#define PAGE_SIZE
Definition system.h:7
int blkcache_flush(void)
Writes every dirty block of the cache to its disk.
Definition blkcache.c:309
#define MIN(a, b)
Definition system.h:11
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
Definition iobuf.c:115
ssize_t iobuf_in(struct iobuf *io, void *dst, size_t n)
Copies bytes from the iobuf's buffer into the kernel, and moves past them.
Definition iobuf.c:135
int kdev_map(struct devid *dd, struct vm_space *vm_space, struct vm_entry *vm_entry)
Maps a device into an address space (mmap() of a framebuffer).
Definition kdev.c:361
ssize_t kdev_file_close(struct devid *dd, struct file *file)
Closes an open device file, through its driver's file operations.
Definition kdev.c:468
off_t kdev_file_lseek(struct devid *dd, struct file *file, off_t offset, int whence)
Moves an open device file's offset, through its driver's file operations.
Definition kdev.c:447
void kdev_blkdev_register(devid_t major, struct dev *dev)
Registers a driver as the block device of a major number.
Definition kdev.c:605
struct fops * kdev_fops(struct devid *dd)
Returns the file operations of a device.
Definition kdev.c:52
int kdev_file_can_write(struct devid *dd, struct file *file, size_t size)
Asks a device's driver whether a write wouldn't have to wait.
Definition kdev.c:534
int kdev_file_eof(struct devid *dd, struct file *file)
Asks a device's driver whether a read that found no data is at the end of the file.
Definition kdev.c:555
ssize_t kdev_file_write(struct devid *dd, struct file *file, struct iobuf *io)
Writes to an open device file, through its driver's file operations.
Definition kdev.c:423
ssize_t kdev_file_read(struct devid *dd, struct file *file, struct iobuf *io)
Reads an open device file, through its driver's file operations.
Definition kdev.c:402
struct dev * blkdev[256]
Definition kdev.c:22
int kdev_file_ioctl(struct devid *dd, struct file *file, int request, void *argp)
Passes an ioctl() on an open device file to its driver's file operations.
Definition kdev.c:492
ssize_t kdev_read(struct devid *dd, off_t offset, struct iobuf *io)
Reads from a device: a character device through its driver, a block device in blocks.
Definition kdev.c:297
ssize_t kdev_bread(struct devid *dd, off_t offset, size_t size, void *buf)
Reads bytes from a block device, at any offset: the driver reads whole blocks, and the partial blocks...
Definition kdev.c:80
void kdev_chrdev_register(devid_t major, struct dev *dev)
Registers a driver as the character device of a major number.
Definition kdev.c:575
int kdev_close(struct devid *dev)
Closes a device: there is nothing to do.
Definition kdev.c:64
int kdev_file_open(struct devid *dd, struct file *file)
Opens a device, through its driver's file operations.
Definition kdev.c:381
static ssize_t kdev_blk_io(struct devid *dd, off_t offset, struct iobuf *io, int write)
Reads or writes a block device's bytes from or to an iobuf (user memory), a page at a time through a ...
Definition kdev.c:253
int kdev_sync(void)
Writes what the block cache holds that was written, and what the block devices hold in their write ca...
Definition kdev.c:587
struct dev * chrdev[256]
Definition kdev.c:21
static struct dev * kdev_get(struct devid *dd)
Returns the driver of a device number, picked by minor if the major's driver multiplexes several devi...
Definition kdev.c:26
int kdev_ioctl(struct devid *dd, int request, void *argp)
Passes an ioctl() to a device's driver.
Definition kdev.c:340
int kdev_file_can_read(struct devid *dd, struct file *file, size_t size)
Asks a device's driver whether a read wouldn't have to wait.
Definition kdev.c:513
ssize_t kdev_write(struct devid *dd, off_t offset, struct iobuf *io)
Writes to a device: a character device through its driver, a block device in blocks.
Definition kdev.c:319
void kdev_init()
Starts the device layer, at boot.
Definition kdev.c:615
ssize_t kdev_bwrite(struct devid *dd, off_t offset, size_t size, void *buf)
Writes bytes to a block device, at any offset: the driver writes whole blocks, and the partial blocks...
Definition kdev.c:165
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
int posix_file_close(struct file *file)
Closes an open file by dropping its reference to its vnode.
Definition close.c:15
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
#define NULL
Definition stddef.h:27
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
struct dev *(*) mux(struct devid *dev)
Definition dev.h:47
ssize_t(*) read(struct devid *dev, off_t offset, struct iobuf *io)
Definition dev.h:34
int(*) map(struct devid *dev, struct vm_space *vm_space, struct vm_entry *vm_entry)
Definition dev.h:43
ssize_t(*) write(struct devid *dev, off_t offset, struct iobuf *io)
Definition dev.h:35
char * name
Definition dev.h:29
struct fops fops
Definition dev.h:45
size_t(*) getbs(struct devid *dev)
Definition dev.h:48
int(*) sync(void)
Definition dev.h:49
int(*) ioctl(struct devid *dev, int request, void *argp)
Definition dev.h:42
ssize_t(*) bread(struct devid *dev, off_t lba, size_t count, void *buf)
Definition dev.h:39
ssize_t(*) bwrite(struct devid *dev, off_t lba, size_t count, void *buf)
Definition dev.h:40
Which device: its kind (S_IFCHR or S_IFBLK) and numbers.
Definition dev.h:21
mode_t type
Definition dev.h:22
devid_t major
Definition dev.h:23
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
An open file's operations.
Definition vfs.h:28
int(*) ioctl(struct file *file, int request, void *argp)
Definition vfs.h:35
int(*) close(struct file *file)
Definition vfs.h:34
int(*) can_read(struct file *file, size_t size)
Definition vfs.h:39
ssize_t(*) read(struct file *file, struct iobuf *io)
Definition vfs.h:30
off_t(*) lseek(struct file *file, off_t offset, int whence)
Definition vfs.h:33
ssize_t(*) write(struct file *file, struct iobuf *io)
Definition vfs.h:31
int(*) open(struct file *file)
Definition vfs.h:29
int(*) eof(struct file *)
Definition vfs.h:41
int(*) can_write(struct file *file, size_t size)
Definition vfs.h:40
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A mapping (map entry): a range of an address space, its permissions, and where its pages come from.
Definition vm.h:66
An address space: its mappings, and its page tables.
Definition vm.h:25
uint8_t devid_t
Definition types.h:17
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10