Remove building with NOCRYPTO option
[minix.git] / minix / drivers / system / log / log.c
blob8869eedd27eb7ef3b35a57df830dc7fd5047eb8f
1 /* This file contains a driver for:
2 * /dev/klog - system log device
4 * Changes:
5 * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder)
6 * 7 July 2005 - Created (Ben Gras)
7 */
9 #include "log.h"
10 #include <sys/time.h>
11 #include <sys/select.h>
12 #include <minix/endpoint.h>
14 #define LOG_DEBUG 0 /* enable/ disable debugging */
16 #define NR_DEVS 1 /* number of minor devices */
17 #define MINOR_KLOG 0 /* /dev/klog */
19 #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
21 struct logdevice logdevices[NR_DEVS];
23 static ssize_t log_read(devminor_t minor, u64_t position, endpoint_t endpt,
24 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
25 static ssize_t log_write(devminor_t minor, u64_t position, endpoint_t endpt,
26 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
27 static int log_open(devminor_t minor, int access, endpoint_t user_endpt);
28 static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
29 static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt);
30 static int subread(struct logdevice *log, size_t size, endpoint_t endpt,
31 cp_grant_id_t grant);
33 /* Entry points to this driver. */
34 static struct chardriver log_dtab = {
35 .cdr_open = log_open,
36 .cdr_read = log_read,
37 .cdr_write = log_write,
38 .cdr_cancel = log_cancel,
39 .cdr_select = log_select
42 /* SEF functions and variables. */
43 static void sef_local_startup(void);
44 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
45 EXTERN int sef_cb_lu_prepare(int state);
46 EXTERN int sef_cb_lu_state_isvalid(int state, int flags);
47 EXTERN void sef_cb_lu_state_dump(int state);
48 static void sef_cb_signal_handler(int signo);
50 /*===========================================================================*
51 * main *
52 *===========================================================================*/
53 int main(void)
55 /* SEF local startup. */
56 sef_local_startup();
58 /* Call the generic receive loop. */
59 chardriver_task(&log_dtab);
61 return(OK);
64 /*===========================================================================*
65 * sef_local_startup *
66 *===========================================================================*/
67 static void sef_local_startup()
69 /* Register init callbacks. */
70 sef_setcb_init_fresh(sef_cb_init_fresh);
72 /* Register live update callbacks. */
73 sef_setcb_lu_prepare(sef_cb_lu_prepare);
74 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
75 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
77 /* Register signal callbacks. */
78 sef_setcb_signal_handler(sef_cb_signal_handler);
80 /* Let SEF perform startup. */
81 sef_startup();
84 /*===========================================================================*
85 * sef_cb_init_fresh *
86 *===========================================================================*/
87 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
89 /* Initialize the log driver. */
90 int i;
92 /* Initialize log devices. */
93 for(i = 0; i < NR_DEVS; i++) {
94 logdevices[i].log_size = logdevices[i].log_read =
95 logdevices[i].log_write =
96 logdevices[i].log_selected = 0;
97 logdevices[i].log_source = NONE;
100 /* Register for diagnostics notifications. */
101 sys_diagctl_register();
103 /* Announce we are up! */
104 chardriver_announce();
106 return(OK);
109 /*===========================================================================*
110 * sef_cb_signal_handler *
111 *===========================================================================*/
112 static void sef_cb_signal_handler(int signo)
114 /* Only check for a pending message from the kernel, ignore anything else. */
115 if (signo != SIGKMESS) return;
117 do_new_kmess();
120 /*===========================================================================*
121 * subwrite *
122 *===========================================================================*/
123 static int
124 subwrite(struct logdevice *log, size_t size, endpoint_t endpt,
125 cp_grant_id_t grant, char *localbuf)
127 size_t count, offset;
128 int overflow, r, result;
129 devminor_t minor;
130 char *buf;
131 message m;
133 /* With a sufficiently large input size, we might wrap around the ring buffer
134 * multiple times.
136 result = 0;
137 for (offset = 0; offset < size; offset += count) {
138 count = size - offset;
140 if (log->log_write + count > LOG_SIZE)
141 count = LOG_SIZE - log->log_write;
142 buf = log->log_buffer + log->log_write;
144 if(localbuf != NULL) {
145 memcpy(buf, localbuf, count);
146 localbuf += count;
148 else {
149 if((r=sys_safecopyfrom(endpt, grant, offset,
150 (vir_bytes)buf, count)) != OK) {
151 /* return any partial success upon error */
152 result = (offset > 0) ? (int)offset : r;
153 break;
157 LOGINC(log->log_write, count);
158 log->log_size += count;
160 if(log->log_size > LOG_SIZE) {
161 overflow = log->log_size - LOG_SIZE;
162 log->log_size -= overflow;
163 LOGINC(log->log_read, overflow);
166 result += (int)count;
169 if (log->log_size > 0 && log->log_source != NONE) {
170 /* Someone who was suspended on read can now be revived. */
171 r = subread(log, log->log_iosize, log->log_source, log->log_grant);
173 chardriver_reply_task(log->log_source, log->log_id, r);
175 log->log_source = NONE;
178 if (log->log_size > 0 && (log->log_selected & CDEV_OP_RD)) {
179 /* Someone(s) who was/were select()ing can now be awoken. If there was
180 * a blocking read (above), this can only happen if the blocking read
181 * didn't swallow all the data (log_size > 0).
183 minor = log-logdevices;
184 #if LOG_DEBUG
185 printf("select sending CDEV_SEL2_REPLY\n");
186 #endif
187 chardriver_reply_select(log->log_select_proc, minor, CDEV_OP_RD);
188 log->log_selected &= ~CDEV_OP_RD;
191 return result;
194 /*===========================================================================*
195 * log_append *
196 *===========================================================================*/
197 void
198 log_append(char *buf, int count)
200 int skip = 0;
202 if(count < 1) return;
203 if(count > LOG_SIZE) skip = count - LOG_SIZE;
204 count -= skip;
205 buf += skip;
207 subwrite(&logdevices[0], count, SELF, GRANT_INVALID, buf);
210 /*===========================================================================*
211 * subread *
212 *===========================================================================*/
213 static int
214 subread(struct logdevice *log, size_t size, endpoint_t endpt,
215 cp_grant_id_t grant)
217 size_t offset, count;
218 char *buf;
219 int r;
221 for (offset = 0; log->log_size > 0 && offset < size; offset += count) {
222 count = size - offset;
224 if (count > log->log_size)
225 count = log->log_size;
226 if (log->log_read + count > LOG_SIZE)
227 count = LOG_SIZE - log->log_read;
229 buf = log->log_buffer + log->log_read;
230 if((r=sys_safecopyto(endpt, grant, offset, (vir_bytes)buf,
231 count)) != OK)
232 return r;
234 LOGINC(log->log_read, count);
235 log->log_size -= count;
238 return offset;
241 /*===========================================================================*
242 * log_read *
243 *===========================================================================*/
244 static ssize_t log_read(devminor_t minor, u64_t UNUSED(position),
245 endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
246 cdev_id_t id)
248 /* Read from one of the driver's minor devices. */
249 struct logdevice *log;
250 int r;
252 if (minor < 0 || minor >= NR_DEVS) return EIO;
253 log = &logdevices[minor];
255 /* If there's already someone hanging to read, don't accept new work. */
256 if (log->log_source != NONE) return OK;
258 if (!log->log_size && size > 0) {
259 if (flags & CDEV_NONBLOCK) return EAGAIN;
261 /* No data available; let caller block. */
262 log->log_source = endpt;
263 log->log_iosize = size;
264 log->log_grant = grant;
265 log->log_id = id;
266 #if LOG_DEBUG
267 printf("blocked %d (%d)\n", log->log_source, id);
268 #endif
269 return EDONTREPLY;
272 return subread(log, size, endpt, grant);
275 /*===========================================================================*
276 * log_write *
277 *===========================================================================*/
278 static ssize_t log_write(devminor_t minor, u64_t UNUSED(position),
279 endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
280 cdev_id_t UNUSED(id))
282 /* Write to one of the driver's minor devices. */
283 struct logdevice *log;
284 int r;
286 if (minor < 0 || minor >= NR_DEVS) return EIO;
287 log = &logdevices[minor];
289 return subwrite(log, size, endpt, grant, NULL);
292 /*============================================================================*
293 * log_open *
294 *============================================================================*/
295 static int log_open(devminor_t minor, int UNUSED(access),
296 endpoint_t UNUSED(user_endpt))
298 if (minor < 0 || minor >= NR_DEVS) return(ENXIO);
300 return(OK);
303 /*============================================================================*
304 * log_cancel *
305 *============================================================================*/
306 static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
308 if (minor < 0 || minor >= NR_DEVS)
309 return EINVAL;
311 /* Not for the suspended request? Must be a stale cancel request. Ignore. */
312 if (logdevices[minor].log_source != endpt || logdevices[minor].log_id != id)
313 return EDONTREPLY;
315 logdevices[minor].log_source = NONE;
317 return EINTR; /* this is the reply to the original, interrupted request */
320 /*============================================================================*
321 * log_select *
322 *============================================================================*/
323 static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
325 int want_ops, ready_ops = 0;
327 if (minor < 0 || minor >= NR_DEVS)
328 return ENXIO;
330 want_ops = ops & (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
332 /* Read blocks when there is no log. */
333 if ((want_ops & CDEV_OP_RD) && logdevices[minor].log_size > 0) {
334 #if LOG_DEBUG
335 printf("log can read; size %d\n", logdevices[minor].log_size);
336 #endif
337 ready_ops |= CDEV_OP_RD;
340 /* Write never blocks. */
341 if (want_ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR;
343 /* Enable select calback if not all requested operations were ready to go,
344 * and notify was enabled.
346 want_ops &= ~ready_ops;
347 if ((ops & CDEV_NOTIFY) && want_ops) {
348 logdevices[minor].log_selected |= want_ops;
349 logdevices[minor].log_select_proc = endpt;
350 #if LOG_DEBUG
351 printf("log setting selector.\n");
352 #endif
355 #if LOG_DEBUG
356 printf("log returning ops %d\n", ready_ops);
357 #endif
359 return(ready_ops);