00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <types.h>
00054 #include <kern/errno.h>
00055 #include <lib.h>
00056 #include <uio.h>
00057 #include <thread.h>
00058 #include <current.h>
00059 #include <synch.h>
00060 #include <generic/console.h>
00061 #include <vfs.h>
00062 #include <device.h>
00063 #include "autoconf.h"
00064
00065
00066
00067
00068 static struct con_softc *the_console = NULL;
00069
00070
00071
00072
00073
00074 static struct lock *con_userlock_read = NULL;
00075 static struct lock *con_userlock_write = NULL;
00076
00077
00078
00079
00080
00081
00082
00083
00084 #define DELAYBUFSIZE 1024
00085 static char delayed_outbuf[DELAYBUFSIZE];
00086 static size_t delayed_outbuf_pos=0;
00087
00088 static
00089 void
00090 putch_delayed(int ch)
00091 {
00092
00093
00094
00095
00096
00097 KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
00098 delayed_outbuf[delayed_outbuf_pos++] = ch;
00099 }
00100
00101 static
00102 void
00103 flush_delay_buf(void)
00104 {
00105 size_t i;
00106 for (i=0; i<delayed_outbuf_pos; i++) {
00107 putch(delayed_outbuf[i]);
00108 }
00109 delayed_outbuf_pos = 0;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118 static
00119 void
00120 putch_polled(struct con_softc *cs, int ch)
00121 {
00122 cs->cs_sendpolled(cs->cs_devdata, ch);
00123 }
00124
00125 static
00126 void
00127 putch_prepare_polled(struct con_softc *cs)
00128 {
00129 if (cs->cs_startpolling != NULL) {
00130 cs->cs_startpolling(cs->cs_devdata);
00131 }
00132 }
00133
00134 static
00135 void
00136 putch_complete_polled(struct con_softc *cs)
00137 {
00138 if (cs->cs_endpolling != NULL) {
00139 cs->cs_endpolling(cs->cs_devdata);
00140 }
00141 }
00142
00143
00144
00145
00146
00147
00148 static
00149 void
00150 putch_intr(struct con_softc *cs, int ch)
00151 {
00152 P(cs->cs_wsem);
00153 cs->cs_send(cs->cs_devdata, ch);
00154 }
00155
00156
00157
00158
00159 static
00160 int
00161 getch_intr(struct con_softc *cs)
00162 {
00163 unsigned char ret;
00164
00165 P(cs->cs_rsem);
00166 ret = cs->cs_gotchars[cs->cs_gotchars_tail];
00167 cs->cs_gotchars_tail =
00168 (cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
00169 return ret;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 void
00182 con_input(void *vcs, int ch)
00183 {
00184 struct con_softc *cs = vcs;
00185 unsigned nexthead;
00186
00187 nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
00188 if (nexthead == cs->cs_gotchars_tail) {
00189
00190 return;
00191 }
00192
00193 cs->cs_gotchars[cs->cs_gotchars_head] = ch;
00194 cs->cs_gotchars_head = nexthead;
00195
00196 V(cs->cs_rsem);
00197 }
00198
00199
00200
00201
00202 void
00203 con_start(void *vcs)
00204 {
00205 struct con_softc *cs = vcs;
00206
00207 V(cs->cs_wsem);
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 void
00221 putch(int ch)
00222 {
00223 struct con_softc *cs = the_console;
00224
00225 if (cs==NULL) {
00226 putch_delayed(ch);
00227 }
00228 else if (curthread->t_in_interrupt || curthread->t_iplhigh_count > 0) {
00229 putch_polled(cs, ch);
00230 }
00231 else {
00232 putch_intr(cs, ch);
00233 }
00234 }
00235
00236 void
00237 putch_prepare(void)
00238 {
00239 struct con_softc *cs = the_console;
00240
00241 if (cs == NULL) {
00242
00243 }
00244 else if (curthread->t_in_interrupt || curthread->t_iplhigh_count > 0) {
00245 putch_prepare_polled(cs);
00246 }
00247 else {
00248
00249 }
00250 }
00251
00252 void
00253 putch_complete(void)
00254 {
00255 struct con_softc *cs = the_console;
00256
00257 if (cs == NULL) {
00258
00259 }
00260 else if (curthread->t_in_interrupt || curthread->t_iplhigh_count > 0) {
00261 putch_complete_polled(cs);
00262 }
00263 else {
00264
00265 }
00266 }
00267
00268 int
00269 getch(void)
00270 {
00271 struct con_softc *cs = the_console;
00272 KASSERT(cs != NULL);
00273 KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0);
00274
00275 return getch_intr(cs);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284 static
00285 int
00286 con_open(struct device *dev, int openflags)
00287 {
00288 (void)dev;
00289 (void)openflags;
00290 return 0;
00291 }
00292
00293 static
00294 int
00295 con_close(struct device *dev)
00296 {
00297 (void)dev;
00298 return 0;
00299 }
00300
00301 static
00302 int
00303 con_io(struct device *dev, struct uio *uio)
00304 {
00305 int result;
00306 char ch;
00307 struct lock *lk;
00308
00309 (void)dev;
00310
00311 if (uio->uio_rw==UIO_READ) {
00312 lk = con_userlock_read;
00313 }
00314 else {
00315 lk = con_userlock_write;
00316 }
00317
00318 KASSERT(lk != NULL);
00319 lock_acquire(lk);
00320
00321 while (uio->uio_resid > 0) {
00322 if (uio->uio_rw==UIO_READ) {
00323 ch = getch();
00324 if (ch=='\r') {
00325 ch = '\n';
00326 }
00327 result = uiomove(&ch, 1, uio);
00328 if (result) {
00329 lock_release(lk);
00330 return result;
00331 }
00332 if (ch=='\n') {
00333 break;
00334 }
00335 }
00336 else {
00337 result = uiomove(&ch, 1, uio);
00338 if (result) {
00339 lock_release(lk);
00340 return result;
00341 }
00342 if (ch=='\n') {
00343 putch('\r');
00344 }
00345 putch(ch);
00346 }
00347 }
00348 lock_release(lk);
00349 return 0;
00350 }
00351
00352 static
00353 int
00354 con_ioctl(struct device *dev, int op, userptr_t data)
00355 {
00356
00357 (void)dev;
00358 (void)op;
00359 (void)data;
00360 return EINVAL;
00361 }
00362
00363 static
00364 int
00365 attach_console_to_vfs(struct con_softc *cs)
00366 {
00367 struct device *dev;
00368 int result;
00369
00370 dev = kmalloc(sizeof(*dev));
00371 if (dev==NULL) {
00372 return ENOMEM;
00373 }
00374
00375 dev->d_open = con_open;
00376 dev->d_close = con_close;
00377 dev->d_io = con_io;
00378 dev->d_ioctl = con_ioctl;
00379 dev->d_blocks = 0;
00380 dev->d_blocksize = 1;
00381 dev->d_data = cs;
00382
00383 result = vfs_adddev("con", dev, 0);
00384 if (result) {
00385 kfree(dev);
00386 return result;
00387 }
00388
00389 return 0;
00390 }
00391
00392
00393
00394
00395
00396
00397
00398 int
00399 config_con(struct con_softc *cs, int unit)
00400 {
00401 struct semaphore *rsem, *wsem;
00402 struct lock *rlk, *wlk;
00403
00404
00405
00406
00407
00408
00409
00410
00411 if (unit>0) {
00412 KASSERT(the_console!=NULL);
00413 return ENODEV;
00414 }
00415 KASSERT(the_console==NULL);
00416
00417 rsem = sem_create("console read", 0);
00418 if (rsem == NULL) {
00419 return ENOMEM;
00420 }
00421 wsem = sem_create("console write", 1);
00422 if (wsem == NULL) {
00423 sem_destroy(rsem);
00424 return ENOMEM;
00425 }
00426 rlk = lock_create("console-lock-read");
00427 if (rlk == NULL) {
00428 sem_destroy(rsem);
00429 sem_destroy(wsem);
00430 return ENOMEM;
00431 }
00432 wlk = lock_create("console-lock-write");
00433 if (wlk == NULL) {
00434 lock_destroy(rlk);
00435 sem_destroy(rsem);
00436 sem_destroy(wsem);
00437 return ENOMEM;
00438 }
00439
00440 cs->cs_rsem = rsem;
00441 cs->cs_wsem = wsem;
00442 cs->cs_gotchars_head = 0;
00443 cs->cs_gotchars_tail = 0;
00444
00445 the_console = cs;
00446 con_userlock_read = rlk;
00447 con_userlock_write = wlk;
00448
00449 flush_delay_buf();
00450
00451 return attach_console_to_vfs(cs);
00452 }