source: rtems-libbsd/rtemsbsd/sys/fs/devfs/devfs_devs.c @ 6afe73d

55-freebsd-126-freebsd-12
Last change on this file since 6afe73d was 880a17c, checked in by Kevin Kirspel <kevin-kirspel@…>, on 05/04/17 at 12:27:59

Adding RTEMS support for FREEBSD TTY

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <machine/rtems-bsd-kernel-space.h>
33
34#include <sys/types.h>
35#include <sys/conf.h>
36#include <sys/kernel.h>
37#include <sys/file.h>
38#include <sys/malloc.h>
39#include <sys/proc.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#include <fs/devfs/devfs_int.h>
45
46#include <machine/pcpu.h>
47
48#include <rtems/imfs.h>
49
50#define DEVFS_ROOTINO 2
51
52const char rtems_cdev_directory[] = RTEMS_CDEV_DIRECTORY;
53
54/*
55 * The one true (but secret) list of active devices in the system.
56 * Locked by dev_lock()/devmtx
57 */
58struct cdev_priv_list cdevp_list = TAILQ_HEAD_INITIALIZER(cdevp_list);
59
60struct unrhdr *devfs_inos;
61
62static MALLOC_DEFINE(M_CDEVP, "DEVFS1", "DEVFS cdev_priv storage");
63
64static struct cdev *
65devfs_imfs_get_context_by_iop(rtems_libio_t *iop)
66{
67        return IMFS_generic_get_context_by_iop(iop);
68}
69
70static int
71devfs_imfs_open(rtems_libio_t *iop, const char *path, int oflag, mode_t mode)
72{
73        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
74        struct file *fp = rtems_bsd_iop_to_fp(iop);
75        struct thread *td = rtems_bsd_get_curthread_or_null();
76        struct file *fpop;
77        int error;
78
79        if (td != NULL) {
80                fpop = td->td_fpop;
81                curthread->td_fpop = fp;
82                error = cdev->si_devsw->d_open(cdev, oflag, 0, td);
83                /* Clean up any cdevpriv upon error. */
84                if (error != 0)
85                        devfs_clear_cdevpriv();
86                curthread->td_fpop = fpop;
87        } else {
88                error = ENOMEM;
89        }
90
91        return rtems_bsd_error_to_status_and_errno(error);
92}
93
94static int
95devfs_imfs_close(rtems_libio_t *iop)
96{
97        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
98        struct file *fp = rtems_bsd_iop_to_fp(iop);
99        struct thread *td = rtems_bsd_get_curthread_or_null();
100        int flags = rtems_libio_to_fcntl_flags(iop->flags);
101        struct file *fpop;
102        int error;
103
104        if (td != NULL) {
105                fpop = td->td_fpop;
106                curthread->td_fpop = fp;
107                error = cdev->si_devsw->d_close(cdev, flags, 0, td);
108                curthread->td_fpop = fpop;
109        } else {
110                error = ENOMEM;
111        }
112
113        return rtems_bsd_error_to_status_and_errno(error);
114}
115
116static ssize_t
117devfs_imfs_readv(rtems_libio_t *iop, const struct iovec *iov, int iovcnt,
118    ssize_t total)
119{
120        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
121        struct file *fp = rtems_bsd_iop_to_fp(iop);
122        struct thread *td = rtems_bsd_get_curthread_or_null();
123        struct uio uio = {
124                .uio_iov = __DECONST(struct iovec *, iov),
125                .uio_iovcnt = iovcnt,
126                .uio_offset = 0,
127                .uio_resid = total,
128                .uio_segflg = UIO_USERSPACE,
129                .uio_rw = UIO_READ,
130                .uio_td = td
131        };
132        struct file *fpop;
133        int error;
134
135        if (td != NULL) {
136                fpop = td->td_fpop;
137                curthread->td_fpop = fp;
138                error = cdev->si_devsw->d_read(cdev, &uio,
139                    rtems_libio_to_fcntl_flags(iop->flags));
140                td->td_fpop = fpop;
141        } else {
142                error = ENOMEM;
143        }
144
145        if (error == 0) {
146                return (total - uio.uio_resid);
147        } else {
148                rtems_set_errno_and_return_minus_one(error);
149        }
150}
151
152static ssize_t
153devfs_imfs_read(rtems_libio_t *iop, void *buffer, size_t count)
154{
155        struct iovec iov = {
156                .iov_base = buffer,
157                .iov_len = count
158        };
159
160        return (devfs_imfs_readv(iop, &iov, 1, count));
161}
162
163static ssize_t
164devfs_imfs_writev(rtems_libio_t *iop, const struct iovec *iov, int iovcnt,
165    ssize_t total)
166{
167        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
168        struct file *fp = rtems_bsd_iop_to_fp(iop);
169        struct thread *td = rtems_bsd_get_curthread_or_null();
170        struct uio uio = {
171                .uio_iov = __DECONST(struct iovec *, iov),
172                .uio_iovcnt = iovcnt,
173                .uio_offset = 0,
174                .uio_resid = total,
175                .uio_segflg = UIO_USERSPACE,
176                .uio_rw = UIO_WRITE,
177                .uio_td = td
178        };
179        struct file *fpop;
180        int error;
181
182        if (td != NULL) {
183                fpop = td->td_fpop;
184                curthread->td_fpop = fp;
185                error = cdev->si_devsw->d_write(cdev, &uio,
186                    rtems_libio_to_fcntl_flags(iop->flags));
187                td->td_fpop = fpop;
188        } else {
189                error = ENOMEM;
190        }
191
192        if (error == 0) {
193                return (total - uio.uio_resid);
194        } else {
195                rtems_set_errno_and_return_minus_one(error);
196        }
197}
198
199static ssize_t
200devfs_imfs_write(rtems_libio_t *iop, const void *buffer, size_t count)
201{
202        struct iovec iov = {
203                .iov_base = __DECONST(void *, buffer),
204                .iov_len = count
205        };
206
207        return (devfs_imfs_writev(iop, &iov, 1, count));
208}
209
210static int
211devfs_imfs_ioctl(rtems_libio_t *iop, ioctl_command_t request, void *buffer)
212{
213        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
214        struct file *fp = rtems_bsd_iop_to_fp(iop);
215        struct thread *td = rtems_bsd_get_curthread_or_null();
216        struct file *fpop;
217        int error;
218        int flags = rtems_libio_to_fcntl_flags(iop->flags);
219
220        if (td != 0) {
221                fpop = td->td_fpop;
222                curthread->td_fpop = fp;
223                error = cdev->si_devsw->d_ioctl(cdev, request, buffer, flags,
224                    td);
225                td->td_fpop = fpop;
226        } else {
227                error = ENOMEM;
228        }
229
230        return (rtems_bsd_error_to_status_and_errno(error));
231}
232
233static int
234devfs_imfs_poll(rtems_libio_t *iop, int events)
235{
236        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
237        struct file *fp = rtems_bsd_iop_to_fp(iop);
238        struct thread *td = rtems_bsd_get_curthread_or_wait_forever();
239        struct file *fpop;
240        int error;
241
242        fpop = td->td_fpop;
243        curthread->td_fpop = fp;
244        error = cdev->si_devsw->d_poll(cdev, events, td);
245        td->td_fpop = fpop;
246
247        return error;
248}
249
250static int
251devfs_imfs_kqfilter(rtems_libio_t *iop, struct knote *kn)
252{
253        struct cdev *cdev = devfs_imfs_get_context_by_iop(iop);
254        struct file *fp = rtems_bsd_iop_to_fp(iop);
255        struct thread *td = rtems_bsd_get_curthread_or_wait_forever();
256        struct file *fpop;
257        int error;
258
259        fpop = td->td_fpop;
260        curthread->td_fpop = fp;
261        error = cdev->si_devsw->d_kqfilter(cdev, kn);
262        td->td_fpop = fpop;
263
264        return error;
265}
266
267static const rtems_filesystem_file_handlers_r devfs_imfs_handlers = {
268        .open_h = devfs_imfs_open,
269        .close_h = devfs_imfs_close,
270        .read_h = devfs_imfs_read,
271        .write_h = devfs_imfs_write,
272        .ioctl_h = devfs_imfs_ioctl,
273        .lseek_h = rtems_filesystem_default_lseek_file,
274        .fstat_h = rtems_filesystem_default_fstat,
275        .ftruncate_h = rtems_filesystem_default_ftruncate,
276        .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
277        .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
278        .fcntl_h = rtems_filesystem_default_fcntl,
279        .poll_h = devfs_imfs_poll,
280        .kqfilter_h = devfs_imfs_kqfilter,
281        .readv_h = devfs_imfs_readv,
282        .writev_h = devfs_imfs_writev,
283};
284
285static const IMFS_node_control devfs_imfs_control = IMFS_GENERIC_INITIALIZER(
286    &devfs_imfs_handlers, IMFS_node_initialize_generic,
287    IMFS_node_destroy_default);
288
289struct cdev *
290devfs_alloc(int flags)
291{
292        struct cdev_priv *cdp;
293        struct cdev *cdev;
294
295        cdp = malloc(sizeof *cdp, M_CDEVP, M_ZERO |
296            ((flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK));
297        if (cdp == NULL)
298                return (NULL);
299
300        cdev = &cdp->cdp_c;
301        LIST_INIT(&cdev->si_children);
302
303        memcpy(cdev->si_path, rtems_cdev_directory, sizeof(cdev->si_path));
304        return (cdev);
305}
306
307void
308devfs_free(struct cdev *cdev)
309{
310        struct cdev_priv *cdp;
311
312        cdp = cdev2priv(cdev);
313        devfs_free_cdp_inode(cdp->cdp_inode);
314        free(cdp, M_CDEVP);
315}
316
317/*
318 * Create the directory for a device.
319 * Note: This don't uses dirname() because this function is not defined thread
320 * save in POSIX.
321 */
322static void
323devfs_create_directory(const char *devname)
324{
325        char *dir = NULL;
326        char *lastsep = NULL;
327        int rv;
328        mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
329
330        dir = strdup(devname, M_TEMP);
331        BSD_ASSERT(dir != NULL);
332
333        lastsep = strrchr(dir, '/');
334        if(lastsep != NULL) {
335                *lastsep = 0;
336                rv = rtems_mkdir(dir, mode);
337                BSD_ASSERT(rv == 0);
338        }
339
340        free(dir, M_TEMP);
341}
342
343/*
344 * devfs_create() and devfs_destroy() are called from kern_conf.c and
345 * in both cases the devlock() mutex is held, so no further locking
346 * is necesary and no sleeping allowed.
347 */
348
349void
350devfs_create(struct cdev *dev)
351{
352        struct cdev_priv *cdp;
353        int rv;
354        mode_t mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO;
355
356        devfs_create_directory(dev->si_path);
357
358        rv = IMFS_make_generic_node(dev->si_path, mode, &devfs_imfs_control,
359            dev);
360        BSD_ASSERT(rv == 0);
361
362        cdp = cdev2priv(dev);
363        cdp->cdp_flags |= CDP_ACTIVE;
364        cdp->cdp_inode = alloc_unrl(devfs_inos);
365        dev_refl(dev);
366        TAILQ_INSERT_TAIL(&cdevp_list, cdp, cdp_list);
367}
368
369void
370devfs_destroy(struct cdev *dev)
371{
372        struct cdev_priv *cdp;
373        int rv;
374
375        cdp = cdev2priv(dev);
376        cdp->cdp_flags &= ~CDP_ACTIVE;
377
378        rv = unlink(dev->si_path);
379        BSD_ASSERT(rv == 0);
380
381        /* FIXME: Check if directory is empty and remove it. */
382}
383
384int
385devfs_dev_exists(const char *name)
386{
387        const size_t dirlen = sizeof(rtems_cdev_directory) - 1;
388        const size_t maxnamelen = SPECNAMELEN;
389
390        int rv;
391        char fullpath[dirlen + maxnamelen + 1];
392
393        memcpy(fullpath, rtems_cdev_directory, dirlen);
394        strncpy(fullpath + dirlen, name, maxnamelen);
395
396        rv = access(fullpath, F_OK);
397
398        if(rv == 0)
399                return 1;
400        else
401                return 0;
402}
403
404ino_t
405devfs_alloc_cdp_inode(void)
406{
407
408        return (alloc_unr(devfs_inos));
409}
410
411void
412devfs_free_cdp_inode(ino_t ino)
413{
414
415        if (ino > 0)
416                free_unr(devfs_inos, ino);
417}
418
419static void
420        devfs_devs_init(void *junk __unused)
421{
422
423        devfs_inos = new_unrhdr(DEVFS_ROOTINO + 1, INT_MAX, &devmtx);
424}
425
426SYSINIT(devfs_devs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_devs_init, NULL);
Note: See TracBrowser for help on using the repository browser.