00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "log.h"
00010 #include <sys/time.h>
00011 #include <sys/select.h>
00012 #include "../../kernel/const.h"
00013 #include "../../kernel/type.h"
00014
00015 #define LOG_DEBUG 0
00016
00017 #define NR_DEVS 1
00018 #define MINOR_KLOG 0
00019
00020 #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
00021
00022 PUBLIC struct logdevice logdevices[NR_DEVS];
00023 PRIVATE struct device log_geom[NR_DEVS];
00024 PRIVATE int log_device = -1;
00025
00026 FORWARD _PROTOTYPE( char *log_name, (void) );
00027 FORWARD _PROTOTYPE( struct device *log_prepare, (int device) );
00028 FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, off_t position,
00029 iovec_t *iov, unsigned nr_req) );
00030 FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
00031 FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
00032 FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
00033 FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, message *m_ptr) );
00034 FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) );
00035 FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
00036 FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) );
00037
00038
00039 PRIVATE struct driver log_dtab = {
00040 log_name,
00041 log_do_open,
00042 do_nop,
00043 do_nop,
00044 log_prepare,
00045 log_transfer,
00046 nop_cleanup,
00047 log_geometry,
00048 log_signal,
00049 nop_alarm,
00050 log_cancel,
00051 log_select,
00052 log_other,
00053 NULL
00054 };
00055
00056 extern int device_caller;
00057
00058
00059
00060
00061 PUBLIC int main(void)
00062 {
00063 int i;
00064 for(i = 0; i < NR_DEVS; i++) {
00065 log_geom[i].dv_size = cvul64(LOG_SIZE);
00066 log_geom[i].dv_base = cvul64((long)logdevices[i].log_buffer);
00067 logdevices[i].log_size = logdevices[i].log_read =
00068 logdevices[i].log_write =
00069 logdevices[i].log_select_alerted =
00070 logdevices[i].log_selected =
00071 logdevices[i].log_select_ready_ops = 0;
00072 logdevices[i].log_proc_nr = 0;
00073 logdevices[i].log_revive_alerted = 0;
00074 }
00075 driver_task(&log_dtab);
00076 return(OK);
00077 }
00078
00079
00080
00081
00082 PRIVATE char *log_name()
00083 {
00084
00085 static char name[] = "log";
00086 return name;
00087 }
00088
00089
00090
00091
00092 PRIVATE struct device *log_prepare(device)
00093 int device;
00094 {
00095
00096
00097 if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
00098 log_device = device;
00099
00100 return(&log_geom[device]);
00101 }
00102
00103
00104
00105
00106 PRIVATE int
00107 subwrite(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
00108 {
00109 char *buf;
00110 int r;
00111 if (log->log_write + count > LOG_SIZE)
00112 count = LOG_SIZE - log->log_write;
00113 buf = log->log_buffer + log->log_write;
00114
00115 if(proc_nr == SELF) {
00116 memcpy(buf, (char *) user_vir, count);
00117 }
00118 else {
00119 if((r=sys_vircopy(proc_nr,D,user_vir, SELF,D,(int)buf, count)) != OK)
00120 return r;
00121 }
00122
00123 LOGINC(log->log_write, count);
00124 log->log_size += count;
00125
00126 if(log->log_size > LOG_SIZE) {
00127 int overflow;
00128 overflow = log->log_size - LOG_SIZE;
00129 log->log_size -= overflow;
00130 LOGINC(log->log_read, overflow);
00131 }
00132
00133 if(log->log_size > 0 && log->log_proc_nr && !log->log_revive_alerted) {
00134
00135
00136
00137 log->log_status = subread(log, log->log_iosize,
00138 log->log_proc_nr, log->log_user_vir);
00139 notify(log->log_source);
00140 log->log_revive_alerted = 1;
00141 }
00142
00143 if(log->log_size > 0)
00144 log->log_select_ready_ops |= SEL_RD;
00145
00146 if(log->log_size > 0 && log->log_selected &&
00147 !(log->log_select_alerted)) {
00148
00149
00150
00151
00152
00153 if(log->log_selected & SEL_RD) {
00154 notify(log->log_select_proc);
00155 log->log_select_alerted = 1;
00156 #if LOG_DEBUG
00157 printf("log notified %d\n", log->log_select_proc);
00158 #endif
00159 }
00160 }
00161
00162 return count;
00163 }
00164
00165
00166
00167
00168 PUBLIC void
00169 log_append(char *buf, int count)
00170 {
00171 int w = 0, skip = 0;
00172
00173 if(count < 1) return;
00174 if(count > LOG_SIZE) skip = count - LOG_SIZE;
00175 count -= skip;
00176 buf += skip;
00177 w = subwrite(&logdevices[0], count, SELF, (vir_bytes) buf);
00178
00179 if(w > 0 && w < count)
00180 subwrite(&logdevices[0], count-w, SELF, (vir_bytes) buf+w);
00181 return;
00182 }
00183
00184
00185
00186
00187 PRIVATE int
00188 subread(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
00189 {
00190 char *buf;
00191 int r;
00192 if (count > log->log_size)
00193 count = log->log_size;
00194 if (log->log_read + count > LOG_SIZE)
00195 count = LOG_SIZE - log->log_read;
00196
00197 buf = log->log_buffer + log->log_read;
00198 if((r=sys_vircopy(SELF,D,(int)buf,proc_nr,D,user_vir, count)) != OK)
00199 return r;
00200
00201 LOGINC(log->log_read, count);
00202 log->log_size -= count;
00203
00204 return count;
00205 }
00206
00207
00208
00209
00210 PRIVATE int log_transfer(proc_nr, opcode, position, iov, nr_req)
00211 int proc_nr;
00212 int opcode;
00213 off_t position;
00214 iovec_t *iov;
00215 unsigned nr_req;
00216 {
00217
00218 unsigned count;
00219 vir_bytes user_vir;
00220 struct device *dv;
00221 unsigned long dv_size;
00222 int accumulated_read = 0;
00223 struct logdevice *log;
00224 static int f;
00225
00226 if(log_device < 0 || log_device >= NR_DEVS)
00227 return EIO;
00228
00229
00230 dv = &log_geom[log_device];
00231 dv_size = cv64ul(dv->dv_size);
00232 log = &logdevices[log_device];
00233
00234 while (nr_req > 0) {
00235
00236 count = iov->iov_size;
00237 user_vir = iov->iov_addr;
00238
00239 switch (log_device) {
00240
00241 case MINOR_KLOG:
00242 if (opcode == DEV_GATHER) {
00243 if (log->log_proc_nr || count < 1) {
00244
00245
00246
00247 return(OK);
00248 }
00249
00250 if (!log->log_size) {
00251 if(accumulated_read)
00252 return OK;
00253
00254 log->log_proc_nr = proc_nr;
00255 log->log_iosize = count;
00256 log->log_user_vir = user_vir;
00257 log->log_revive_alerted = 0;
00258
00259
00260 log->log_source = device_caller;
00261 #if LOG_DEBUG
00262 printf("blocked %d (%d)\n",
00263 log->log_source, log->log_proc_nr);
00264 #endif
00265 return(SUSPEND);
00266 }
00267 count = subread(log, count, proc_nr, user_vir);
00268 if(count < 0) {
00269 return count;
00270 }
00271 accumulated_read += count;
00272 } else {
00273 count = subwrite(log, count, proc_nr, user_vir);
00274 if(count < 0)
00275 return count;
00276 }
00277 break;
00278
00279 default:
00280 return(EINVAL);
00281 }
00282
00283
00284 iov->iov_addr += count;
00285 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
00286 }
00287 return(OK);
00288 }
00289
00290
00291
00292
00293 PRIVATE int log_do_open(dp, m_ptr)
00294 struct driver *dp;
00295 message *m_ptr;
00296 {
00297 if (log_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00298 return(OK);
00299 }
00300
00301
00302
00303
00304 PRIVATE void log_geometry(entry)
00305 struct partition *entry;
00306 {
00307
00308 entry->heads = 64;
00309 entry->sectors = 32;
00310 entry->cylinders = div64u(log_geom[log_device].dv_size, SECTOR_SIZE) /
00311 (entry->heads * entry->sectors);
00312 }
00313
00314
00315
00316
00317 PRIVATE int log_cancel(dp, m_ptr)
00318 struct driver *dp;
00319 message *m_ptr;
00320 {
00321 int d;
00322 d = m_ptr->TTY_LINE;
00323 if(d < 0 || d >= NR_DEVS)
00324 return EINVAL;
00325 logdevices[d].log_proc_nr = 0;
00326 logdevices[d].log_revive_alerted = 0;
00327 return(OK);
00328 }
00329
00330
00331
00332
00333 PRIVATE void do_status(message *m_ptr)
00334 {
00335 int d;
00336 message m;
00337
00338
00339
00340
00341
00342
00343
00344 for(d = 0; d < NR_DEVS; d++) {
00345
00346 if(logdevices[d].log_proc_nr && logdevices[d].log_revive_alerted
00347 && logdevices[d].log_source == m_ptr->m_source) {
00348 m.m_type = DEV_REVIVE;
00349 m.REP_ENDPT = logdevices[d].log_proc_nr;
00350 m.REP_STATUS = logdevices[d].log_status;
00351 send(m_ptr->m_source, &m);
00352 logdevices[d].log_proc_nr = 0;
00353 logdevices[d].log_revive_alerted = 0;
00354 #if LOG_DEBUG
00355 printf("revived %d with %d bytes\n",
00356 m.REP_ENDPT, m.REP_STATUS);
00357 #endif
00358 return;
00359 }
00360
00361
00362 if(logdevices[d].log_selected && logdevices[d].log_select_proc == m_ptr->m_source
00363 && logdevices[d].log_select_alerted) {
00364 m.m_type = DEV_IO_READY;
00365 m.DEV_SEL_OPS = logdevices[d].log_select_ready_ops;
00366 m.DEV_MINOR = d;
00367 #if LOG_DEBUG
00368 printf("select sending sent\n");
00369 #endif
00370 send(m_ptr->m_source, &m);
00371 logdevices[d].log_selected &= ~logdevices[d].log_select_ready_ops;
00372 logdevices[d].log_select_alerted = 0;
00373 #if LOG_DEBUG
00374 printf("select send sent\n");
00375 #endif
00376 return;
00377 }
00378 }
00379
00380
00381 m.m_type = DEV_NO_STATUS;
00382 send(m_ptr->m_source, &m);
00383
00384 return;
00385 }
00386
00387
00388
00389
00390 PRIVATE void log_signal(dp, m_ptr)
00391 struct driver *dp;
00392 message *m_ptr;
00393 {
00394 sigset_t sigset = m_ptr->NOTIFY_ARG;
00395 if (sigismember(&sigset, SIGKMESS)) {
00396 do_new_kmess(m_ptr);
00397 }
00398 }
00399
00400
00401
00402
00403
00404 PRIVATE int log_other(dp, m_ptr)
00405 struct driver *dp;
00406 message *m_ptr;
00407 {
00408 int r;
00409
00410
00411
00412
00413 switch(m_ptr->m_type) {
00414 case DIAGNOSTICS: {
00415 r = do_diagnostics(m_ptr);
00416 break;
00417 }
00418 case DEV_STATUS: {
00419 do_status(m_ptr);
00420 r = EDONTREPLY;
00421 break;
00422 }
00423 case NOTIFY_FROM(TTY_PROC_NR):
00424 do_new_kmess(m_ptr);
00425 r = EDONTREPLY;
00426 break;
00427 default:
00428 r = EINVAL;
00429 break;
00430 }
00431 return r;
00432 }
00433
00434
00435
00436
00437 PRIVATE int log_select(dp, m_ptr)
00438 struct driver *dp;
00439 message *m_ptr;
00440 {
00441 int d, ready_ops = 0, ops = 0;
00442 d = m_ptr->TTY_LINE;
00443 if(d < 0 || d >= NR_DEVS) {
00444 #if LOG_DEBUG
00445 printf("line %d? EINVAL\n", d);
00446 #endif
00447 return EINVAL;
00448 }
00449
00450 ops = m_ptr->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
00451
00452
00453 if((m_ptr->IO_ENDPT & SEL_RD) && logdevices[d].log_size > 0) {
00454 #if LOG_DEBUG
00455 printf("log can read; size %d\n", logdevices[d].log_size);
00456 #endif
00457 ready_ops |= SEL_RD;
00458 }
00459
00460
00461 if(m_ptr->IO_ENDPT & SEL_WR) ready_ops |= SEL_WR;
00462
00463
00464
00465
00466
00467 if((m_ptr->IO_ENDPT & SEL_NOTIFY) && ops && !ready_ops) {
00468 logdevices[d].log_selected |= ops;
00469 logdevices[d].log_select_proc = m_ptr->m_source;
00470 #if LOG_DEBUG
00471 printf("log setting selector.\n");
00472 #endif
00473 }
00474
00475 #if LOG_DEBUG
00476 printf("log returning ops %d\n", ready_ops);
00477 #endif
00478
00479 return(ready_ops);
00480 }