1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
3 #include <libubox/avl-cmp.h>
11 static void phy_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
12 struct vlist_node
*node_old
);
14 VLIST_TREE(phy_list
, avl_strcmp
, phy_update
, true, false);
17 phy_file_path(struct phy
*phy
, const char *file
)
21 snprintf(path
, sizeof(path
), "/sys/kernel/debug/ieee80211/%s/rc/%s", phy_name(phy
), file
);
27 phy_event_read_buf(struct phy
*phy
, char *buf
)
32 for (cur
= buf
; (next
= strchr(cur
, '\n')); cur
= next
+ 1) {
35 rcd_client_phy_event(phy
, cur
);
40 memmove(buf
, cur
, len
+ 1);
46 phy_event_cb(struct uloop_fd
*fd
, unsigned int events
)
48 struct phy
*phy
= container_of(fd
, struct phy
, event_fd
);
53 len
= read(fd
->fd
, buf
+ offset
, sizeof(buf
) - 1 - offset
);
61 vlist_delete(&phy_list
, &phy
->node
);
68 buf
[offset
+ len
] = 0;
69 offset
= phy_event_read_buf(phy
, buf
);
74 phy_init(struct phy
*phy
)
80 phy_add(struct phy
*phy
)
84 cfd
= open(phy_file_path(phy
, "api_control"), O_WRONLY
);
88 efd
= open(phy_file_path(phy
, "api_event"), O_RDONLY
);
92 phy
->control_fd
= cfd
;
93 phy
->event_fd
.fd
= efd
;
94 phy
->event_fd
.cb
= phy_event_cb
;
95 uloop_fd_add(&phy
->event_fd
, ULOOP_READ
);
97 rcd_client_set_phy_state(NULL
, phy
, true);
103 vlist_delete(&phy_list
, &phy
->node
);
107 phy_remove(struct phy
*phy
)
109 if (phy
->control_fd
< 0)
112 rcd_client_set_phy_state(NULL
, phy
, false);
113 uloop_fd_delete(&phy
->event_fd
);
114 close(phy
->control_fd
);
115 close(phy
->event_fd
.fd
);
122 phy_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
123 struct vlist_node
*node_old
)
125 struct phy
*phy_new
= node_new
? container_of(node_new
, struct phy
, node
) : NULL
;
126 struct phy
*phy_old
= node_old
? container_of(node_old
, struct phy
, node
) : NULL
;
128 if (phy_new
&& phy_old
)
136 static void phy_refresh_timer(struct uloop_timeout
*t
)
141 glob("/sys/kernel/debug/ieee80211/phy*", 0, NULL
, &gl
);
142 for (i
= 0; i
< gl
.gl_pathc
; i
++) {
144 char *name
, *name_buf
;
146 name
= basename(gl
.gl_pathv
[i
]);
147 phy
= calloc_a(sizeof(*phy
), &name_buf
, strlen(name
) + 1);
149 vlist_add(&phy_list
, &phy
->node
, strcpy(name_buf
, name
));
153 uloop_timeout_set(t
, 1000);
156 void rcd_phy_init_client(struct client
*cl
)
160 vlist_for_each_element(&phy_list
, phy
, node
)
161 rcd_client_set_phy_state(cl
, phy
, true);
164 void rcd_phy_dump(struct client
*cl
, struct phy
*phy
)
169 f
= fopen(phy_file_path(phy
, "api_info"), "r");
173 while (fgets(buf
, sizeof(buf
), f
) != NULL
)
174 client_printf(cl
, "*;0;%s", buf
);
179 void rcd_phy_control(struct client
*cl
, char *data
)
185 sep
= strchr(data
, ';');
187 err
= "Syntax error";
192 phy
= vlist_find(&phy_list
, data
, phy
, node
);
194 err
= "PHY not found";
200 if (write(phy
->control_fd
, data
, strlen(data
)) < 0) {
201 if (errno
== EINTR
|| errno
== EAGAIN
)
204 err
= strerror(errno
);
211 client_printf(cl
, "*;0;#error;%s\n", err
);
214 void rcd_phy_init(void)
216 static struct uloop_timeout t
= {
217 .cb
= phy_refresh_timer
220 uloop_timeout_set(&t
, 1);