/* Structures and data needed to register tty driver */ staticstruct tty_driver *sclp_vt220_driver;
staticstruct tty_port sclp_vt220_port;
/* Lock to protect internal data from concurrent access */ static DEFINE_SPINLOCK(sclp_vt220_lock);
/* List of empty pages to be used as write request buffers */ static LIST_HEAD(sclp_vt220_empty);
/* List of pending requests */ static LIST_HEAD(sclp_vt220_outqueue);
/* Flag that output queue is currently running */ staticint sclp_vt220_queue_running;
/* Timer used for delaying write requests to merge subsequent messages into
* a single buffer */ staticstruct timer_list sclp_vt220_timer;
/* Pointer to current request buffer which has been partially filled but not
* yet sent */ staticstruct sclp_vt220_request *sclp_vt220_current_request;
/* Number of characters in current request buffer */ staticint sclp_vt220_buffered_chars;
/* Flag indicating that sclp_vt220_current_request should really *havebeenalreadyqueuedbutwasn'tbecausetheSCLPwasprocessing
* another buffer */ staticint sclp_vt220_flush_later;
do { /* Put buffer back to list of empty buffers */
page = request->sclp_req.sccb;
spin_lock_irqsave(&sclp_vt220_lock, flags); /* Move request from outqueue to empty queue */
list_del(&request->list);
list_add_tail((struct list_head *) page, &sclp_vt220_empty); /* Check if there is a pending buffer on the out queue. */
request = NULL; if (!list_empty(&sclp_vt220_outqueue))
request = list_entry(sclp_vt220_outqueue.next, struct sclp_vt220_request, list); if (!request) {
sclp_vt220_queue_running = 0;
spin_unlock_irqrestore(&sclp_vt220_lock, flags); break;
}
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
} while (__sclp_vt220_emit(request)); if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
tty_port_tty_wakeup(&sclp_vt220_port);
}
if (!sclp_console_drop) return0;
list = sclp_vt220_outqueue.next; if (sclp_vt220_queue_running) /* The first element is in I/O */
list = list->next; if (list == &sclp_vt220_outqueue) return0;
list_del(list);
request = list_entry(list, struct sclp_vt220_request, list);
page = request->sclp_req.sccb;
list_add_tail((struct list_head *) page, &sclp_vt220_empty); return1;
}
/* *Internalimplementationofthewritefunction.WriteCOUNTbytesofdata *frommemoryatBUF *totheSCLPinterface.Incasethatthedatadoesnotfitintothecurrent *writebuffer,emitthecurrentoneandallocateanewone.Ifthereareno *moreemptybuffersavailable,waituntilonegetsemptied.IfDO_SCHEDULE *isnon-zero,thebufferwillbescheduledforemittingafteratimeout- *otherwisetheuserhastoexplicitlycalltheflushfunction. *Anon-zeroCONVERTLFparameterindicatesthat0x0acharactersinthemessage *buffershouldbeconvertedto0x0a0x0d.Aftercompletion,returnthenumber *ofbyteswritten.
*/ staticint
__sclp_vt220_write(constunsignedchar *buf, int count, int do_schedule, int convertlf, int may_fail)
{ unsignedlong flags; void *page; int written; int overall_written;
if (count <= 0) return0;
overall_written = 0;
spin_lock_irqsave(&sclp_vt220_lock, flags); do { /* Create an sclp output buffer if none exists yet */ if (sclp_vt220_current_request == NULL) { if (list_empty(&sclp_vt220_empty))
sclp_console_full++; while (list_empty(&sclp_vt220_empty)) { if (may_fail) goto out; if (sclp_vt220_drop_buffer()) break;
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
sclp_sync_wait();
spin_lock_irqsave(&sclp_vt220_lock, flags);
}
page = (void *) sclp_vt220_empty.next;
list_del((struct list_head *) page);
sclp_vt220_current_request =
sclp_vt220_initialize_page(page);
} /* Try to write the string to the current request buffer */
written = sclp_vt220_add_msg(sclp_vt220_current_request,
buf, count, convertlf);
overall_written += written; if (written == count) break; /* *Notallcharacterscouldbewrittentothecurrent *outputbuffer.Emitthebuffer,createanewbuffer *andthenoutputtherestofthestring.
*/
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
sclp_vt220_emit_current();
spin_lock_irqsave(&sclp_vt220_lock, flags);
buf += written;
count -= written;
} while (count > 0); /* Setup timer to output current console buffer after some time */ if (sclp_vt220_current_request != NULL &&
!timer_pending(&sclp_vt220_timer) && do_schedule) {
sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY;
add_timer(&sclp_vt220_timer);
}
out:
spin_unlock_irqrestore(&sclp_vt220_lock, flags); return overall_written;
}
/* Release memory and unregister from sclp core. Controlled by init counting -
* only the last invoker will actually perform these actions. */ staticvoid __init __sclp_vt220_cleanup(void)
{
sclp_vt220_init_count--; if (sclp_vt220_init_count != 0) return;
sclp_unregister(&sclp_vt220_register);
__sclp_vt220_free_pages();
tty_port_destroy(&sclp_vt220_port);
}
/* Allocate buffer pages and register with sclp core. Controlled by init
* counting - only the first invoker will actually perform these actions. */ staticint __init __sclp_vt220_init(int num_pages)
{ void *page; int i; int rc;
/* Note: we're not testing for CONSOLE_IS_SCLP here to preserve
* symmetry between VM and LPAR systems regarding ttyS1. */
driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); if (IS_ERR(driver)) return PTR_ERR(driver);
rc = __sclp_vt220_init(MAX_KMEM_PAGES); if (rc) goto out_driver;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.