1 /* This file contains a driver for:
2 * /dev/klog - system log device
5 * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder)
6 * 7 July 2005 - Created (Ben Gras)
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
,
33 /* Entry points to this driver. */
34 static struct chardriver log_dtab
= {
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 /*===========================================================================*
52 *===========================================================================*/
55 /* SEF local startup. */
58 /* Call the generic receive loop. */
59 chardriver_task(&log_dtab
);
64 /*===========================================================================*
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. */
84 /*===========================================================================*
86 *===========================================================================*/
87 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
89 /* Initialize the log driver. */
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();
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;
120 /*===========================================================================*
122 *===========================================================================*/
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
;
133 /* With a sufficiently large input size, we might wrap around the ring buffer
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
);
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
;
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
;
185 printf("select sending CDEV_SEL2_REPLY\n");
187 chardriver_reply_select(log
->log_select_proc
, minor
, CDEV_OP_RD
);
188 log
->log_selected
&= ~CDEV_OP_RD
;
194 /*===========================================================================*
196 *===========================================================================*/
198 log_append(char *buf
, int count
)
202 if(count
< 1) return;
203 if(count
> LOG_SIZE
) skip
= count
- LOG_SIZE
;
207 subwrite(&logdevices
[0], count
, SELF
, GRANT_INVALID
, buf
);
210 /*===========================================================================*
212 *===========================================================================*/
214 subread(struct logdevice
*log
, size_t size
, endpoint_t endpt
,
217 size_t offset
, count
;
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
,
234 LOGINC(log
->log_read
, count
);
235 log
->log_size
-= count
;
241 /*===========================================================================*
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
,
248 /* Read from one of the driver's minor devices. */
249 struct logdevice
*log
;
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
;
267 printf("blocked %d (%d)\n", log
->log_source
, id
);
272 return subread(log
, size
, endpt
, grant
);
275 /*===========================================================================*
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
;
286 if (minor
< 0 || minor
>= NR_DEVS
) return EIO
;
287 log
= &logdevices
[minor
];
289 return subwrite(log
, size
, endpt
, grant
, NULL
);
292 /*============================================================================*
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
);
303 /*============================================================================*
305 *============================================================================*/
306 static int log_cancel(devminor_t minor
, endpoint_t endpt
, cdev_id_t id
)
308 if (minor
< 0 || minor
>= NR_DEVS
)
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
)
315 logdevices
[minor
].log_source
= NONE
;
317 return EINTR
; /* this is the reply to the original, interrupted request */
320 /*============================================================================*
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
)
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) {
335 printf("log can read; size %d\n", logdevices
[minor
].log_size
);
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
;
351 printf("log setting selector.\n");
356 printf("log returning ops %d\n", ready_ops
);