10ca3913dSOlivier Deprez /* 2*c56a85d0SHarrison Mutai * Copyright (c) 2019-2025, Arm Limited. All rights reserved. 30ca3913dSOlivier Deprez * 40ca3913dSOlivier Deprez * SPDX-License-Identifier: BSD-3-Clause 50ca3913dSOlivier Deprez */ 60ca3913dSOlivier Deprez 70ca3913dSOlivier Deprez #include <cdefs.h> 80ca3913dSOlivier Deprez #include <common/debug.h> 90ca3913dSOlivier Deprez #include <lib/debugfs.h> 100ca3913dSOlivier Deprez #include <string.h> 110ca3913dSOlivier Deprez 120ca3913dSOlivier Deprez #include "dev.h" 130ca3913dSOlivier Deprez 140ca3913dSOlivier Deprez #define NR_MOUNT_POINTS 4 150ca3913dSOlivier Deprez 160ca3913dSOlivier Deprez struct mount_point { 170ca3913dSOlivier Deprez chan_t *new; 180ca3913dSOlivier Deprez chan_t *old; 190ca3913dSOlivier Deprez }; 200ca3913dSOlivier Deprez 210ca3913dSOlivier Deprez /* This array contains all the available channels of the filesystem. 220ca3913dSOlivier Deprez * A file descriptor is the index of a specific channel in this array. 230ca3913dSOlivier Deprez */ 240ca3913dSOlivier Deprez static chan_t fdset[NR_CHANS]; 250ca3913dSOlivier Deprez 260ca3913dSOlivier Deprez /* This array contains all the available mount points of the filesystem. */ 270ca3913dSOlivier Deprez static struct mount_point mount_points[NR_MOUNT_POINTS]; 280ca3913dSOlivier Deprez 290ca3913dSOlivier Deprez /* This variable stores the channel associated to the root directory. */ 300ca3913dSOlivier Deprez static chan_t slash_channel; 310ca3913dSOlivier Deprez 320ca3913dSOlivier Deprez /* This function creates a channel from a device index and registers 330ca3913dSOlivier Deprez * it to fdset. 340ca3913dSOlivier Deprez */ 350ca3913dSOlivier Deprez static chan_t *create_new_channel(unsigned char index) 360ca3913dSOlivier Deprez { 370ca3913dSOlivier Deprez chan_t *channel = NULL; 380ca3913dSOlivier Deprez int i; 390ca3913dSOlivier Deprez 400ca3913dSOlivier Deprez for (i = 0; i < NR_CHANS; i++) { 410ca3913dSOlivier Deprez if (fdset[i].index == NODEV) { 420ca3913dSOlivier Deprez channel = &fdset[i]; 430ca3913dSOlivier Deprez channel->index = index; 440ca3913dSOlivier Deprez break; 450ca3913dSOlivier Deprez } 460ca3913dSOlivier Deprez } 470ca3913dSOlivier Deprez 480ca3913dSOlivier Deprez return channel; 490ca3913dSOlivier Deprez } 500ca3913dSOlivier Deprez 510ca3913dSOlivier Deprez /******************************************************************************* 520ca3913dSOlivier Deprez * This function returns a pointer to an existing channel in fdset from a file 530ca3913dSOlivier Deprez * descriptor. 540ca3913dSOlivier Deprez ******************************************************************************/ 550ca3913dSOlivier Deprez static chan_t *fd_to_channel(int fd) 560ca3913dSOlivier Deprez { 570ca3913dSOlivier Deprez if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) { 580ca3913dSOlivier Deprez return NULL; 590ca3913dSOlivier Deprez } 600ca3913dSOlivier Deprez 610ca3913dSOlivier Deprez return &fdset[fd]; 620ca3913dSOlivier Deprez } 630ca3913dSOlivier Deprez 640ca3913dSOlivier Deprez /******************************************************************************* 650ca3913dSOlivier Deprez * This function returns a file descriptor from a channel. 660ca3913dSOlivier Deprez * The caller must be sure that the channel is registered in fdset. 670ca3913dSOlivier Deprez ******************************************************************************/ 680ca3913dSOlivier Deprez static int channel_to_fd(chan_t *channel) 690ca3913dSOlivier Deprez { 700ca3913dSOlivier Deprez return (channel == NULL) ? -1 : (channel - fdset); 710ca3913dSOlivier Deprez } 720ca3913dSOlivier Deprez 730ca3913dSOlivier Deprez /******************************************************************************* 740ca3913dSOlivier Deprez * This function checks the validity of a mode. 750ca3913dSOlivier Deprez ******************************************************************************/ 760ca3913dSOlivier Deprez static bool is_valid_mode(int mode) 770ca3913dSOlivier Deprez { 780ca3913dSOlivier Deprez if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) { 790ca3913dSOlivier Deprez return false; 800ca3913dSOlivier Deprez } 810ca3913dSOlivier Deprez if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) { 820ca3913dSOlivier Deprez return false; 830ca3913dSOlivier Deprez } 840ca3913dSOlivier Deprez if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) { 850ca3913dSOlivier Deprez return false; 860ca3913dSOlivier Deprez } 870ca3913dSOlivier Deprez 880ca3913dSOlivier Deprez return true; 890ca3913dSOlivier Deprez } 900ca3913dSOlivier Deprez 910ca3913dSOlivier Deprez /******************************************************************************* 920ca3913dSOlivier Deprez * This function extracts the next part of the given path contained and puts it 930ca3913dSOlivier Deprez * in token. It returns a pointer to the remainder of the path. 940ca3913dSOlivier Deprez ******************************************************************************/ 950ca3913dSOlivier Deprez static const char *next(const char *path, char *token) 960ca3913dSOlivier Deprez { 970ca3913dSOlivier Deprez int index; 980ca3913dSOlivier Deprez const char *cursor; 990ca3913dSOlivier Deprez 1000ca3913dSOlivier Deprez while (*path == '/') { 1010ca3913dSOlivier Deprez ++path; 1020ca3913dSOlivier Deprez } 1030ca3913dSOlivier Deprez 1040ca3913dSOlivier Deprez index = 0; 1050ca3913dSOlivier Deprez cursor = path; 1060ca3913dSOlivier Deprez if (*path != '\0') { 1070ca3913dSOlivier Deprez while (*cursor != '/' && *cursor != '\0') { 1080ca3913dSOlivier Deprez if (index == NAMELEN) { 1090ca3913dSOlivier Deprez return NULL; 1100ca3913dSOlivier Deprez } 1110ca3913dSOlivier Deprez token[index++] = *cursor++; 1120ca3913dSOlivier Deprez } 1130ca3913dSOlivier Deprez } 1140ca3913dSOlivier Deprez token[index] = '\0'; 1150ca3913dSOlivier Deprez 1160ca3913dSOlivier Deprez return cursor; 1170ca3913dSOlivier Deprez } 1180ca3913dSOlivier Deprez 1190ca3913dSOlivier Deprez /******************************************************************************* 1200ca3913dSOlivier Deprez * This function returns the driver index in devtab of the driver 1210ca3913dSOlivier Deprez * identified by id. 1220ca3913dSOlivier Deprez ******************************************************************************/ 1230ca3913dSOlivier Deprez static int get_device_index(int id) 1240ca3913dSOlivier Deprez { 1250ca3913dSOlivier Deprez int index; 1260ca3913dSOlivier Deprez dev_t * const *dp; 1270ca3913dSOlivier Deprez 1280ca3913dSOlivier Deprez for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) { 1290ca3913dSOlivier Deprez index++; 1300ca3913dSOlivier Deprez } 1310ca3913dSOlivier Deprez 1320ca3913dSOlivier Deprez if (*dp == NULL) { 1330ca3913dSOlivier Deprez return -1; 1340ca3913dSOlivier Deprez } 1350ca3913dSOlivier Deprez 1360ca3913dSOlivier Deprez return index; 1370ca3913dSOlivier Deprez } 1380ca3913dSOlivier Deprez 1390ca3913dSOlivier Deprez /******************************************************************************* 1400ca3913dSOlivier Deprez * This function clears a given channel fields 1410ca3913dSOlivier Deprez ******************************************************************************/ 1420ca3913dSOlivier Deprez static void channel_clear(chan_t *channel) 1430ca3913dSOlivier Deprez { 1440ca3913dSOlivier Deprez channel->offset = 0; 1450ca3913dSOlivier Deprez channel->qid = 0; 1460ca3913dSOlivier Deprez channel->index = NODEV; 1470ca3913dSOlivier Deprez channel->dev = 0; 1480ca3913dSOlivier Deprez channel->mode = 0; 1490ca3913dSOlivier Deprez } 1500ca3913dSOlivier Deprez 1510ca3913dSOlivier Deprez /******************************************************************************* 1520ca3913dSOlivier Deprez * This function closes the channel pointed to by c. 1530ca3913dSOlivier Deprez ******************************************************************************/ 1540ca3913dSOlivier Deprez void channel_close(chan_t *channel) 1550ca3913dSOlivier Deprez { 1560ca3913dSOlivier Deprez if (channel != NULL) { 1570ca3913dSOlivier Deprez channel_clear(channel); 1580ca3913dSOlivier Deprez } 1590ca3913dSOlivier Deprez } 1600ca3913dSOlivier Deprez 1610ca3913dSOlivier Deprez /******************************************************************************* 1620ca3913dSOlivier Deprez * This function copies data from src to dst after applying the offset of the 1630ca3913dSOlivier Deprez * channel c. nbytes bytes are expected to be copied unless the data goes over 1640ca3913dSOlivier Deprez * dst + len. 1650ca3913dSOlivier Deprez * It returns the actual number of bytes that were copied. 1660ca3913dSOlivier Deprez ******************************************************************************/ 167*c56a85d0SHarrison Mutai int buf_to_channel(chan_t *channel, void *dst, void *src, size_t nbytes, long len) 1680ca3913dSOlivier Deprez { 1690ca3913dSOlivier Deprez const char *addr = src; 1700ca3913dSOlivier Deprez 1710ca3913dSOlivier Deprez if ((channel == NULL) || (dst == NULL) || (src == NULL)) { 1720ca3913dSOlivier Deprez return 0; 1730ca3913dSOlivier Deprez } 1740ca3913dSOlivier Deprez 1750ca3913dSOlivier Deprez if (channel->offset >= len) { 1760ca3913dSOlivier Deprez return 0; 1770ca3913dSOlivier Deprez } 1780ca3913dSOlivier Deprez 1790ca3913dSOlivier Deprez if ((channel->offset + nbytes) > len) { 1800ca3913dSOlivier Deprez nbytes = len - channel->offset; 1810ca3913dSOlivier Deprez } 1820ca3913dSOlivier Deprez 1830ca3913dSOlivier Deprez memcpy(dst, addr + channel->offset, nbytes); 1840ca3913dSOlivier Deprez 1850ca3913dSOlivier Deprez channel->offset += nbytes; 1860ca3913dSOlivier Deprez 1870ca3913dSOlivier Deprez return nbytes; 1880ca3913dSOlivier Deprez } 1890ca3913dSOlivier Deprez 1900ca3913dSOlivier Deprez /******************************************************************************* 1910ca3913dSOlivier Deprez * This function checks whether a channel (identified by its device index and 1920ca3913dSOlivier Deprez * qid) is registered as a mount point. 1930ca3913dSOlivier Deprez * Returns a pointer to the channel it is mounted to when found, NULL otherwise. 1940ca3913dSOlivier Deprez ******************************************************************************/ 1950ca3913dSOlivier Deprez static chan_t *mount_point_to_channel(int index, qid_t qid) 1960ca3913dSOlivier Deprez { 1970ca3913dSOlivier Deprez chan_t *channel; 1980ca3913dSOlivier Deprez struct mount_point *mp; 1990ca3913dSOlivier Deprez 2000ca3913dSOlivier Deprez for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) { 2010ca3913dSOlivier Deprez channel = mp->new; 2020ca3913dSOlivier Deprez if (channel == NULL) { 2030ca3913dSOlivier Deprez continue; 2040ca3913dSOlivier Deprez } 2050ca3913dSOlivier Deprez 2060ca3913dSOlivier Deprez if ((channel->index == index) && (channel->qid == qid)) { 2070ca3913dSOlivier Deprez return mp->old; 2080ca3913dSOlivier Deprez } 2090ca3913dSOlivier Deprez } 2100ca3913dSOlivier Deprez 2110ca3913dSOlivier Deprez return NULL; 2120ca3913dSOlivier Deprez } 2130ca3913dSOlivier Deprez 2140ca3913dSOlivier Deprez /******************************************************************************* 2150ca3913dSOlivier Deprez * This function calls the attach function of the driver identified by id. 2160ca3913dSOlivier Deprez ******************************************************************************/ 2170ca3913dSOlivier Deprez chan_t *attach(int id, int dev) 2180ca3913dSOlivier Deprez { 2190ca3913dSOlivier Deprez /* Get the devtab index for the driver identified by id */ 2200ca3913dSOlivier Deprez int index = get_device_index(id); 2210ca3913dSOlivier Deprez 2220ca3913dSOlivier Deprez if (index < 0) { 2230ca3913dSOlivier Deprez return NULL; 2240ca3913dSOlivier Deprez } 2250ca3913dSOlivier Deprez 2260ca3913dSOlivier Deprez return devtab[index]->attach(id, dev); 2270ca3913dSOlivier Deprez } 2280ca3913dSOlivier Deprez 2290ca3913dSOlivier Deprez /******************************************************************************* 2300ca3913dSOlivier Deprez * This function is the default implementation of the driver attach function. 2310ca3913dSOlivier Deprez * It creates a new channel and returns a pointer to it. 2320ca3913dSOlivier Deprez ******************************************************************************/ 2330ca3913dSOlivier Deprez chan_t *devattach(int id, int dev) 2340ca3913dSOlivier Deprez { 2350ca3913dSOlivier Deprez chan_t *channel; 2360ca3913dSOlivier Deprez int index; 2370ca3913dSOlivier Deprez 2380ca3913dSOlivier Deprez index = get_device_index(id); 2390ca3913dSOlivier Deprez if (index < 0) { 2400ca3913dSOlivier Deprez return NULL; 2410ca3913dSOlivier Deprez } 2420ca3913dSOlivier Deprez 2430ca3913dSOlivier Deprez channel = create_new_channel(index); 2440ca3913dSOlivier Deprez if (channel == NULL) { 2450ca3913dSOlivier Deprez return NULL; 2460ca3913dSOlivier Deprez } 2470ca3913dSOlivier Deprez 2480ca3913dSOlivier Deprez channel->dev = dev; 2490ca3913dSOlivier Deprez channel->qid = CHDIR; 2500ca3913dSOlivier Deprez 2510ca3913dSOlivier Deprez return channel; 2520ca3913dSOlivier Deprez } 2530ca3913dSOlivier Deprez 2540ca3913dSOlivier Deprez /******************************************************************************* 2550ca3913dSOlivier Deprez * This function returns a channel given a path. 2560ca3913dSOlivier Deprez * It goes through the filesystem, from the root namespace ('/') or from a 2570ca3913dSOlivier Deprez * device namespace ('#'), switching channel on mount points. 2580ca3913dSOlivier Deprez ******************************************************************************/ 2590ca3913dSOlivier Deprez chan_t *path_to_channel(const char *path, int mode) 2600ca3913dSOlivier Deprez { 2610ca3913dSOlivier Deprez int i, n; 2620ca3913dSOlivier Deprez const char *path_next; 2630ca3913dSOlivier Deprez chan_t *mnt, *channel; 2640ca3913dSOlivier Deprez char elem[NAMELEN]; 2650ca3913dSOlivier Deprez 2660ca3913dSOlivier Deprez if (path == NULL) { 2670ca3913dSOlivier Deprez return NULL; 2680ca3913dSOlivier Deprez } 2690ca3913dSOlivier Deprez 2700ca3913dSOlivier Deprez switch (path[0]) { 2710ca3913dSOlivier Deprez case '/': 2720ca3913dSOlivier Deprez channel = clone(&slash_channel, NULL); 2730ca3913dSOlivier Deprez path_next = path; 2740ca3913dSOlivier Deprez break; 2750ca3913dSOlivier Deprez case '#': 2760ca3913dSOlivier Deprez path_next = next(path + 1, elem); 2770ca3913dSOlivier Deprez if (path_next == NULL) { 2780ca3913dSOlivier Deprez goto noent; 2790ca3913dSOlivier Deprez } 2800ca3913dSOlivier Deprez 2810ca3913dSOlivier Deprez n = 0; 2820ca3913dSOlivier Deprez for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) { 2830ca3913dSOlivier Deprez n += elem[i] - '0'; 2840ca3913dSOlivier Deprez } 2850ca3913dSOlivier Deprez 2860ca3913dSOlivier Deprez if (elem[i] != '\0') { 2870ca3913dSOlivier Deprez goto noent; 2880ca3913dSOlivier Deprez } 2890ca3913dSOlivier Deprez 2900ca3913dSOlivier Deprez channel = attach(elem[0], n); 2910ca3913dSOlivier Deprez break; 2920ca3913dSOlivier Deprez default: 2930ca3913dSOlivier Deprez return NULL; 2940ca3913dSOlivier Deprez } 2950ca3913dSOlivier Deprez 2960ca3913dSOlivier Deprez if (channel == NULL) { 2970ca3913dSOlivier Deprez return NULL; 2980ca3913dSOlivier Deprez } 2990ca3913dSOlivier Deprez 3000ca3913dSOlivier Deprez for (path_next = next(path_next, elem); *elem; 3010ca3913dSOlivier Deprez path_next = next(path_next, elem)) { 3020ca3913dSOlivier Deprez if ((channel->qid & CHDIR) == 0) { 3030ca3913dSOlivier Deprez goto notfound; 3040ca3913dSOlivier Deprez } 3050ca3913dSOlivier Deprez 3060ca3913dSOlivier Deprez if (devtab[channel->index]->walk(channel, elem) < 0) { 3070ca3913dSOlivier Deprez channel_close(channel); 3080ca3913dSOlivier Deprez goto notfound; 3090ca3913dSOlivier Deprez } 3100ca3913dSOlivier Deprez 3110ca3913dSOlivier Deprez mnt = mount_point_to_channel(channel->index, channel->qid); 3120ca3913dSOlivier Deprez if (mnt != NULL) { 3130ca3913dSOlivier Deprez clone(mnt, channel); 3140ca3913dSOlivier Deprez } 3150ca3913dSOlivier Deprez } 3160ca3913dSOlivier Deprez 3170ca3913dSOlivier Deprez if (path_next == NULL) { 3180ca3913dSOlivier Deprez goto notfound; 3190ca3913dSOlivier Deprez } 3200ca3913dSOlivier Deprez 3210ca3913dSOlivier Deprez /* TODO: check mode */ 3220ca3913dSOlivier Deprez return channel; 3230ca3913dSOlivier Deprez 3240ca3913dSOlivier Deprez notfound: 3250ca3913dSOlivier Deprez channel_close(channel); 3260ca3913dSOlivier Deprez noent: 3270ca3913dSOlivier Deprez return NULL; 3280ca3913dSOlivier Deprez } 3290ca3913dSOlivier Deprez 3300ca3913dSOlivier Deprez /******************************************************************************* 3310ca3913dSOlivier Deprez * This function calls the clone function of the driver associated to the 3320ca3913dSOlivier Deprez * channel c. 3330ca3913dSOlivier Deprez ******************************************************************************/ 3340ca3913dSOlivier Deprez chan_t *clone(chan_t *c, chan_t *nc) 3350ca3913dSOlivier Deprez { 336b226c747SZelalem if (c->index == NODEV) { 337b226c747SZelalem return NULL; 338b226c747SZelalem } 339b226c747SZelalem 3400ca3913dSOlivier Deprez return devtab[c->index]->clone(c, nc); 3410ca3913dSOlivier Deprez } 3420ca3913dSOlivier Deprez 3430ca3913dSOlivier Deprez /******************************************************************************* 3440ca3913dSOlivier Deprez * This function is the default implementation of the driver clone function. 3450ca3913dSOlivier Deprez * It creates a new channel and returns a pointer to it. 3460ca3913dSOlivier Deprez * It clones channel into new_channel. 3470ca3913dSOlivier Deprez ******************************************************************************/ 3480ca3913dSOlivier Deprez chan_t *devclone(chan_t *channel, chan_t *new_channel) 3490ca3913dSOlivier Deprez { 3500ca3913dSOlivier Deprez if (channel == NULL) { 3510ca3913dSOlivier Deprez return NULL; 3520ca3913dSOlivier Deprez } 3530ca3913dSOlivier Deprez 3540ca3913dSOlivier Deprez if (new_channel == NULL) { 3550ca3913dSOlivier Deprez new_channel = create_new_channel(channel->index); 3560ca3913dSOlivier Deprez if (new_channel == NULL) { 3570ca3913dSOlivier Deprez return NULL; 3580ca3913dSOlivier Deprez } 3590ca3913dSOlivier Deprez } 3600ca3913dSOlivier Deprez 3610ca3913dSOlivier Deprez new_channel->qid = channel->qid; 3620ca3913dSOlivier Deprez new_channel->dev = channel->dev; 3630ca3913dSOlivier Deprez new_channel->mode = channel->mode; 3640ca3913dSOlivier Deprez new_channel->offset = channel->offset; 3650ca3913dSOlivier Deprez new_channel->index = channel->index; 3660ca3913dSOlivier Deprez 3670ca3913dSOlivier Deprez return new_channel; 3680ca3913dSOlivier Deprez } 3690ca3913dSOlivier Deprez 3700ca3913dSOlivier Deprez /******************************************************************************* 3710ca3913dSOlivier Deprez * This function is the default implementation of the driver walk function. 3720ca3913dSOlivier Deprez * It goes through all the elements of tab using the gen function until a match 3730ca3913dSOlivier Deprez * is found with name. 3740ca3913dSOlivier Deprez * If a match is found, it copies the qid of the new directory. 3750ca3913dSOlivier Deprez ******************************************************************************/ 3760ca3913dSOlivier Deprez int devwalk(chan_t *channel, const char *name, const dirtab_t *tab, 3770ca3913dSOlivier Deprez int ntab, devgen_t *gen) 3780ca3913dSOlivier Deprez { 3790ca3913dSOlivier Deprez int i; 3800ca3913dSOlivier Deprez dir_t dir; 3810ca3913dSOlivier Deprez 3820ca3913dSOlivier Deprez if ((channel == NULL) || (name == NULL) || (gen == NULL)) { 3830ca3913dSOlivier Deprez return -1; 3840ca3913dSOlivier Deprez } 3850ca3913dSOlivier Deprez 3860ca3913dSOlivier Deprez if ((name[0] == '.') && (name[1] == '\0')) { 3870ca3913dSOlivier Deprez return 1; 3880ca3913dSOlivier Deprez } 3890ca3913dSOlivier Deprez 3900ca3913dSOlivier Deprez for (i = 0; ; i++) { 3910ca3913dSOlivier Deprez switch ((*gen)(channel, tab, ntab, i, &dir)) { 3920ca3913dSOlivier Deprez case 0: 3930ca3913dSOlivier Deprez /* Intentional fall-through */ 3940ca3913dSOlivier Deprez case -1: 3950ca3913dSOlivier Deprez return -1; 3960ca3913dSOlivier Deprez case 1: 3970ca3913dSOlivier Deprez if (strncmp(name, dir.name, NAMELEN) != 0) { 3980ca3913dSOlivier Deprez continue; 3990ca3913dSOlivier Deprez } 4000ca3913dSOlivier Deprez channel->qid = dir.qid; 4010ca3913dSOlivier Deprez return 1; 4020ca3913dSOlivier Deprez } 4030ca3913dSOlivier Deprez } 4040ca3913dSOlivier Deprez } 4050ca3913dSOlivier Deprez 4060ca3913dSOlivier Deprez /******************************************************************************* 4070ca3913dSOlivier Deprez * This is a helper function which exposes the content of a directory, element 4080ca3913dSOlivier Deprez * by element. It is meant to be called until the end of the directory is 4090ca3913dSOlivier Deprez * reached or an error occurs. 4100ca3913dSOlivier Deprez * It returns -1 on error, 0 on end of directory and 1 when a new file is found. 4110ca3913dSOlivier Deprez ******************************************************************************/ 4120ca3913dSOlivier Deprez int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab, 4130ca3913dSOlivier Deprez int ntab, devgen_t *gen) 4140ca3913dSOlivier Deprez { 4150ca3913dSOlivier Deprez int i, ret; 4160ca3913dSOlivier Deprez 4170ca3913dSOlivier Deprez if ((channel == NULL) || (dir == NULL) || (gen == NULL)) { 4180ca3913dSOlivier Deprez return -1; 4190ca3913dSOlivier Deprez } 4200ca3913dSOlivier Deprez 4210ca3913dSOlivier Deprez i = channel->offset/sizeof(dir_t); 4220ca3913dSOlivier Deprez ret = (*gen)(channel, tab, ntab, i, dir); 4230ca3913dSOlivier Deprez if (ret == 1) { 4240ca3913dSOlivier Deprez channel->offset += sizeof(dir_t); 4250ca3913dSOlivier Deprez } 4260ca3913dSOlivier Deprez 4270ca3913dSOlivier Deprez return ret; 4280ca3913dSOlivier Deprez } 4290ca3913dSOlivier Deprez 4300ca3913dSOlivier Deprez /******************************************************************************* 4310ca3913dSOlivier Deprez * This function sets the elements of dir. 4320ca3913dSOlivier Deprez ******************************************************************************/ 4330ca3913dSOlivier Deprez void make_dir_entry(chan_t *channel, dir_t *dir, 4340ca3913dSOlivier Deprez const char *name, long length, qid_t qid, unsigned int mode) 4350ca3913dSOlivier Deprez { 4360ca3913dSOlivier Deprez if ((channel == NULL) || (dir == NULL) || (name == NULL)) { 4370ca3913dSOlivier Deprez return; 4380ca3913dSOlivier Deprez } 4390ca3913dSOlivier Deprez 4400ca3913dSOlivier Deprez strlcpy(dir->name, name, sizeof(dir->name)); 4410ca3913dSOlivier Deprez dir->length = length; 4420ca3913dSOlivier Deprez dir->qid = qid; 4430ca3913dSOlivier Deprez dir->mode = mode; 4440ca3913dSOlivier Deprez 4450ca3913dSOlivier Deprez if ((qid & CHDIR) != 0) { 4460ca3913dSOlivier Deprez dir->mode |= O_DIR; 4470ca3913dSOlivier Deprez } 4480ca3913dSOlivier Deprez 4490ca3913dSOlivier Deprez dir->index = channel->index; 4500ca3913dSOlivier Deprez dir->dev = channel->dev; 4510ca3913dSOlivier Deprez } 4520ca3913dSOlivier Deprez 4530ca3913dSOlivier Deprez /******************************************************************************* 4540ca3913dSOlivier Deprez * This function is the default implementation of the internal driver gen 4550ca3913dSOlivier Deprez * function. 4560ca3913dSOlivier Deprez * It copies and formats the information of the nth element of tab into dir. 4570ca3913dSOlivier Deprez ******************************************************************************/ 4580ca3913dSOlivier Deprez int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir) 4590ca3913dSOlivier Deprez { 4600ca3913dSOlivier Deprez const dirtab_t *dp; 4610ca3913dSOlivier Deprez 4620ca3913dSOlivier Deprez if ((channel == NULL) || (dir == NULL) || (tab == NULL) || 4630ca3913dSOlivier Deprez (n >= ntab)) { 4640ca3913dSOlivier Deprez return 0; 4650ca3913dSOlivier Deprez } 4660ca3913dSOlivier Deprez 4670ca3913dSOlivier Deprez dp = &tab[n]; 4680ca3913dSOlivier Deprez make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm); 4690ca3913dSOlivier Deprez return 1; 4700ca3913dSOlivier Deprez } 4710ca3913dSOlivier Deprez 4720ca3913dSOlivier Deprez /******************************************************************************* 4730ca3913dSOlivier Deprez * This function returns a file descriptor identifying the channel associated to 4740ca3913dSOlivier Deprez * the given path. 4750ca3913dSOlivier Deprez ******************************************************************************/ 4760ca3913dSOlivier Deprez int open(const char *path, int mode) 4770ca3913dSOlivier Deprez { 4780ca3913dSOlivier Deprez chan_t *channel; 4790ca3913dSOlivier Deprez 4800ca3913dSOlivier Deprez if (path == NULL) { 4810ca3913dSOlivier Deprez return -1; 4820ca3913dSOlivier Deprez } 4830ca3913dSOlivier Deprez 4840ca3913dSOlivier Deprez if (is_valid_mode(mode) == false) { 4850ca3913dSOlivier Deprez return -1; 4860ca3913dSOlivier Deprez } 4870ca3913dSOlivier Deprez 4880ca3913dSOlivier Deprez channel = path_to_channel(path, mode); 4890ca3913dSOlivier Deprez 4900ca3913dSOlivier Deprez return channel_to_fd(channel); 4910ca3913dSOlivier Deprez } 4920ca3913dSOlivier Deprez 4930ca3913dSOlivier Deprez /******************************************************************************* 4940ca3913dSOlivier Deprez * This function closes the channel identified by the file descriptor fd. 4950ca3913dSOlivier Deprez ******************************************************************************/ 4960ca3913dSOlivier Deprez int close(int fd) 4970ca3913dSOlivier Deprez { 4980ca3913dSOlivier Deprez chan_t *channel; 4990ca3913dSOlivier Deprez 5000ca3913dSOlivier Deprez channel = fd_to_channel(fd); 5010ca3913dSOlivier Deprez if (channel == NULL) { 5020ca3913dSOlivier Deprez return -1; 5030ca3913dSOlivier Deprez } 5040ca3913dSOlivier Deprez 5050ca3913dSOlivier Deprez channel_close(channel); 5060ca3913dSOlivier Deprez return 0; 5070ca3913dSOlivier Deprez } 5080ca3913dSOlivier Deprez 5090ca3913dSOlivier Deprez /******************************************************************************* 5100ca3913dSOlivier Deprez * This function is the default implementation of the driver stat function. 5110ca3913dSOlivier Deprez * It goes through all the elements of tab using the gen function until a match 5120ca3913dSOlivier Deprez * is found with file. 5130ca3913dSOlivier Deprez * If a match is found, dir contains the information file. 5140ca3913dSOlivier Deprez ******************************************************************************/ 5150ca3913dSOlivier Deprez int devstat(chan_t *dirc, const char *file, dir_t *dir, 5160ca3913dSOlivier Deprez const dirtab_t *tab, int ntab, devgen_t *gen) 5170ca3913dSOlivier Deprez { 5180ca3913dSOlivier Deprez int i, r = 0; 5190ca3913dSOlivier Deprez chan_t *c, *mnt; 5200ca3913dSOlivier Deprez 5210ca3913dSOlivier Deprez if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) { 5220ca3913dSOlivier Deprez return -1; 5230ca3913dSOlivier Deprez } 5240ca3913dSOlivier Deprez 5250ca3913dSOlivier Deprez c = path_to_channel(file, O_STAT); 5260ca3913dSOlivier Deprez if (c == NULL) { 5270ca3913dSOlivier Deprez return -1; 5280ca3913dSOlivier Deprez } 5290ca3913dSOlivier Deprez 5300ca3913dSOlivier Deprez for (i = 0; ; i++) { 5310ca3913dSOlivier Deprez switch ((*gen)(dirc, tab, ntab, i, dir)) { 5320ca3913dSOlivier Deprez case 0: 5330ca3913dSOlivier Deprez /* Intentional fall-through */ 5340ca3913dSOlivier Deprez case -1: 5350ca3913dSOlivier Deprez r = -1; 5360ca3913dSOlivier Deprez goto leave; 5370ca3913dSOlivier Deprez case 1: 5380ca3913dSOlivier Deprez mnt = mount_point_to_channel(dir->index, dir->qid); 5390ca3913dSOlivier Deprez if (mnt != NULL) { 5400ca3913dSOlivier Deprez dir->qid = mnt->qid; 5410ca3913dSOlivier Deprez dir->index = mnt->index; 5420ca3913dSOlivier Deprez } 5430ca3913dSOlivier Deprez 5440ca3913dSOlivier Deprez if ((dir->qid != c->qid) || (dir->index != c->index)) { 5450ca3913dSOlivier Deprez continue; 5460ca3913dSOlivier Deprez } 5470ca3913dSOlivier Deprez 5480ca3913dSOlivier Deprez goto leave; 5490ca3913dSOlivier Deprez } 5500ca3913dSOlivier Deprez } 5510ca3913dSOlivier Deprez 5520ca3913dSOlivier Deprez leave: 5530ca3913dSOlivier Deprez channel_close(c); 5540ca3913dSOlivier Deprez return r; 5550ca3913dSOlivier Deprez } 5560ca3913dSOlivier Deprez 5570ca3913dSOlivier Deprez /******************************************************************************* 5580ca3913dSOlivier Deprez * This function calls the stat function of the driver associated to the parent 5590ca3913dSOlivier Deprez * directory of the file in path. 5600ca3913dSOlivier Deprez * The result is stored in dir. 5610ca3913dSOlivier Deprez ******************************************************************************/ 5620ca3913dSOlivier Deprez int stat(const char *path, dir_t *dir) 5630ca3913dSOlivier Deprez { 5640ca3913dSOlivier Deprez int r; 5650ca3913dSOlivier Deprez size_t len; 5660ca3913dSOlivier Deprez chan_t *channel; 5670ca3913dSOlivier Deprez char *p, dirname[PATHLEN]; 5680ca3913dSOlivier Deprez 5690ca3913dSOlivier Deprez if ((path == NULL) || (dir == NULL)) { 5700ca3913dSOlivier Deprez return -1; 5710ca3913dSOlivier Deprez } 5720ca3913dSOlivier Deprez 5730ca3913dSOlivier Deprez len = strlen(path); 5740ca3913dSOlivier Deprez if ((len + 1) > sizeof(dirname)) { 5750ca3913dSOlivier Deprez return -1; 5760ca3913dSOlivier Deprez } 5770ca3913dSOlivier Deprez 5780ca3913dSOlivier Deprez memcpy(dirname, path, len); 5790ca3913dSOlivier Deprez for (p = dirname + len; p > dirname; --p) { 5800ca3913dSOlivier Deprez if (*p != '/') { 5810ca3913dSOlivier Deprez break; 5820ca3913dSOlivier Deprez } 5830ca3913dSOlivier Deprez } 5840ca3913dSOlivier Deprez 5850ca3913dSOlivier Deprez p = memrchr(dirname, '/', p - dirname); 5860ca3913dSOlivier Deprez if (p == NULL) { 5870ca3913dSOlivier Deprez return -1; 5880ca3913dSOlivier Deprez } 5890ca3913dSOlivier Deprez 5900ca3913dSOlivier Deprez dirname[p - dirname + 1] = '\0'; 5910ca3913dSOlivier Deprez 5920ca3913dSOlivier Deprez channel = path_to_channel(dirname, O_STAT); 5930ca3913dSOlivier Deprez if (channel == NULL) { 5940ca3913dSOlivier Deprez return -1; 5950ca3913dSOlivier Deprez } 5960ca3913dSOlivier Deprez 5970ca3913dSOlivier Deprez r = devtab[channel->index]->stat(channel, path, dir); 5980ca3913dSOlivier Deprez channel_close(channel); 5990ca3913dSOlivier Deprez 6000ca3913dSOlivier Deprez return r; 6010ca3913dSOlivier Deprez } 6020ca3913dSOlivier Deprez 6030ca3913dSOlivier Deprez /******************************************************************************* 6040ca3913dSOlivier Deprez * This function calls the read function of the driver associated to fd. 6050ca3913dSOlivier Deprez * It fills buf with at most n bytes. 6060ca3913dSOlivier Deprez * It returns the number of bytes that were actually read. 6070ca3913dSOlivier Deprez ******************************************************************************/ 6080ca3913dSOlivier Deprez int read(int fd, void *buf, int n) 6090ca3913dSOlivier Deprez { 6100ca3913dSOlivier Deprez chan_t *channel; 6110ca3913dSOlivier Deprez 6120ca3913dSOlivier Deprez if (buf == NULL) { 6130ca3913dSOlivier Deprez return -1; 6140ca3913dSOlivier Deprez } 6150ca3913dSOlivier Deprez 6160ca3913dSOlivier Deprez channel = fd_to_channel(fd); 6170ca3913dSOlivier Deprez if (channel == NULL) { 6180ca3913dSOlivier Deprez return -1; 6190ca3913dSOlivier Deprez } 6200ca3913dSOlivier Deprez 6210ca3913dSOlivier Deprez if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) { 6220ca3913dSOlivier Deprez return -1; 6230ca3913dSOlivier Deprez } 6240ca3913dSOlivier Deprez 6250ca3913dSOlivier Deprez return devtab[channel->index]->read(channel, buf, n); 6260ca3913dSOlivier Deprez } 6270ca3913dSOlivier Deprez 6280ca3913dSOlivier Deprez /******************************************************************************* 6290ca3913dSOlivier Deprez * This function calls the write function of the driver associated to fd. 6300ca3913dSOlivier Deprez * It writes at most n bytes of buf. 6310ca3913dSOlivier Deprez * It returns the number of bytes that were actually written. 6320ca3913dSOlivier Deprez ******************************************************************************/ 6330ca3913dSOlivier Deprez int write(int fd, void *buf, int n) 6340ca3913dSOlivier Deprez { 6350ca3913dSOlivier Deprez chan_t *channel; 6360ca3913dSOlivier Deprez 6370ca3913dSOlivier Deprez if (buf == NULL) { 6380ca3913dSOlivier Deprez return -1; 6390ca3913dSOlivier Deprez } 6400ca3913dSOlivier Deprez 6410ca3913dSOlivier Deprez channel = fd_to_channel(fd); 6420ca3913dSOlivier Deprez if (channel == NULL) { 6430ca3913dSOlivier Deprez return -1; 6440ca3913dSOlivier Deprez } 6450ca3913dSOlivier Deprez 6460ca3913dSOlivier Deprez if ((channel->qid & CHDIR) != 0) { 6470ca3913dSOlivier Deprez return -1; 6480ca3913dSOlivier Deprez } 6490ca3913dSOlivier Deprez 6500ca3913dSOlivier Deprez return devtab[channel->index]->write(channel, buf, n); 6510ca3913dSOlivier Deprez } 6520ca3913dSOlivier Deprez 6530ca3913dSOlivier Deprez /******************************************************************************* 6540ca3913dSOlivier Deprez * This function calls the seek function of the driver associated to fd. 6550ca3913dSOlivier Deprez * It applies the offset off according to the strategy whence. 6560ca3913dSOlivier Deprez ******************************************************************************/ 6570ca3913dSOlivier Deprez int seek(int fd, long off, int whence) 6580ca3913dSOlivier Deprez { 6590ca3913dSOlivier Deprez chan_t *channel; 6600ca3913dSOlivier Deprez 6610ca3913dSOlivier Deprez channel = fd_to_channel(fd); 6620ca3913dSOlivier Deprez if (channel == NULL) { 6630ca3913dSOlivier Deprez return -1; 6640ca3913dSOlivier Deprez } 6650ca3913dSOlivier Deprez 6660ca3913dSOlivier Deprez if ((channel->qid & CHDIR) != 0) { 6670ca3913dSOlivier Deprez return -1; 6680ca3913dSOlivier Deprez } 6690ca3913dSOlivier Deprez 6700ca3913dSOlivier Deprez return devtab[channel->index]->seek(channel, off, whence); 6710ca3913dSOlivier Deprez } 6720ca3913dSOlivier Deprez 6730ca3913dSOlivier Deprez /******************************************************************************* 6740ca3913dSOlivier Deprez * This function is the default error implementation of the driver mount 6750ca3913dSOlivier Deprez * function. 6760ca3913dSOlivier Deprez ******************************************************************************/ 6770ca3913dSOlivier Deprez chan_t *deverrmount(chan_t *channel, const char *spec) 6780ca3913dSOlivier Deprez { 6790ca3913dSOlivier Deprez return NULL; 6800ca3913dSOlivier Deprez } 6810ca3913dSOlivier Deprez 6820ca3913dSOlivier Deprez /******************************************************************************* 6830ca3913dSOlivier Deprez * This function is the default error implementation of the driver write 6840ca3913dSOlivier Deprez * function. 6850ca3913dSOlivier Deprez ******************************************************************************/ 6860ca3913dSOlivier Deprez int deverrwrite(chan_t *channel, void *buf, int n) 6870ca3913dSOlivier Deprez { 6880ca3913dSOlivier Deprez return -1; 6890ca3913dSOlivier Deprez } 6900ca3913dSOlivier Deprez 6910ca3913dSOlivier Deprez /******************************************************************************* 6920ca3913dSOlivier Deprez * This function is the default error implementation of the driver seek 6930ca3913dSOlivier Deprez * function. 6940ca3913dSOlivier Deprez ******************************************************************************/ 6950ca3913dSOlivier Deprez int deverrseek(chan_t *channel, long off, int whence) 6960ca3913dSOlivier Deprez { 6970ca3913dSOlivier Deprez return -1; 6980ca3913dSOlivier Deprez } 6990ca3913dSOlivier Deprez 7000ca3913dSOlivier Deprez /******************************************************************************* 7010ca3913dSOlivier Deprez * This function is the default implementation of the driver seek function. 7020ca3913dSOlivier Deprez * It applies the offset off according to the strategy whence to the channel c. 7030ca3913dSOlivier Deprez ******************************************************************************/ 7040ca3913dSOlivier Deprez int devseek(chan_t *channel, long off, int whence) 7050ca3913dSOlivier Deprez { 7060ca3913dSOlivier Deprez switch (whence) { 7070ca3913dSOlivier Deprez case KSEEK_SET: 7080ca3913dSOlivier Deprez channel->offset = off; 7090ca3913dSOlivier Deprez break; 7100ca3913dSOlivier Deprez case KSEEK_CUR: 7110ca3913dSOlivier Deprez channel->offset += off; 7120ca3913dSOlivier Deprez break; 7130ca3913dSOlivier Deprez case KSEEK_END: 7140ca3913dSOlivier Deprez /* Not implemented */ 7150ca3913dSOlivier Deprez return -1; 7160ca3913dSOlivier Deprez } 7170ca3913dSOlivier Deprez 7180ca3913dSOlivier Deprez return 0; 7190ca3913dSOlivier Deprez } 7200ca3913dSOlivier Deprez 7210ca3913dSOlivier Deprez /******************************************************************************* 7220ca3913dSOlivier Deprez * This function registers the channel associated to the path new as a mount 7230ca3913dSOlivier Deprez * point for the channel c. 7240ca3913dSOlivier Deprez ******************************************************************************/ 7250ca3913dSOlivier Deprez static int add_mount_point(chan_t *channel, const char *new) 7260ca3913dSOlivier Deprez { 7270ca3913dSOlivier Deprez int i; 7280ca3913dSOlivier Deprez chan_t *cn; 7290ca3913dSOlivier Deprez struct mount_point *mp; 7300ca3913dSOlivier Deprez 7310ca3913dSOlivier Deprez if (new == NULL) { 7320ca3913dSOlivier Deprez goto err0; 7330ca3913dSOlivier Deprez } 7340ca3913dSOlivier Deprez 7350ca3913dSOlivier Deprez cn = path_to_channel(new, O_READ); 7360ca3913dSOlivier Deprez if (cn == NULL) { 7370ca3913dSOlivier Deprez goto err0; 7380ca3913dSOlivier Deprez } 7390ca3913dSOlivier Deprez 7400ca3913dSOlivier Deprez if ((cn->qid & CHDIR) == 0) { 7410ca3913dSOlivier Deprez goto err1; 7420ca3913dSOlivier Deprez } 7430ca3913dSOlivier Deprez 7440ca3913dSOlivier Deprez for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) { 7450ca3913dSOlivier Deprez mp = &mount_points[i]; 7460ca3913dSOlivier Deprez if (mp->new == NULL) { 7470ca3913dSOlivier Deprez break; 7480ca3913dSOlivier Deprez } 7490ca3913dSOlivier Deprez } 7500ca3913dSOlivier Deprez 7510ca3913dSOlivier Deprez if (i < 0) { 7520ca3913dSOlivier Deprez goto err1; 7530ca3913dSOlivier Deprez } 7540ca3913dSOlivier Deprez 7550ca3913dSOlivier Deprez mp->new = cn; 7560ca3913dSOlivier Deprez mp->old = channel; 7570ca3913dSOlivier Deprez 7580ca3913dSOlivier Deprez return 0; 7590ca3913dSOlivier Deprez 7600ca3913dSOlivier Deprez err1: 7610ca3913dSOlivier Deprez channel_close(cn); 7620ca3913dSOlivier Deprez err0: 7630ca3913dSOlivier Deprez return -1; 7640ca3913dSOlivier Deprez } 7650ca3913dSOlivier Deprez 7660ca3913dSOlivier Deprez /******************************************************************************* 7670ca3913dSOlivier Deprez * This function registers the path new as a mount point for the path old. 7680ca3913dSOlivier Deprez ******************************************************************************/ 7690ca3913dSOlivier Deprez int bind(const char *old, const char *new) 7700ca3913dSOlivier Deprez { 7710ca3913dSOlivier Deprez chan_t *channel; 7720ca3913dSOlivier Deprez 7730ca3913dSOlivier Deprez channel = path_to_channel(old, O_BIND); 7740ca3913dSOlivier Deprez if (channel == NULL) { 7750ca3913dSOlivier Deprez return -1; 7760ca3913dSOlivier Deprez } 7770ca3913dSOlivier Deprez 7780ca3913dSOlivier Deprez if (add_mount_point(channel, new) < 0) { 7790ca3913dSOlivier Deprez channel_close(channel); 7800ca3913dSOlivier Deprez return -1; 7810ca3913dSOlivier Deprez } 7820ca3913dSOlivier Deprez 7830ca3913dSOlivier Deprez return 0; 7840ca3913dSOlivier Deprez } 7850ca3913dSOlivier Deprez 7860ca3913dSOlivier Deprez /******************************************************************************* 7870ca3913dSOlivier Deprez * This function calls the mount function of the driver associated to the path 7880ca3913dSOlivier Deprez * srv. 7890ca3913dSOlivier Deprez * It mounts the path srv on the path where. 7900ca3913dSOlivier Deprez ******************************************************************************/ 7910ca3913dSOlivier Deprez int mount(const char *srv, const char *where, const char *spec) 7920ca3913dSOlivier Deprez { 7930ca3913dSOlivier Deprez chan_t *channel, *mount_point_chan; 7940ca3913dSOlivier Deprez int ret; 7950ca3913dSOlivier Deprez 7960ca3913dSOlivier Deprez channel = path_to_channel(srv, O_RDWR); 7970ca3913dSOlivier Deprez if (channel == NULL) { 7980ca3913dSOlivier Deprez goto err0; 7990ca3913dSOlivier Deprez } 8000ca3913dSOlivier Deprez 8010ca3913dSOlivier Deprez mount_point_chan = devtab[channel->index]->mount(channel, spec); 8020ca3913dSOlivier Deprez if (mount_point_chan == NULL) { 8030ca3913dSOlivier Deprez goto err1; 8040ca3913dSOlivier Deprez } 8050ca3913dSOlivier Deprez 8060ca3913dSOlivier Deprez ret = add_mount_point(mount_point_chan, where); 8070ca3913dSOlivier Deprez if (ret < 0) { 8080ca3913dSOlivier Deprez goto err2; 8090ca3913dSOlivier Deprez } 8100ca3913dSOlivier Deprez 8110ca3913dSOlivier Deprez channel_close(channel); 8120ca3913dSOlivier Deprez 8130ca3913dSOlivier Deprez return 0; 8140ca3913dSOlivier Deprez 8150ca3913dSOlivier Deprez err2: 8160ca3913dSOlivier Deprez channel_close(mount_point_chan); 8170ca3913dSOlivier Deprez err1: 8180ca3913dSOlivier Deprez channel_close(channel); 8190ca3913dSOlivier Deprez err0: 8200ca3913dSOlivier Deprez return -1; 8210ca3913dSOlivier Deprez } 8220ca3913dSOlivier Deprez 8230ca3913dSOlivier Deprez /******************************************************************************* 8240ca3913dSOlivier Deprez * This function initializes the device environment. 8250ca3913dSOlivier Deprez * It creates the '/' channel. 8260ca3913dSOlivier Deprez * It links the device drivers to the physical drivers. 8270ca3913dSOlivier Deprez ******************************************************************************/ 8280ca3913dSOlivier Deprez void debugfs_init(void) 8290ca3913dSOlivier Deprez { 8300ca3913dSOlivier Deprez chan_t *channel, *cloned_channel; 8310ca3913dSOlivier Deprez 8320ca3913dSOlivier Deprez for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) { 8330ca3913dSOlivier Deprez channel_clear(channel); 8340ca3913dSOlivier Deprez } 8350ca3913dSOlivier Deprez 8360ca3913dSOlivier Deprez channel = devattach('/', 0); 8370ca3913dSOlivier Deprez if (channel == NULL) { 8380ca3913dSOlivier Deprez panic(); 8390ca3913dSOlivier Deprez } 8400ca3913dSOlivier Deprez 8410ca3913dSOlivier Deprez cloned_channel = clone(channel, &slash_channel); 8420ca3913dSOlivier Deprez if (cloned_channel == NULL) { 8430ca3913dSOlivier Deprez panic(); 8440ca3913dSOlivier Deprez } 8450ca3913dSOlivier Deprez 8460ca3913dSOlivier Deprez channel_close(channel); 8470ca3913dSOlivier Deprez devlink(); 8480ca3913dSOlivier Deprez } 8490ca3913dSOlivier Deprez 8500ca3913dSOlivier Deprez __dead2 void devpanic(const char *cause) 8510ca3913dSOlivier Deprez { 8520ca3913dSOlivier Deprez panic(); 8530ca3913dSOlivier Deprez } 854