X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fserial.c;h=d6bdc2d7309fb3da9422ea05392a017f87fa5cf7;hb=8a3dbb70c29175bad79764a0b2f3961b98138bb2;hp=e7f11dabc9d677c8931542cc0df31651b12dedbd;hpb=d3ba44fb64c5a40a0d47cf8fecf809b8c20fd440;p=palacios.git diff --git a/palacios/src/devices/serial.c b/palacios/src/devices/serial.c index e7f11da..d6bdc2d 100644 --- a/palacios/src/devices/serial.c +++ b/palacios/src/devices/serial.c @@ -12,6 +12,7 @@ * All rights reserved. * * Author: Rumou Duan + * Lei Xia * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". @@ -25,9 +26,16 @@ #include #include #include -#include #include +#include + + +#ifndef V3_CONFIG_DEBUG_SERIAL +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + #define COM1_DATA_PORT 0x3f8 #define COM1_IRQ_ENABLE_PORT 0x3f9 @@ -250,7 +258,7 @@ struct dll_register { struct dlm_register { uint8_t data; }; -#define SERIAL_BUF_LEN 16 +#define SERIAL_BUF_LEN 128 struct serial_buffer { int head; // most recent data @@ -277,27 +285,30 @@ struct serial_port { struct serial_buffer tx_buffer; struct serial_buffer rx_buffer; uint_t irq_number; + + + void * backend_data; + struct v3_dev_char_ops * ops; + }; struct serial_state { - struct serial_port com1; - struct serial_port com2; - struct serial_port com3; - struct serial_port com4; + struct serial_port coms[4]; + }; static struct serial_port * get_com_from_port(struct serial_state * serial, uint16_t port) { if ((port >= COM1_DATA_PORT) && (port <= COM1_SCRATCH_PORT)) { - return &(serial->com1); + return &(serial->coms[0]); } else if ((port >= COM2_DATA_PORT) && (port <= COM2_SCRATCH_PORT)) { - return &(serial->com2); + return &(serial->coms[1]); } else if ((port >= COM3_DATA_PORT) && (port <= COM3_SCRATCH_PORT)) { - return &(serial->com3); + return &(serial->coms[2]); } else if ((port >= COM4_DATA_PORT) && (port <= COM4_SCRATCH_PORT)) { - return &(serial->com4); + return &(serial->coms[3]); } else { PrintError("Error: Could not find serial port associated with IO port %d\n", port); return NULL; @@ -332,15 +343,15 @@ static int getNumber(struct serial_buffer * buf) { } } -static int updateIRQ(struct serial_port * com, struct vm_device * dev) { +static int updateIRQ(struct v3_vm_info * vm, struct serial_port * com) { if ( (com->ier.erbfi == 0x1) && (receive_buffer_trigger( getNumber(&(com->rx_buffer)), com->fcr.rx_trigger)) ) { - PrintDebug("UART: receive buffer interrupt(trigger level reached)"); + PrintDebug("UART: receive buffer interrupt(trigger level reached)\n"); com->iir.iid = RX_IRQ_TRIGGER_LEVEL; - v3_raise_irq(dev->vm, com->irq_number); + v3_raise_irq(vm, com->irq_number); } if ( (com->iir.iid == RX_IRQ_TRIGGER_LEVEL) && @@ -359,21 +370,20 @@ static int updateIRQ(struct serial_port * com, struct vm_device * dev) { } else if ( (com->ier.etbei == 0x1) && (getNumber(&(com->tx_buffer)) != SERIAL_BUF_LEN )) { - PrintDebug("UART: transmit buffer interrupt(buffer not full)"); + PrintDebug("UART: transmit buffer interrupt(buffer not full)\n"); com->iir.iid = TX_IRQ_THRE; com->iir.pending = 0; - v3_raise_irq(dev->vm, com->irq_number); + v3_raise_irq(vm, com->irq_number); } return 1; } -static int queue_data(struct serial_buffer * buf, uint8_t data, - struct serial_port * com, struct vm_device * dev) { - +static int queue_data(struct v3_vm_info * vm, struct serial_port * com, + struct serial_buffer * buf, uint8_t data) { int next_loc = (buf->head + 1) % SERIAL_BUF_LEN; if (buf->full == 1) { @@ -383,6 +393,8 @@ static int queue_data(struct serial_buffer * buf, uint8_t data, com->lsr.oe = 1; //overrun error bit set } + updateIRQ(vm, com); + return 0; } @@ -401,14 +413,12 @@ static int queue_data(struct serial_buffer * buf, uint8_t data, com->lsr.thre = 0; //reset thre and temt bits. com->lsr.temt = 0; } - - updateIRQ(com, dev); - + return 0; } -static int dequeue_data(struct serial_buffer * buf, uint8_t * data, - struct serial_port * com, struct vm_device * dev) { +static int dequeue_data(struct v3_vm_info * vm, struct serial_port * com, + struct serial_buffer * buf, uint8_t * data) { int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN; @@ -436,34 +446,21 @@ static int dequeue_data(struct serial_buffer * buf, uint8_t * data, com->lsr.temt = 1; } - updateIRQ(com, dev); + updateIRQ(vm, com); return 0; } -/* -static void printBuffer(struct serial_buffer * buf) { - int i = 0; - - for (i = 0; i < SERIAL_BUF_LEN; i++) { - PrintDebug(" %d ", buf->buffer[i]); - } - - PrintDebug("\n the number of elements is %d \n", getNumber(buf)); -} -*/ - -//note: write to data port is NOT implemented and corresponding codes are commented out static int write_data_port(struct guest_info * core, uint16_t port, - void * src, uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + void * src, uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t * val = (uint8_t *)src; struct serial_port * com_port = NULL; PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *val); if (length != 1) { - PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port); + PrintError("Invalid length(%d) in write to 0x%x\n", length, port); return -1; } @@ -476,7 +473,7 @@ static int write_data_port(struct guest_info * core, uint16_t port, com_port = get_com_from_port(state, port); if (com_port == NULL) { - PrintDebug("UART:read from NOBODY"); + PrintError("UART:read from NOBODY\n"); return -1; } @@ -485,25 +482,32 @@ static int write_data_port(struct guest_info * core, uint16_t port, if (com_port->lcr.dlab == 1) { com_port->dll.data = *val; } else { - queue_data(&(com_port->tx_buffer), *val, com_port, dev); + + + /* JRL: Some buffering would probably be a good idea here.... */ + if (com_port->ops) { + com_port->ops->output(val, 1, com_port->backend_data); + } else { + queue_data(core->vm_info, com_port, &(com_port->tx_buffer), *val); + updateIRQ(core->vm_info, com_port); + } } - return length; } static int read_data_port(struct guest_info * core, uint16_t port, - void * dst, uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + void * dst, uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t * val = (uint8_t *)dst; struct serial_port * com_port = NULL; PrintDebug("Read from Data Port 0x%x\n", port); if (length != 1) { - PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port); + PrintError("Invalid length(%d) in write to 0x%x\n", length, port); return -1; } @@ -516,16 +520,16 @@ static int read_data_port(struct guest_info * core, uint16_t port, com_port = get_com_from_port(state, port); if (com_port == NULL) { - PrintDebug("UART:read from NOBODY"); + PrintError("UART:read from NOBODY\n"); return -1; } if (com_port->lcr.dlab == 1) { *val = com_port->dll.data; } else { - dequeue_data(&(com_port->rx_buffer), val, com_port, dev); - } - + dequeue_data(core->vm_info, com_port, &(com_port->rx_buffer), val); + } + return length; } @@ -578,15 +582,15 @@ static int handle_fcr_write(struct serial_port * com, uint8_t value) { static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, - uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t val = *(uint8_t *)src; struct serial_port * com_port = NULL; PrintDebug("UART:Write to Control Port (val=%x)\n", val); if (length != 1) { - PrintDebug("UART:Invalid Write length to control port%d\n", port); + PrintError("UART:Invalid Write length to control port%d\n", port); return -1; } @@ -617,7 +621,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, case COM2_FIFO_CTRL_PORT: case COM3_FIFO_CTRL_PORT: case COM4_FIFO_CTRL_PORT: { - PrintDebug("UART:Write to FCR"); + PrintDebug("UART:Write to FCR\n"); if (handle_fcr_write(com_port, val) == -1) { return -1; @@ -629,7 +633,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, case COM2_LINE_CTRL_PORT: case COM3_LINE_CTRL_PORT: case COM4_LINE_CTRL_PORT: { - PrintDebug("UART:Write to LCR"); + PrintDebug("UART:Write to LCR\n"); com_port->lcr.val = val; break; } @@ -637,7 +641,7 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, case COM2_MODEM_CTRL_PORT: case COM3_MODEM_CTRL_PORT: case COM4_MODEM_CTRL_PORT: { - PrintDebug("UART:Write to MCR"); + PrintDebug("UART:Write to MCR\n"); com_port->mcr.val = val; break; } @@ -645,12 +649,12 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, case COM2_SCRATCH_PORT: case COM3_SCRATCH_PORT: case COM4_SCRATCH_PORT: { - PrintDebug("UART:Write to SCRATCH"); + PrintDebug("UART:Write to SCRATCH\n"); com_port->scr.data = val; break; } default: - PrintDebug("UART:Write to NOBODY, ERROR"); + PrintError("UART:Write to NOBODY, ERROR\n"); return -1; } @@ -662,15 +666,15 @@ static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, - uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t * val = (uint8_t *)dst; struct serial_port * com_port = NULL; PrintDebug("Read from Control Port\n"); if (length != 1) { - PrintDebug("Invalid Read length to control port\n"); + PrintError("Invalid Read length to control port\n"); return -1; } @@ -687,7 +691,7 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, case COM2_IRQ_ENABLE_PORT: case COM3_IRQ_ENABLE_PORT: case COM4_IRQ_ENABLE_PORT: { - PrintDebug("UART:read from IER"); + PrintDebug("UART:read from IER\n"); if (com_port->lcr.dlab == 1) { *val = com_port->dlm.data; @@ -697,19 +701,19 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, break; } - case COM1_FIFO_CTRL_PORT: - case COM2_FIFO_CTRL_PORT: - case COM3_FIFO_CTRL_PORT: - case COM4_FIFO_CTRL_PORT: - PrintDebug("UART:read from FCR"); - *val = com_port->fcr.val; + case COM1_IIR_PORT: + case COM2_IIR_PORT: + case COM3_IIR_PORT: + case COM4_IIR_PORT: + PrintDebug("UART:read from IIR\n"); + *val = com_port->iir.val; break; case COM1_LINE_CTRL_PORT: case COM2_LINE_CTRL_PORT: case COM3_LINE_CTRL_PORT: case COM4_LINE_CTRL_PORT: - PrintDebug("UART:read from LCR"); + PrintDebug("UART:read from LCR\n"); *val = com_port->lcr.val; break; @@ -717,7 +721,7 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, case COM2_MODEM_CTRL_PORT: case COM3_MODEM_CTRL_PORT: case COM4_MODEM_CTRL_PORT: - PrintDebug("UART:read from MCR"); + PrintDebug("UART:read from MCR\n"); *val = com_port->mcr.val; break; @@ -725,12 +729,12 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, case COM2_SCRATCH_PORT: case COM3_SCRATCH_PORT: case COM4_SCRATCH_PORT: - PrintDebug("UART:read from SCRATCH"); + PrintDebug("UART:read from SCRATCH\n"); *val = com_port->scr.data; break; default: - PrintDebug("UART:read from NOBODY"); + PrintError("UART:read from NOBODY\n"); return -1; } @@ -739,15 +743,15 @@ static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, static int write_status_port(struct guest_info * core, uint16_t port, void * src, - uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t val = *(uint8_t *)src; struct serial_port * com_port = NULL; PrintDebug("Write to Status Port (val=%x)\n", val); if (length != 1) { - PrintDebug("Invalid Write length to status port %d\n", port); + PrintError("Invalid Write length to status port %d\n", port); return -1; } @@ -763,7 +767,7 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src case COM2_LINE_STATUS_PORT: case COM3_LINE_STATUS_PORT: case COM4_LINE_STATUS_PORT: - PrintDebug("UART:write to LSR"); + PrintDebug("UART:write to LSR\n"); com_port->lsr.val = val; break; @@ -771,12 +775,12 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src case COM2_MODEM_STATUS_PORT: case COM3_MODEM_STATUS_PORT: case COM4_MODEM_STATUS_PORT: - PrintDebug("UART:write to MSR"); + PrintDebug("UART:write to MSR\n"); com_port->msr.val = val; break; default: - PrintDebug("UART:write to NOBODY"); + PrintError("UART:write to NOBODY\n"); return -1; } @@ -784,18 +788,13 @@ static int write_status_port(struct guest_info * core, uint16_t port, void * src } static int read_status_port(struct guest_info * core, uint16_t port, void * dst, - uint_t length, struct vm_device * dev) { - struct serial_state * state = (struct serial_state *)dev->private_data; + uint_t length, void * priv_data) { + struct serial_state * state = priv_data; uint8_t * val = (uint8_t *)dst; struct serial_port * com_port = NULL; PrintDebug("Read from Status Port 0x%x\n", port); - if (length != 1) { - PrintDebug("Invalid Read length to control port\n"); - return -1; - } - com_port = get_com_from_port(state, port); if (com_port == NULL) { @@ -808,7 +807,13 @@ static int read_status_port(struct guest_info * core, uint16_t port, void * dst, case COM2_LINE_STATUS_PORT: case COM3_LINE_STATUS_PORT: case COM4_LINE_STATUS_PORT: - PrintDebug("UART:read from LSR"); + + if (length != 1) { + PrintError("Invalid Read length to control port\n"); + return -1; + } + + PrintDebug("UART:read from LSR\n"); *val = com_port->lsr.val; com_port->lsr.oe = 0; // Why do we clear this?? @@ -819,57 +824,38 @@ static int read_status_port(struct guest_info * core, uint16_t port, void * dst, case COM2_MODEM_STATUS_PORT: case COM3_MODEM_STATUS_PORT: case COM4_MODEM_STATUS_PORT: - PrintDebug("UART:read from COM4 MSR"); + PrintDebug("UART:read from COM4 MSR (length = %d)\n", length); + + if (length > 2) { + PrintError("Invalid Read length to MSR port\n"); + return -1; + } + + if (length == 2) { + /* Windows XP expects to be able to read this register and the next in one go */ + + if (read_ctrl_port(core, port + 1, val + 1, 1, priv_data) < 0) { + PrintError("Error reading control port for word size read of Status register\n"); + return -1; + } + } + + // always read low byte... + *val = com_port->msr.val; break; default: - PrintDebug("UART:read from NOBODY"); + PrintError("UART:read from NOBODY (length = %d)\n", length); return -1; } return length; } -static int serial_deinit(struct vm_device * dev) { - - - v3_dev_unhook_io(dev, COM1_DATA_PORT); - v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT); - v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT); - v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT); - v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT); - v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT); - v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT); - v3_dev_unhook_io(dev, COM1_SCRATCH_PORT); - - v3_dev_unhook_io(dev, COM2_DATA_PORT); - v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT); - v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT); - v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT); - v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT); - v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT); - v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT); - v3_dev_unhook_io(dev, COM2_SCRATCH_PORT); - - v3_dev_unhook_io(dev, COM3_DATA_PORT); - v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT); - v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT); - v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT); - v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT); - v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT); - v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT); - v3_dev_unhook_io(dev, COM3_SCRATCH_PORT); - - v3_dev_unhook_io(dev, COM4_DATA_PORT); - v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT); - v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT); - v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT); - v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT); - v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT); - v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT); - v3_dev_unhook_io(dev, COM4_SCRATCH_PORT); +static int serial_free(struct serial_state * state) { + V3_Free(state); return 0; } @@ -877,11 +863,7 @@ static int serial_deinit(struct vm_device * dev) { static struct v3_device_ops dev_ops = { - //.init = serial_init, - .free = serial_deinit, - .reset = NULL, - .start = NULL, - .stop = NULL, + .free = (int (*)(void *))serial_free, }; @@ -909,70 +891,154 @@ static int init_serial_port(struct serial_port * com) { com->rx_buffer.full = 0; memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN); + com->ops = NULL; + com->backend_data = NULL; + + return 0; +} + +static uint64_t serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * priv_data){ + struct serial_port * com_port = (struct serial_port *)priv_data; + int i; + + for(i = 0; i < len; i++){ + queue_data(vm, com_port, &(com_port->rx_buffer), buf[i]); + } + + updateIRQ(vm, com_port); + + return len; +} + + +static int connect_fn(struct v3_vm_info * vm, + void * frontend_data, + struct v3_dev_char_ops * ops, + v3_cfg_tree_t * cfg, + void * private_data, + void ** push_fn_arg) { + + struct serial_state * serial = (struct serial_state *)frontend_data; + struct serial_port * com = NULL; + char * com_port = v3_cfg_val(cfg, "com_port"); + int com_idx = 0; + + if (com_port == NULL) { + PrintError("Invalid Serial frontend config: missing \"com_port\"\n"); + return -1; + } + + com_idx = atoi(com_port) - 1; + + if ((com_idx > 3) || (com_idx < 0)) { + PrintError("Invalid Com port (%s) \n", com_port); + return -1; + } + + com = &(serial->coms[com_idx]); + + com->ops = ops; + com->backend_data = private_data; + + com->ops->input = serial_input; + *push_fn_arg = com; + return 0; } static int serial_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { - struct serial_state * state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state)); - char * name = v3_cfg_val(cfg, "name"); + struct serial_state * state = NULL; + char * dev_id = v3_cfg_val(cfg, "ID"); + int ret = 0; - PrintDebug("UART: init_device\n"); - init_serial_port(&(state->com1)); - init_serial_port(&(state->com2)); - init_serial_port(&(state->com3)); - init_serial_port(&(state->com4)); + state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state)); + + if (state == NULL) { + PrintError("Could not allocate Serial Device\n"); + return -1; + } + + memset(state, 0, sizeof(struct serial_state)); + + init_serial_port(&(state->coms[0])); + init_serial_port(&(state->coms[1])); + init_serial_port(&(state->coms[2])); + init_serial_port(&(state->coms[3])); - state->com1.irq_number = COM1_IRQ; - state->com2.irq_number = COM2_IRQ; - state->com3.irq_number = COM3_IRQ; - state->com4.irq_number = COM4_IRQ; + state->coms[0].irq_number = COM1_IRQ; + state->coms[1].irq_number = COM2_IRQ; + state->coms[2].irq_number = COM3_IRQ; + state->coms[3].irq_number = COM4_IRQ; - struct vm_device * dev = v3_allocate_device(name, &dev_ops, state); + struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state); - if (v3_attach_device(vm, dev) == -1) { - PrintError("Could not attach device %s\n", name); + if (dev == NULL) { + PrintError("Could not attach device %s\n", dev_id); + V3_Free(state); + return -1; + } + + PrintDebug("Serial device attached\n"); + + ret |= v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port); + ret |= v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); + + ret |= v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port); + ret |= v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); + + ret |= v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port); + ret |= v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); + + ret |= v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port); + ret |= v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); + ret |= v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port); + ret |= v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); + + if (ret != 0) { + PrintError("Error hooking Serial IO ports\n"); + v3_remove_device(dev); + return -1; + } + + PrintDebug("Serial ports hooked\n"); + + + + if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)state) == -1) { + PrintError("Could not register %s as frontend\n", dev_id); + v3_remove_device(dev); return -1; } - v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port); - v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); - - v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port); - v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); - - v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port); - v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); - - v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port); - v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port); - v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port); - v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port); return 0; } + + + device_register("SERIAL", serial_init)