Subversion Repositories HelenOS

Compare Revisions

Regard whitespace Rev 4676 → Rev 4677

/branches/dd/uspace/srv/pci/serial.c
1,7 → 1,19
#include <unistd.h>
#include <ddi.h>
#include <libarch/ddi.h>
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <ipc/serial.h>
#include <ipc/devmap.h>
#include <ipc/ns.h>
#include <bool.h>
#include <errno.h>
#include <async.h>
#include <stdio.h>
#include <futex.h>
#include <assert.h>
#include <adt/list.h>
#include <string.h>
 
#include "isa.h"
#include "serial.h"
9,11 → 21,33
#define NAME "serial"
 
#define REG_COUNT 7
#define COM1 0x3F8
#define COM2 0x2F8
 
static ioport8_t *com1 = 0, *com2 = 0;
#define MAX_NAME_LEN 8
 
struct serial_dev {
link_t link;
char name[MAX_NAME_LEN];
int handle;
bool client_connected;
ioport8_t *port;
void *phys_addr;
bridge_to_isa_t *parent;
};
 
typedef struct serial_dev serial_dev_t;
 
static void * serial_phys_addresses[] = { (void *)0x3F8, (void *)0x2F8 };
static int serial_phys_addr_cnt = sizeof(serial_phys_addresses)/sizeof(void *);
// number, which should be assigned to a newly found serial device - increment first, then assign to the device
static int serial_idx = 0;
 
static int serial_driver_phone = -1;
 
LIST_INITIALIZE(serial_devices_list);
 
static atomic_t serial_futex = FUTEX_INITIALIZER;
 
 
static void serial_init_port(ioport8_t *port);
static void serial_write_8(ioport8_t *port, uint8_t c);
static bool is_transmit_empty(ioport8_t *port);
20,7 → 54,12
static uint8_t serial_read_8(ioport8_t *port);
static bool serial_received(ioport8_t *port);
static void serial_probe(bridge_to_isa_t *parent);
static void * serial_probe_port(void *phys_addr);
static ioport8_t * serial_probe_port(void *phys_addr);
static int serial_device_register(int driver_phone, char *name, int *handle);
static int serial_driver_register(char *name);
static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request);
static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid);
static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall);
 
static isa_drv_ops_t serial_isa_ops = {
.probe = serial_probe
33,8 → 72,14
 
int serial_init()
{
// TODO: register this driver by generic isa bus driver
// register driver by devmapper
serial_driver_phone = serial_driver_register(NAME);
if (serial_driver_phone < 0) {
printf(NAME ": Unable to register driver\n");
return false;
}
// register this driver by generic isa bus driver
isa_register_driver(&serial_isa_drv);
return 1;
}
77,30 → 122,64
pio_write_8(port + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
 
static serial_dev_t * serial_alloc_dev()
{
serial_dev_t *dev = (serial_dev_t *)malloc(sizeof(serial_dev_t));
memset(dev, 0, sizeof(serial_dev_t));
return dev;
}
 
static void serial_init_dev(serial_dev_t *dev, bridge_to_isa_t *parent, int idx)
{
assert(dev != NULL);
memset(dev, 0, sizeof(serial_dev_t));
dev->parent = parent;
dev->phys_addr = dev->parent->ops->absolutize(serial_phys_addresses[idx % serial_phys_addr_cnt]);
snprintf(dev->name, MAX_NAME_LEN, "com%d", idx + 1);
dev->client_connected = false;
}
 
static bool serial_probe_dev(serial_dev_t *dev)
{
assert(dev != NULL);
printf(NAME " driver: probing %s \n", dev->name);
return (dev->port = (ioport8_t *)serial_probe_port(dev->phys_addr)) != NULL;
}
 
static void serial_delete_dev(serial_dev_t *dev) {
free(dev);
}
 
static void serial_probe(bridge_to_isa_t *parent)
{
printf(NAME " driver: probe()\n");
 
printf(NAME " driver: probing com1 \n");
if (com1 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM1))) {
printf(NAME " driver: initializing com1 \n");
serial_init_port(com1);
} else {
printf(NAME " driver: com1 is not present \n");
}
serial_dev_t *dev = serial_alloc_dev();
printf(NAME " driver: probing com2 \n");
if (com2 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM2))) {
printf(NAME " driver: initializing com2 \n");
serial_init_port(com2);
int i;
for (i = 0; i < serial_phys_addr_cnt; i++) {
serial_init_dev(dev, parent, serial_idx);
if (serial_probe_dev(dev)) {
printf(NAME " driver: initializing %s.\n", dev->name);
serial_init_port(dev->port);
if (EOK != serial_device_register(serial_driver_phone, dev->name, &(dev->handle))) {
printf(NAME ": Unable to register device %s\n", dev->name);
}
else {
printf(NAME " driver: com2 is not present \n");
list_append(&(dev->link), &serial_devices_list);
dev = serial_alloc_dev();
} else {
printf(NAME " driver: %s is not present \n", dev->name);
}
serial_idx++;
}
 
serial_delete_dev(dev);
}
 
// returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise
static void * serial_probe_port(void *phys_addr)
static ioport8_t * serial_probe_port(void *phys_addr)
{
ioport8_t *port_addr = NULL;
125,3 → 204,156
return port_addr;
}
 
 
static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request)
{
int c = IPC_GET_ARG1(*request);
serial_write_8(dev->port, (uint8_t)c);
ipc_answer_0(rid, EOK);
}
 
static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid)
{
uint8_t c = serial_read_8(dev->port);
ipc_answer_1(rid, EOK, c);
}
 
static serial_dev_t * serial_handle_to_dev(int handle) {
futex_down(&serial_futex);
link_t *item = serial_devices_list.next;
serial_dev_t *dev = NULL;
while (item != &serial_devices_list) {
dev = list_get_instance(item, serial_dev_t, link);
if (dev->handle == handle) {
futex_up(&serial_futex);
return dev;
}
item = item->next;
}
futex_up(&serial_futex);
return NULL;
}
 
 
/** Handle one connection to the driver.
*
* @param iid Hash of the request that opened the connection.
* @param icall Call data of the request that opened the connection.
*/
static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall)
{
/*
* Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of the device to which the client connected.
*/
int handle = IPC_GET_ARG1(*icall);
serial_dev_t *dev = serial_handle_to_dev(handle);
if (dev == NULL) {
ipc_answer_0(iid, ENOENT);
return;
}
if (dev->client_connected) {
ipc_answer_0(iid, ELIMIT);
return;
}
dev->client_connected = true;
ipc_answer_0(iid, EOK);
while (1) {
ipc_callid_t callid;
ipc_call_t call;
callid = async_get_call(&call);
switch (IPC_GET_METHOD(call)) {
case IPC_M_PHONE_HUNGUP:
/*
* The other side has hung up.
* Answer the message and exit the fibril.
*/
ipc_answer_0(callid, EOK);
dev->client_connected = false;
return;
break;
case SERIAL_GETCHAR:
serial_getchar(dev, callid);
break;
case SERIAL_PUTCHAR:
serial_putchar(dev, callid, &call);
break;
default:
ipc_answer_0(callid, ENOTSUP);
break;
}
}
}
 
 
/**
* Register the driver with the given name and return its newly created phone.
*/
static int serial_driver_register(char *name)
{
ipcarg_t retval;
aid_t req;
ipc_call_t answer;
int phone;
ipcarg_t callback_phonehash;
 
phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
 
while (phone < 0) {
usleep(10000);
phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
DEVMAP_DRIVER, 0);
}
req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
 
retval = ipc_data_write_start(phone, (char *) name, str_length(name) + 1);
 
if (retval != EOK) {
async_wait_for(req, NULL);
return -1;
}
 
async_set_client_connection(serial_client_conn); // set callback function which will serve client connections
 
ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
async_wait_for(req, &retval);
 
return phone;
}
 
static int serial_device_register(int driver_phone, char *name, int *handle)
{
ipcarg_t retval;
aid_t req;
ipc_call_t answer;
 
req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
 
retval = ipc_data_write_start(driver_phone, (char *) name, str_length(name) + 1);
 
if (retval != EOK) {
async_wait_for(req, NULL);
return retval;
}
 
async_wait_for(req, &retval);
 
if (handle != NULL)
*handle = -1;
if (EOK == retval) {
if (NULL != handle)
*handle = (int) IPC_GET_ARG1(answer);
}
return retval;
}
/branches/dd/uspace/srv/pci/main.c
1,5 → 1,6
#include <stdio.h>
#include <stdlib.h>
#include <async.h>
 
#include "intel_piix3.h"
#include "pci.h"
26,8 → 27,11
// pci-to-isa bridge device
intel_piix3_init();
// TODO: write driver of some device (serial port) and initialize it here
// serial port driver
serial_init();
printf("PCI + ISA + serial: Accepting connections\n");
async_manager();
return 0;
}