1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <cdefs.h>
8*54fd6939SJiyong Park #include <common/debug.h>
9*54fd6939SJiyong Park #include <lib/debugfs.h>
10*54fd6939SJiyong Park #include <string.h>
11*54fd6939SJiyong Park
12*54fd6939SJiyong Park #include "dev.h"
13*54fd6939SJiyong Park
14*54fd6939SJiyong Park #define NR_MOUNT_POINTS 4
15*54fd6939SJiyong Park
16*54fd6939SJiyong Park struct mount_point {
17*54fd6939SJiyong Park chan_t *new;
18*54fd6939SJiyong Park chan_t *old;
19*54fd6939SJiyong Park };
20*54fd6939SJiyong Park
21*54fd6939SJiyong Park /* This array contains all the available channels of the filesystem.
22*54fd6939SJiyong Park * A file descriptor is the index of a specific channel in this array.
23*54fd6939SJiyong Park */
24*54fd6939SJiyong Park static chan_t fdset[NR_CHANS];
25*54fd6939SJiyong Park
26*54fd6939SJiyong Park /* This array contains all the available mount points of the filesystem. */
27*54fd6939SJiyong Park static struct mount_point mount_points[NR_MOUNT_POINTS];
28*54fd6939SJiyong Park
29*54fd6939SJiyong Park /* This variable stores the channel associated to the root directory. */
30*54fd6939SJiyong Park static chan_t slash_channel;
31*54fd6939SJiyong Park
32*54fd6939SJiyong Park /* This function creates a channel from a device index and registers
33*54fd6939SJiyong Park * it to fdset.
34*54fd6939SJiyong Park */
create_new_channel(unsigned char index)35*54fd6939SJiyong Park static chan_t *create_new_channel(unsigned char index)
36*54fd6939SJiyong Park {
37*54fd6939SJiyong Park chan_t *channel = NULL;
38*54fd6939SJiyong Park int i;
39*54fd6939SJiyong Park
40*54fd6939SJiyong Park for (i = 0; i < NR_CHANS; i++) {
41*54fd6939SJiyong Park if (fdset[i].index == NODEV) {
42*54fd6939SJiyong Park channel = &fdset[i];
43*54fd6939SJiyong Park channel->index = index;
44*54fd6939SJiyong Park break;
45*54fd6939SJiyong Park }
46*54fd6939SJiyong Park }
47*54fd6939SJiyong Park
48*54fd6939SJiyong Park return channel;
49*54fd6939SJiyong Park }
50*54fd6939SJiyong Park
51*54fd6939SJiyong Park /*******************************************************************************
52*54fd6939SJiyong Park * This function returns a pointer to an existing channel in fdset from a file
53*54fd6939SJiyong Park * descriptor.
54*54fd6939SJiyong Park ******************************************************************************/
fd_to_channel(int fd)55*54fd6939SJiyong Park static chan_t *fd_to_channel(int fd)
56*54fd6939SJiyong Park {
57*54fd6939SJiyong Park if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) {
58*54fd6939SJiyong Park return NULL;
59*54fd6939SJiyong Park }
60*54fd6939SJiyong Park
61*54fd6939SJiyong Park return &fdset[fd];
62*54fd6939SJiyong Park }
63*54fd6939SJiyong Park
64*54fd6939SJiyong Park /*******************************************************************************
65*54fd6939SJiyong Park * This function returns a file descriptor from a channel.
66*54fd6939SJiyong Park * The caller must be sure that the channel is registered in fdset.
67*54fd6939SJiyong Park ******************************************************************************/
channel_to_fd(chan_t * channel)68*54fd6939SJiyong Park static int channel_to_fd(chan_t *channel)
69*54fd6939SJiyong Park {
70*54fd6939SJiyong Park return (channel == NULL) ? -1 : (channel - fdset);
71*54fd6939SJiyong Park }
72*54fd6939SJiyong Park
73*54fd6939SJiyong Park /*******************************************************************************
74*54fd6939SJiyong Park * This function checks the validity of a mode.
75*54fd6939SJiyong Park ******************************************************************************/
is_valid_mode(int mode)76*54fd6939SJiyong Park static bool is_valid_mode(int mode)
77*54fd6939SJiyong Park {
78*54fd6939SJiyong Park if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) {
79*54fd6939SJiyong Park return false;
80*54fd6939SJiyong Park }
81*54fd6939SJiyong Park if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) {
82*54fd6939SJiyong Park return false;
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) {
85*54fd6939SJiyong Park return false;
86*54fd6939SJiyong Park }
87*54fd6939SJiyong Park
88*54fd6939SJiyong Park return true;
89*54fd6939SJiyong Park }
90*54fd6939SJiyong Park
91*54fd6939SJiyong Park /*******************************************************************************
92*54fd6939SJiyong Park * This function extracts the next part of the given path contained and puts it
93*54fd6939SJiyong Park * in token. It returns a pointer to the remainder of the path.
94*54fd6939SJiyong Park ******************************************************************************/
next(const char * path,char * token)95*54fd6939SJiyong Park static const char *next(const char *path, char *token)
96*54fd6939SJiyong Park {
97*54fd6939SJiyong Park int index;
98*54fd6939SJiyong Park const char *cursor;
99*54fd6939SJiyong Park
100*54fd6939SJiyong Park while (*path == '/') {
101*54fd6939SJiyong Park ++path;
102*54fd6939SJiyong Park }
103*54fd6939SJiyong Park
104*54fd6939SJiyong Park index = 0;
105*54fd6939SJiyong Park cursor = path;
106*54fd6939SJiyong Park if (*path != '\0') {
107*54fd6939SJiyong Park while (*cursor != '/' && *cursor != '\0') {
108*54fd6939SJiyong Park if (index == NAMELEN) {
109*54fd6939SJiyong Park return NULL;
110*54fd6939SJiyong Park }
111*54fd6939SJiyong Park token[index++] = *cursor++;
112*54fd6939SJiyong Park }
113*54fd6939SJiyong Park }
114*54fd6939SJiyong Park token[index] = '\0';
115*54fd6939SJiyong Park
116*54fd6939SJiyong Park return cursor;
117*54fd6939SJiyong Park }
118*54fd6939SJiyong Park
119*54fd6939SJiyong Park /*******************************************************************************
120*54fd6939SJiyong Park * This function returns the driver index in devtab of the driver
121*54fd6939SJiyong Park * identified by id.
122*54fd6939SJiyong Park ******************************************************************************/
get_device_index(int id)123*54fd6939SJiyong Park static int get_device_index(int id)
124*54fd6939SJiyong Park {
125*54fd6939SJiyong Park int index;
126*54fd6939SJiyong Park dev_t * const *dp;
127*54fd6939SJiyong Park
128*54fd6939SJiyong Park for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) {
129*54fd6939SJiyong Park index++;
130*54fd6939SJiyong Park }
131*54fd6939SJiyong Park
132*54fd6939SJiyong Park if (*dp == NULL) {
133*54fd6939SJiyong Park return -1;
134*54fd6939SJiyong Park }
135*54fd6939SJiyong Park
136*54fd6939SJiyong Park return index;
137*54fd6939SJiyong Park }
138*54fd6939SJiyong Park
139*54fd6939SJiyong Park /*******************************************************************************
140*54fd6939SJiyong Park * This function clears a given channel fields
141*54fd6939SJiyong Park ******************************************************************************/
channel_clear(chan_t * channel)142*54fd6939SJiyong Park static void channel_clear(chan_t *channel)
143*54fd6939SJiyong Park {
144*54fd6939SJiyong Park channel->offset = 0;
145*54fd6939SJiyong Park channel->qid = 0;
146*54fd6939SJiyong Park channel->index = NODEV;
147*54fd6939SJiyong Park channel->dev = 0;
148*54fd6939SJiyong Park channel->mode = 0;
149*54fd6939SJiyong Park }
150*54fd6939SJiyong Park
151*54fd6939SJiyong Park /*******************************************************************************
152*54fd6939SJiyong Park * This function closes the channel pointed to by c.
153*54fd6939SJiyong Park ******************************************************************************/
channel_close(chan_t * channel)154*54fd6939SJiyong Park void channel_close(chan_t *channel)
155*54fd6939SJiyong Park {
156*54fd6939SJiyong Park if (channel != NULL) {
157*54fd6939SJiyong Park channel_clear(channel);
158*54fd6939SJiyong Park }
159*54fd6939SJiyong Park }
160*54fd6939SJiyong Park
161*54fd6939SJiyong Park /*******************************************************************************
162*54fd6939SJiyong Park * This function copies data from src to dst after applying the offset of the
163*54fd6939SJiyong Park * channel c. nbytes bytes are expected to be copied unless the data goes over
164*54fd6939SJiyong Park * dst + len.
165*54fd6939SJiyong Park * It returns the actual number of bytes that were copied.
166*54fd6939SJiyong Park ******************************************************************************/
buf_to_channel(chan_t * channel,void * dst,void * src,int nbytes,long len)167*54fd6939SJiyong Park int buf_to_channel(chan_t *channel, void *dst, void *src, int nbytes, long len)
168*54fd6939SJiyong Park {
169*54fd6939SJiyong Park const char *addr = src;
170*54fd6939SJiyong Park
171*54fd6939SJiyong Park if ((channel == NULL) || (dst == NULL) || (src == NULL)) {
172*54fd6939SJiyong Park return 0;
173*54fd6939SJiyong Park }
174*54fd6939SJiyong Park
175*54fd6939SJiyong Park if (channel->offset >= len) {
176*54fd6939SJiyong Park return 0;
177*54fd6939SJiyong Park }
178*54fd6939SJiyong Park
179*54fd6939SJiyong Park if ((channel->offset + nbytes) > len) {
180*54fd6939SJiyong Park nbytes = len - channel->offset;
181*54fd6939SJiyong Park }
182*54fd6939SJiyong Park
183*54fd6939SJiyong Park memcpy(dst, addr + channel->offset, nbytes);
184*54fd6939SJiyong Park
185*54fd6939SJiyong Park channel->offset += nbytes;
186*54fd6939SJiyong Park
187*54fd6939SJiyong Park return nbytes;
188*54fd6939SJiyong Park }
189*54fd6939SJiyong Park
190*54fd6939SJiyong Park /*******************************************************************************
191*54fd6939SJiyong Park * This function checks whether a channel (identified by its device index and
192*54fd6939SJiyong Park * qid) is registered as a mount point.
193*54fd6939SJiyong Park * Returns a pointer to the channel it is mounted to when found, NULL otherwise.
194*54fd6939SJiyong Park ******************************************************************************/
mount_point_to_channel(int index,qid_t qid)195*54fd6939SJiyong Park static chan_t *mount_point_to_channel(int index, qid_t qid)
196*54fd6939SJiyong Park {
197*54fd6939SJiyong Park chan_t *channel;
198*54fd6939SJiyong Park struct mount_point *mp;
199*54fd6939SJiyong Park
200*54fd6939SJiyong Park for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) {
201*54fd6939SJiyong Park channel = mp->new;
202*54fd6939SJiyong Park if (channel == NULL) {
203*54fd6939SJiyong Park continue;
204*54fd6939SJiyong Park }
205*54fd6939SJiyong Park
206*54fd6939SJiyong Park if ((channel->index == index) && (channel->qid == qid)) {
207*54fd6939SJiyong Park return mp->old;
208*54fd6939SJiyong Park }
209*54fd6939SJiyong Park }
210*54fd6939SJiyong Park
211*54fd6939SJiyong Park return NULL;
212*54fd6939SJiyong Park }
213*54fd6939SJiyong Park
214*54fd6939SJiyong Park /*******************************************************************************
215*54fd6939SJiyong Park * This function calls the attach function of the driver identified by id.
216*54fd6939SJiyong Park ******************************************************************************/
attach(int id,int dev)217*54fd6939SJiyong Park chan_t *attach(int id, int dev)
218*54fd6939SJiyong Park {
219*54fd6939SJiyong Park /* Get the devtab index for the driver identified by id */
220*54fd6939SJiyong Park int index = get_device_index(id);
221*54fd6939SJiyong Park
222*54fd6939SJiyong Park if (index < 0) {
223*54fd6939SJiyong Park return NULL;
224*54fd6939SJiyong Park }
225*54fd6939SJiyong Park
226*54fd6939SJiyong Park return devtab[index]->attach(id, dev);
227*54fd6939SJiyong Park }
228*54fd6939SJiyong Park
229*54fd6939SJiyong Park /*******************************************************************************
230*54fd6939SJiyong Park * This function is the default implementation of the driver attach function.
231*54fd6939SJiyong Park * It creates a new channel and returns a pointer to it.
232*54fd6939SJiyong Park ******************************************************************************/
devattach(int id,int dev)233*54fd6939SJiyong Park chan_t *devattach(int id, int dev)
234*54fd6939SJiyong Park {
235*54fd6939SJiyong Park chan_t *channel;
236*54fd6939SJiyong Park int index;
237*54fd6939SJiyong Park
238*54fd6939SJiyong Park index = get_device_index(id);
239*54fd6939SJiyong Park if (index < 0) {
240*54fd6939SJiyong Park return NULL;
241*54fd6939SJiyong Park }
242*54fd6939SJiyong Park
243*54fd6939SJiyong Park channel = create_new_channel(index);
244*54fd6939SJiyong Park if (channel == NULL) {
245*54fd6939SJiyong Park return NULL;
246*54fd6939SJiyong Park }
247*54fd6939SJiyong Park
248*54fd6939SJiyong Park channel->dev = dev;
249*54fd6939SJiyong Park channel->qid = CHDIR;
250*54fd6939SJiyong Park
251*54fd6939SJiyong Park return channel;
252*54fd6939SJiyong Park }
253*54fd6939SJiyong Park
254*54fd6939SJiyong Park /*******************************************************************************
255*54fd6939SJiyong Park * This function returns a channel given a path.
256*54fd6939SJiyong Park * It goes through the filesystem, from the root namespace ('/') or from a
257*54fd6939SJiyong Park * device namespace ('#'), switching channel on mount points.
258*54fd6939SJiyong Park ******************************************************************************/
path_to_channel(const char * path,int mode)259*54fd6939SJiyong Park chan_t *path_to_channel(const char *path, int mode)
260*54fd6939SJiyong Park {
261*54fd6939SJiyong Park int i, n;
262*54fd6939SJiyong Park const char *path_next;
263*54fd6939SJiyong Park chan_t *mnt, *channel;
264*54fd6939SJiyong Park char elem[NAMELEN];
265*54fd6939SJiyong Park
266*54fd6939SJiyong Park if (path == NULL) {
267*54fd6939SJiyong Park return NULL;
268*54fd6939SJiyong Park }
269*54fd6939SJiyong Park
270*54fd6939SJiyong Park switch (path[0]) {
271*54fd6939SJiyong Park case '/':
272*54fd6939SJiyong Park channel = clone(&slash_channel, NULL);
273*54fd6939SJiyong Park path_next = path;
274*54fd6939SJiyong Park break;
275*54fd6939SJiyong Park case '#':
276*54fd6939SJiyong Park path_next = next(path + 1, elem);
277*54fd6939SJiyong Park if (path_next == NULL) {
278*54fd6939SJiyong Park goto noent;
279*54fd6939SJiyong Park }
280*54fd6939SJiyong Park
281*54fd6939SJiyong Park n = 0;
282*54fd6939SJiyong Park for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) {
283*54fd6939SJiyong Park n += elem[i] - '0';
284*54fd6939SJiyong Park }
285*54fd6939SJiyong Park
286*54fd6939SJiyong Park if (elem[i] != '\0') {
287*54fd6939SJiyong Park goto noent;
288*54fd6939SJiyong Park }
289*54fd6939SJiyong Park
290*54fd6939SJiyong Park channel = attach(elem[0], n);
291*54fd6939SJiyong Park break;
292*54fd6939SJiyong Park default:
293*54fd6939SJiyong Park return NULL;
294*54fd6939SJiyong Park }
295*54fd6939SJiyong Park
296*54fd6939SJiyong Park if (channel == NULL) {
297*54fd6939SJiyong Park return NULL;
298*54fd6939SJiyong Park }
299*54fd6939SJiyong Park
300*54fd6939SJiyong Park for (path_next = next(path_next, elem); *elem;
301*54fd6939SJiyong Park path_next = next(path_next, elem)) {
302*54fd6939SJiyong Park if ((channel->qid & CHDIR) == 0) {
303*54fd6939SJiyong Park goto notfound;
304*54fd6939SJiyong Park }
305*54fd6939SJiyong Park
306*54fd6939SJiyong Park if (devtab[channel->index]->walk(channel, elem) < 0) {
307*54fd6939SJiyong Park channel_close(channel);
308*54fd6939SJiyong Park goto notfound;
309*54fd6939SJiyong Park }
310*54fd6939SJiyong Park
311*54fd6939SJiyong Park mnt = mount_point_to_channel(channel->index, channel->qid);
312*54fd6939SJiyong Park if (mnt != NULL) {
313*54fd6939SJiyong Park clone(mnt, channel);
314*54fd6939SJiyong Park }
315*54fd6939SJiyong Park }
316*54fd6939SJiyong Park
317*54fd6939SJiyong Park if (path_next == NULL) {
318*54fd6939SJiyong Park goto notfound;
319*54fd6939SJiyong Park }
320*54fd6939SJiyong Park
321*54fd6939SJiyong Park /* TODO: check mode */
322*54fd6939SJiyong Park return channel;
323*54fd6939SJiyong Park
324*54fd6939SJiyong Park notfound:
325*54fd6939SJiyong Park channel_close(channel);
326*54fd6939SJiyong Park noent:
327*54fd6939SJiyong Park return NULL;
328*54fd6939SJiyong Park }
329*54fd6939SJiyong Park
330*54fd6939SJiyong Park /*******************************************************************************
331*54fd6939SJiyong Park * This function calls the clone function of the driver associated to the
332*54fd6939SJiyong Park * channel c.
333*54fd6939SJiyong Park ******************************************************************************/
clone(chan_t * c,chan_t * nc)334*54fd6939SJiyong Park chan_t *clone(chan_t *c, chan_t *nc)
335*54fd6939SJiyong Park {
336*54fd6939SJiyong Park if (c->index == NODEV) {
337*54fd6939SJiyong Park return NULL;
338*54fd6939SJiyong Park }
339*54fd6939SJiyong Park
340*54fd6939SJiyong Park return devtab[c->index]->clone(c, nc);
341*54fd6939SJiyong Park }
342*54fd6939SJiyong Park
343*54fd6939SJiyong Park /*******************************************************************************
344*54fd6939SJiyong Park * This function is the default implementation of the driver clone function.
345*54fd6939SJiyong Park * It creates a new channel and returns a pointer to it.
346*54fd6939SJiyong Park * It clones channel into new_channel.
347*54fd6939SJiyong Park ******************************************************************************/
devclone(chan_t * channel,chan_t * new_channel)348*54fd6939SJiyong Park chan_t *devclone(chan_t *channel, chan_t *new_channel)
349*54fd6939SJiyong Park {
350*54fd6939SJiyong Park if (channel == NULL) {
351*54fd6939SJiyong Park return NULL;
352*54fd6939SJiyong Park }
353*54fd6939SJiyong Park
354*54fd6939SJiyong Park if (new_channel == NULL) {
355*54fd6939SJiyong Park new_channel = create_new_channel(channel->index);
356*54fd6939SJiyong Park if (new_channel == NULL) {
357*54fd6939SJiyong Park return NULL;
358*54fd6939SJiyong Park }
359*54fd6939SJiyong Park }
360*54fd6939SJiyong Park
361*54fd6939SJiyong Park new_channel->qid = channel->qid;
362*54fd6939SJiyong Park new_channel->dev = channel->dev;
363*54fd6939SJiyong Park new_channel->mode = channel->mode;
364*54fd6939SJiyong Park new_channel->offset = channel->offset;
365*54fd6939SJiyong Park new_channel->index = channel->index;
366*54fd6939SJiyong Park
367*54fd6939SJiyong Park return new_channel;
368*54fd6939SJiyong Park }
369*54fd6939SJiyong Park
370*54fd6939SJiyong Park /*******************************************************************************
371*54fd6939SJiyong Park * This function is the default implementation of the driver walk function.
372*54fd6939SJiyong Park * It goes through all the elements of tab using the gen function until a match
373*54fd6939SJiyong Park * is found with name.
374*54fd6939SJiyong Park * If a match is found, it copies the qid of the new directory.
375*54fd6939SJiyong Park ******************************************************************************/
devwalk(chan_t * channel,const char * name,const dirtab_t * tab,int ntab,devgen_t * gen)376*54fd6939SJiyong Park int devwalk(chan_t *channel, const char *name, const dirtab_t *tab,
377*54fd6939SJiyong Park int ntab, devgen_t *gen)
378*54fd6939SJiyong Park {
379*54fd6939SJiyong Park int i;
380*54fd6939SJiyong Park dir_t dir;
381*54fd6939SJiyong Park
382*54fd6939SJiyong Park if ((channel == NULL) || (name == NULL) || (gen == NULL)) {
383*54fd6939SJiyong Park return -1;
384*54fd6939SJiyong Park }
385*54fd6939SJiyong Park
386*54fd6939SJiyong Park if ((name[0] == '.') && (name[1] == '\0')) {
387*54fd6939SJiyong Park return 1;
388*54fd6939SJiyong Park }
389*54fd6939SJiyong Park
390*54fd6939SJiyong Park for (i = 0; ; i++) {
391*54fd6939SJiyong Park switch ((*gen)(channel, tab, ntab, i, &dir)) {
392*54fd6939SJiyong Park case 0:
393*54fd6939SJiyong Park /* Intentional fall-through */
394*54fd6939SJiyong Park case -1:
395*54fd6939SJiyong Park return -1;
396*54fd6939SJiyong Park case 1:
397*54fd6939SJiyong Park if (strncmp(name, dir.name, NAMELEN) != 0) {
398*54fd6939SJiyong Park continue;
399*54fd6939SJiyong Park }
400*54fd6939SJiyong Park channel->qid = dir.qid;
401*54fd6939SJiyong Park return 1;
402*54fd6939SJiyong Park }
403*54fd6939SJiyong Park }
404*54fd6939SJiyong Park }
405*54fd6939SJiyong Park
406*54fd6939SJiyong Park /*******************************************************************************
407*54fd6939SJiyong Park * This is a helper function which exposes the content of a directory, element
408*54fd6939SJiyong Park * by element. It is meant to be called until the end of the directory is
409*54fd6939SJiyong Park * reached or an error occurs.
410*54fd6939SJiyong Park * It returns -1 on error, 0 on end of directory and 1 when a new file is found.
411*54fd6939SJiyong Park ******************************************************************************/
dirread(chan_t * channel,dir_t * dir,const dirtab_t * tab,int ntab,devgen_t * gen)412*54fd6939SJiyong Park int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab,
413*54fd6939SJiyong Park int ntab, devgen_t *gen)
414*54fd6939SJiyong Park {
415*54fd6939SJiyong Park int i, ret;
416*54fd6939SJiyong Park
417*54fd6939SJiyong Park if ((channel == NULL) || (dir == NULL) || (gen == NULL)) {
418*54fd6939SJiyong Park return -1;
419*54fd6939SJiyong Park }
420*54fd6939SJiyong Park
421*54fd6939SJiyong Park i = channel->offset/sizeof(dir_t);
422*54fd6939SJiyong Park ret = (*gen)(channel, tab, ntab, i, dir);
423*54fd6939SJiyong Park if (ret == 1) {
424*54fd6939SJiyong Park channel->offset += sizeof(dir_t);
425*54fd6939SJiyong Park }
426*54fd6939SJiyong Park
427*54fd6939SJiyong Park return ret;
428*54fd6939SJiyong Park }
429*54fd6939SJiyong Park
430*54fd6939SJiyong Park /*******************************************************************************
431*54fd6939SJiyong Park * This function sets the elements of dir.
432*54fd6939SJiyong Park ******************************************************************************/
make_dir_entry(chan_t * channel,dir_t * dir,const char * name,long length,qid_t qid,unsigned int mode)433*54fd6939SJiyong Park void make_dir_entry(chan_t *channel, dir_t *dir,
434*54fd6939SJiyong Park const char *name, long length, qid_t qid, unsigned int mode)
435*54fd6939SJiyong Park {
436*54fd6939SJiyong Park if ((channel == NULL) || (dir == NULL) || (name == NULL)) {
437*54fd6939SJiyong Park return;
438*54fd6939SJiyong Park }
439*54fd6939SJiyong Park
440*54fd6939SJiyong Park strlcpy(dir->name, name, sizeof(dir->name));
441*54fd6939SJiyong Park dir->length = length;
442*54fd6939SJiyong Park dir->qid = qid;
443*54fd6939SJiyong Park dir->mode = mode;
444*54fd6939SJiyong Park
445*54fd6939SJiyong Park if ((qid & CHDIR) != 0) {
446*54fd6939SJiyong Park dir->mode |= O_DIR;
447*54fd6939SJiyong Park }
448*54fd6939SJiyong Park
449*54fd6939SJiyong Park dir->index = channel->index;
450*54fd6939SJiyong Park dir->dev = channel->dev;
451*54fd6939SJiyong Park }
452*54fd6939SJiyong Park
453*54fd6939SJiyong Park /*******************************************************************************
454*54fd6939SJiyong Park * This function is the default implementation of the internal driver gen
455*54fd6939SJiyong Park * function.
456*54fd6939SJiyong Park * It copies and formats the information of the nth element of tab into dir.
457*54fd6939SJiyong Park ******************************************************************************/
devgen(chan_t * channel,const dirtab_t * tab,int ntab,int n,dir_t * dir)458*54fd6939SJiyong Park int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir)
459*54fd6939SJiyong Park {
460*54fd6939SJiyong Park const dirtab_t *dp;
461*54fd6939SJiyong Park
462*54fd6939SJiyong Park if ((channel == NULL) || (dir == NULL) || (tab == NULL) ||
463*54fd6939SJiyong Park (n >= ntab)) {
464*54fd6939SJiyong Park return 0;
465*54fd6939SJiyong Park }
466*54fd6939SJiyong Park
467*54fd6939SJiyong Park dp = &tab[n];
468*54fd6939SJiyong Park make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm);
469*54fd6939SJiyong Park return 1;
470*54fd6939SJiyong Park }
471*54fd6939SJiyong Park
472*54fd6939SJiyong Park /*******************************************************************************
473*54fd6939SJiyong Park * This function returns a file descriptor identifying the channel associated to
474*54fd6939SJiyong Park * the given path.
475*54fd6939SJiyong Park ******************************************************************************/
open(const char * path,int mode)476*54fd6939SJiyong Park int open(const char *path, int mode)
477*54fd6939SJiyong Park {
478*54fd6939SJiyong Park chan_t *channel;
479*54fd6939SJiyong Park
480*54fd6939SJiyong Park if (path == NULL) {
481*54fd6939SJiyong Park return -1;
482*54fd6939SJiyong Park }
483*54fd6939SJiyong Park
484*54fd6939SJiyong Park if (is_valid_mode(mode) == false) {
485*54fd6939SJiyong Park return -1;
486*54fd6939SJiyong Park }
487*54fd6939SJiyong Park
488*54fd6939SJiyong Park channel = path_to_channel(path, mode);
489*54fd6939SJiyong Park
490*54fd6939SJiyong Park return channel_to_fd(channel);
491*54fd6939SJiyong Park }
492*54fd6939SJiyong Park
493*54fd6939SJiyong Park /*******************************************************************************
494*54fd6939SJiyong Park * This function closes the channel identified by the file descriptor fd.
495*54fd6939SJiyong Park ******************************************************************************/
close(int fd)496*54fd6939SJiyong Park int close(int fd)
497*54fd6939SJiyong Park {
498*54fd6939SJiyong Park chan_t *channel;
499*54fd6939SJiyong Park
500*54fd6939SJiyong Park channel = fd_to_channel(fd);
501*54fd6939SJiyong Park if (channel == NULL) {
502*54fd6939SJiyong Park return -1;
503*54fd6939SJiyong Park }
504*54fd6939SJiyong Park
505*54fd6939SJiyong Park channel_close(channel);
506*54fd6939SJiyong Park return 0;
507*54fd6939SJiyong Park }
508*54fd6939SJiyong Park
509*54fd6939SJiyong Park /*******************************************************************************
510*54fd6939SJiyong Park * This function is the default implementation of the driver stat function.
511*54fd6939SJiyong Park * It goes through all the elements of tab using the gen function until a match
512*54fd6939SJiyong Park * is found with file.
513*54fd6939SJiyong Park * If a match is found, dir contains the information file.
514*54fd6939SJiyong Park ******************************************************************************/
devstat(chan_t * dirc,const char * file,dir_t * dir,const dirtab_t * tab,int ntab,devgen_t * gen)515*54fd6939SJiyong Park int devstat(chan_t *dirc, const char *file, dir_t *dir,
516*54fd6939SJiyong Park const dirtab_t *tab, int ntab, devgen_t *gen)
517*54fd6939SJiyong Park {
518*54fd6939SJiyong Park int i, r = 0;
519*54fd6939SJiyong Park chan_t *c, *mnt;
520*54fd6939SJiyong Park
521*54fd6939SJiyong Park if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) {
522*54fd6939SJiyong Park return -1;
523*54fd6939SJiyong Park }
524*54fd6939SJiyong Park
525*54fd6939SJiyong Park c = path_to_channel(file, O_STAT);
526*54fd6939SJiyong Park if (c == NULL) {
527*54fd6939SJiyong Park return -1;
528*54fd6939SJiyong Park }
529*54fd6939SJiyong Park
530*54fd6939SJiyong Park for (i = 0; ; i++) {
531*54fd6939SJiyong Park switch ((*gen)(dirc, tab, ntab, i, dir)) {
532*54fd6939SJiyong Park case 0:
533*54fd6939SJiyong Park /* Intentional fall-through */
534*54fd6939SJiyong Park case -1:
535*54fd6939SJiyong Park r = -1;
536*54fd6939SJiyong Park goto leave;
537*54fd6939SJiyong Park case 1:
538*54fd6939SJiyong Park mnt = mount_point_to_channel(dir->index, dir->qid);
539*54fd6939SJiyong Park if (mnt != NULL) {
540*54fd6939SJiyong Park dir->qid = mnt->qid;
541*54fd6939SJiyong Park dir->index = mnt->index;
542*54fd6939SJiyong Park }
543*54fd6939SJiyong Park
544*54fd6939SJiyong Park if ((dir->qid != c->qid) || (dir->index != c->index)) {
545*54fd6939SJiyong Park continue;
546*54fd6939SJiyong Park }
547*54fd6939SJiyong Park
548*54fd6939SJiyong Park goto leave;
549*54fd6939SJiyong Park }
550*54fd6939SJiyong Park }
551*54fd6939SJiyong Park
552*54fd6939SJiyong Park leave:
553*54fd6939SJiyong Park channel_close(c);
554*54fd6939SJiyong Park return r;
555*54fd6939SJiyong Park }
556*54fd6939SJiyong Park
557*54fd6939SJiyong Park /*******************************************************************************
558*54fd6939SJiyong Park * This function calls the stat function of the driver associated to the parent
559*54fd6939SJiyong Park * directory of the file in path.
560*54fd6939SJiyong Park * The result is stored in dir.
561*54fd6939SJiyong Park ******************************************************************************/
stat(const char * path,dir_t * dir)562*54fd6939SJiyong Park int stat(const char *path, dir_t *dir)
563*54fd6939SJiyong Park {
564*54fd6939SJiyong Park int r;
565*54fd6939SJiyong Park size_t len;
566*54fd6939SJiyong Park chan_t *channel;
567*54fd6939SJiyong Park char *p, dirname[PATHLEN];
568*54fd6939SJiyong Park
569*54fd6939SJiyong Park if ((path == NULL) || (dir == NULL)) {
570*54fd6939SJiyong Park return -1;
571*54fd6939SJiyong Park }
572*54fd6939SJiyong Park
573*54fd6939SJiyong Park len = strlen(path);
574*54fd6939SJiyong Park if ((len + 1) > sizeof(dirname)) {
575*54fd6939SJiyong Park return -1;
576*54fd6939SJiyong Park }
577*54fd6939SJiyong Park
578*54fd6939SJiyong Park memcpy(dirname, path, len);
579*54fd6939SJiyong Park for (p = dirname + len; p > dirname; --p) {
580*54fd6939SJiyong Park if (*p != '/') {
581*54fd6939SJiyong Park break;
582*54fd6939SJiyong Park }
583*54fd6939SJiyong Park }
584*54fd6939SJiyong Park
585*54fd6939SJiyong Park p = memrchr(dirname, '/', p - dirname);
586*54fd6939SJiyong Park if (p == NULL) {
587*54fd6939SJiyong Park return -1;
588*54fd6939SJiyong Park }
589*54fd6939SJiyong Park
590*54fd6939SJiyong Park dirname[p - dirname + 1] = '\0';
591*54fd6939SJiyong Park
592*54fd6939SJiyong Park channel = path_to_channel(dirname, O_STAT);
593*54fd6939SJiyong Park if (channel == NULL) {
594*54fd6939SJiyong Park return -1;
595*54fd6939SJiyong Park }
596*54fd6939SJiyong Park
597*54fd6939SJiyong Park r = devtab[channel->index]->stat(channel, path, dir);
598*54fd6939SJiyong Park channel_close(channel);
599*54fd6939SJiyong Park
600*54fd6939SJiyong Park return r;
601*54fd6939SJiyong Park }
602*54fd6939SJiyong Park
603*54fd6939SJiyong Park /*******************************************************************************
604*54fd6939SJiyong Park * This function calls the read function of the driver associated to fd.
605*54fd6939SJiyong Park * It fills buf with at most n bytes.
606*54fd6939SJiyong Park * It returns the number of bytes that were actually read.
607*54fd6939SJiyong Park ******************************************************************************/
read(int fd,void * buf,int n)608*54fd6939SJiyong Park int read(int fd, void *buf, int n)
609*54fd6939SJiyong Park {
610*54fd6939SJiyong Park chan_t *channel;
611*54fd6939SJiyong Park
612*54fd6939SJiyong Park if (buf == NULL) {
613*54fd6939SJiyong Park return -1;
614*54fd6939SJiyong Park }
615*54fd6939SJiyong Park
616*54fd6939SJiyong Park channel = fd_to_channel(fd);
617*54fd6939SJiyong Park if (channel == NULL) {
618*54fd6939SJiyong Park return -1;
619*54fd6939SJiyong Park }
620*54fd6939SJiyong Park
621*54fd6939SJiyong Park if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) {
622*54fd6939SJiyong Park return -1;
623*54fd6939SJiyong Park }
624*54fd6939SJiyong Park
625*54fd6939SJiyong Park return devtab[channel->index]->read(channel, buf, n);
626*54fd6939SJiyong Park }
627*54fd6939SJiyong Park
628*54fd6939SJiyong Park /*******************************************************************************
629*54fd6939SJiyong Park * This function calls the write function of the driver associated to fd.
630*54fd6939SJiyong Park * It writes at most n bytes of buf.
631*54fd6939SJiyong Park * It returns the number of bytes that were actually written.
632*54fd6939SJiyong Park ******************************************************************************/
write(int fd,void * buf,int n)633*54fd6939SJiyong Park int write(int fd, void *buf, int n)
634*54fd6939SJiyong Park {
635*54fd6939SJiyong Park chan_t *channel;
636*54fd6939SJiyong Park
637*54fd6939SJiyong Park if (buf == NULL) {
638*54fd6939SJiyong Park return -1;
639*54fd6939SJiyong Park }
640*54fd6939SJiyong Park
641*54fd6939SJiyong Park channel = fd_to_channel(fd);
642*54fd6939SJiyong Park if (channel == NULL) {
643*54fd6939SJiyong Park return -1;
644*54fd6939SJiyong Park }
645*54fd6939SJiyong Park
646*54fd6939SJiyong Park if ((channel->qid & CHDIR) != 0) {
647*54fd6939SJiyong Park return -1;
648*54fd6939SJiyong Park }
649*54fd6939SJiyong Park
650*54fd6939SJiyong Park return devtab[channel->index]->write(channel, buf, n);
651*54fd6939SJiyong Park }
652*54fd6939SJiyong Park
653*54fd6939SJiyong Park /*******************************************************************************
654*54fd6939SJiyong Park * This function calls the seek function of the driver associated to fd.
655*54fd6939SJiyong Park * It applies the offset off according to the strategy whence.
656*54fd6939SJiyong Park ******************************************************************************/
seek(int fd,long off,int whence)657*54fd6939SJiyong Park int seek(int fd, long off, int whence)
658*54fd6939SJiyong Park {
659*54fd6939SJiyong Park chan_t *channel;
660*54fd6939SJiyong Park
661*54fd6939SJiyong Park channel = fd_to_channel(fd);
662*54fd6939SJiyong Park if (channel == NULL) {
663*54fd6939SJiyong Park return -1;
664*54fd6939SJiyong Park }
665*54fd6939SJiyong Park
666*54fd6939SJiyong Park if ((channel->qid & CHDIR) != 0) {
667*54fd6939SJiyong Park return -1;
668*54fd6939SJiyong Park }
669*54fd6939SJiyong Park
670*54fd6939SJiyong Park return devtab[channel->index]->seek(channel, off, whence);
671*54fd6939SJiyong Park }
672*54fd6939SJiyong Park
673*54fd6939SJiyong Park /*******************************************************************************
674*54fd6939SJiyong Park * This function is the default error implementation of the driver mount
675*54fd6939SJiyong Park * function.
676*54fd6939SJiyong Park ******************************************************************************/
deverrmount(chan_t * channel,const char * spec)677*54fd6939SJiyong Park chan_t *deverrmount(chan_t *channel, const char *spec)
678*54fd6939SJiyong Park {
679*54fd6939SJiyong Park return NULL;
680*54fd6939SJiyong Park }
681*54fd6939SJiyong Park
682*54fd6939SJiyong Park /*******************************************************************************
683*54fd6939SJiyong Park * This function is the default error implementation of the driver write
684*54fd6939SJiyong Park * function.
685*54fd6939SJiyong Park ******************************************************************************/
deverrwrite(chan_t * channel,void * buf,int n)686*54fd6939SJiyong Park int deverrwrite(chan_t *channel, void *buf, int n)
687*54fd6939SJiyong Park {
688*54fd6939SJiyong Park return -1;
689*54fd6939SJiyong Park }
690*54fd6939SJiyong Park
691*54fd6939SJiyong Park /*******************************************************************************
692*54fd6939SJiyong Park * This function is the default error implementation of the driver seek
693*54fd6939SJiyong Park * function.
694*54fd6939SJiyong Park ******************************************************************************/
deverrseek(chan_t * channel,long off,int whence)695*54fd6939SJiyong Park int deverrseek(chan_t *channel, long off, int whence)
696*54fd6939SJiyong Park {
697*54fd6939SJiyong Park return -1;
698*54fd6939SJiyong Park }
699*54fd6939SJiyong Park
700*54fd6939SJiyong Park /*******************************************************************************
701*54fd6939SJiyong Park * This function is the default implementation of the driver seek function.
702*54fd6939SJiyong Park * It applies the offset off according to the strategy whence to the channel c.
703*54fd6939SJiyong Park ******************************************************************************/
devseek(chan_t * channel,long off,int whence)704*54fd6939SJiyong Park int devseek(chan_t *channel, long off, int whence)
705*54fd6939SJiyong Park {
706*54fd6939SJiyong Park switch (whence) {
707*54fd6939SJiyong Park case KSEEK_SET:
708*54fd6939SJiyong Park channel->offset = off;
709*54fd6939SJiyong Park break;
710*54fd6939SJiyong Park case KSEEK_CUR:
711*54fd6939SJiyong Park channel->offset += off;
712*54fd6939SJiyong Park break;
713*54fd6939SJiyong Park case KSEEK_END:
714*54fd6939SJiyong Park /* Not implemented */
715*54fd6939SJiyong Park return -1;
716*54fd6939SJiyong Park }
717*54fd6939SJiyong Park
718*54fd6939SJiyong Park return 0;
719*54fd6939SJiyong Park }
720*54fd6939SJiyong Park
721*54fd6939SJiyong Park /*******************************************************************************
722*54fd6939SJiyong Park * This function registers the channel associated to the path new as a mount
723*54fd6939SJiyong Park * point for the channel c.
724*54fd6939SJiyong Park ******************************************************************************/
add_mount_point(chan_t * channel,const char * new)725*54fd6939SJiyong Park static int add_mount_point(chan_t *channel, const char *new)
726*54fd6939SJiyong Park {
727*54fd6939SJiyong Park int i;
728*54fd6939SJiyong Park chan_t *cn;
729*54fd6939SJiyong Park struct mount_point *mp;
730*54fd6939SJiyong Park
731*54fd6939SJiyong Park if (new == NULL) {
732*54fd6939SJiyong Park goto err0;
733*54fd6939SJiyong Park }
734*54fd6939SJiyong Park
735*54fd6939SJiyong Park cn = path_to_channel(new, O_READ);
736*54fd6939SJiyong Park if (cn == NULL) {
737*54fd6939SJiyong Park goto err0;
738*54fd6939SJiyong Park }
739*54fd6939SJiyong Park
740*54fd6939SJiyong Park if ((cn->qid & CHDIR) == 0) {
741*54fd6939SJiyong Park goto err1;
742*54fd6939SJiyong Park }
743*54fd6939SJiyong Park
744*54fd6939SJiyong Park for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) {
745*54fd6939SJiyong Park mp = &mount_points[i];
746*54fd6939SJiyong Park if (mp->new == NULL) {
747*54fd6939SJiyong Park break;
748*54fd6939SJiyong Park }
749*54fd6939SJiyong Park }
750*54fd6939SJiyong Park
751*54fd6939SJiyong Park if (i < 0) {
752*54fd6939SJiyong Park goto err1;
753*54fd6939SJiyong Park }
754*54fd6939SJiyong Park
755*54fd6939SJiyong Park mp->new = cn;
756*54fd6939SJiyong Park mp->old = channel;
757*54fd6939SJiyong Park
758*54fd6939SJiyong Park return 0;
759*54fd6939SJiyong Park
760*54fd6939SJiyong Park err1:
761*54fd6939SJiyong Park channel_close(cn);
762*54fd6939SJiyong Park err0:
763*54fd6939SJiyong Park return -1;
764*54fd6939SJiyong Park }
765*54fd6939SJiyong Park
766*54fd6939SJiyong Park /*******************************************************************************
767*54fd6939SJiyong Park * This function registers the path new as a mount point for the path old.
768*54fd6939SJiyong Park ******************************************************************************/
bind(const char * old,const char * new)769*54fd6939SJiyong Park int bind(const char *old, const char *new)
770*54fd6939SJiyong Park {
771*54fd6939SJiyong Park chan_t *channel;
772*54fd6939SJiyong Park
773*54fd6939SJiyong Park channel = path_to_channel(old, O_BIND);
774*54fd6939SJiyong Park if (channel == NULL) {
775*54fd6939SJiyong Park return -1;
776*54fd6939SJiyong Park }
777*54fd6939SJiyong Park
778*54fd6939SJiyong Park if (add_mount_point(channel, new) < 0) {
779*54fd6939SJiyong Park channel_close(channel);
780*54fd6939SJiyong Park return -1;
781*54fd6939SJiyong Park }
782*54fd6939SJiyong Park
783*54fd6939SJiyong Park return 0;
784*54fd6939SJiyong Park }
785*54fd6939SJiyong Park
786*54fd6939SJiyong Park /*******************************************************************************
787*54fd6939SJiyong Park * This function calls the mount function of the driver associated to the path
788*54fd6939SJiyong Park * srv.
789*54fd6939SJiyong Park * It mounts the path srv on the path where.
790*54fd6939SJiyong Park ******************************************************************************/
mount(const char * srv,const char * where,const char * spec)791*54fd6939SJiyong Park int mount(const char *srv, const char *where, const char *spec)
792*54fd6939SJiyong Park {
793*54fd6939SJiyong Park chan_t *channel, *mount_point_chan;
794*54fd6939SJiyong Park int ret;
795*54fd6939SJiyong Park
796*54fd6939SJiyong Park channel = path_to_channel(srv, O_RDWR);
797*54fd6939SJiyong Park if (channel == NULL) {
798*54fd6939SJiyong Park goto err0;
799*54fd6939SJiyong Park }
800*54fd6939SJiyong Park
801*54fd6939SJiyong Park mount_point_chan = devtab[channel->index]->mount(channel, spec);
802*54fd6939SJiyong Park if (mount_point_chan == NULL) {
803*54fd6939SJiyong Park goto err1;
804*54fd6939SJiyong Park }
805*54fd6939SJiyong Park
806*54fd6939SJiyong Park ret = add_mount_point(mount_point_chan, where);
807*54fd6939SJiyong Park if (ret < 0) {
808*54fd6939SJiyong Park goto err2;
809*54fd6939SJiyong Park }
810*54fd6939SJiyong Park
811*54fd6939SJiyong Park channel_close(channel);
812*54fd6939SJiyong Park
813*54fd6939SJiyong Park return 0;
814*54fd6939SJiyong Park
815*54fd6939SJiyong Park err2:
816*54fd6939SJiyong Park channel_close(mount_point_chan);
817*54fd6939SJiyong Park err1:
818*54fd6939SJiyong Park channel_close(channel);
819*54fd6939SJiyong Park err0:
820*54fd6939SJiyong Park return -1;
821*54fd6939SJiyong Park }
822*54fd6939SJiyong Park
823*54fd6939SJiyong Park /*******************************************************************************
824*54fd6939SJiyong Park * This function initializes the device environment.
825*54fd6939SJiyong Park * It creates the '/' channel.
826*54fd6939SJiyong Park * It links the device drivers to the physical drivers.
827*54fd6939SJiyong Park ******************************************************************************/
debugfs_init(void)828*54fd6939SJiyong Park void debugfs_init(void)
829*54fd6939SJiyong Park {
830*54fd6939SJiyong Park chan_t *channel, *cloned_channel;
831*54fd6939SJiyong Park
832*54fd6939SJiyong Park for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) {
833*54fd6939SJiyong Park channel_clear(channel);
834*54fd6939SJiyong Park }
835*54fd6939SJiyong Park
836*54fd6939SJiyong Park channel = devattach('/', 0);
837*54fd6939SJiyong Park if (channel == NULL) {
838*54fd6939SJiyong Park panic();
839*54fd6939SJiyong Park }
840*54fd6939SJiyong Park
841*54fd6939SJiyong Park cloned_channel = clone(channel, &slash_channel);
842*54fd6939SJiyong Park if (cloned_channel == NULL) {
843*54fd6939SJiyong Park panic();
844*54fd6939SJiyong Park }
845*54fd6939SJiyong Park
846*54fd6939SJiyong Park channel_close(channel);
847*54fd6939SJiyong Park devlink();
848*54fd6939SJiyong Park }
849*54fd6939SJiyong Park
devpanic(const char * cause)850*54fd6939SJiyong Park __dead2 void devpanic(const char *cause)
851*54fd6939SJiyong Park {
852*54fd6939SJiyong Park panic();
853*54fd6939SJiyong Park }
854