HelenOS sources
This source file includes following definitions.
- cuda_init
- cuda_wire
- cuda_claim
- cuda_irq_handler
- cuda_irq_listen
- cuda_irq_receive
- cuda_irq_rcv_end
- cuda_irq_send_start
- cuda_irq_send
- cuda_packet_handle
- cuda_autopoll_set
- cuda_send_start
#include <assert.h>
#include <genarch/drivers/via-cuda/cuda.h>
#include <console/chardev.h>
#include <ddi/irq.h>
#include <arch/asm.h>
#include <stdlib.h>
#include <synch/spinlock.h>
#include <memw.h>
static irq_ownership_t cuda_claim(irq_t *irq);
static void cuda_irq_handler(irq_t *irq);
static void cuda_irq_listen(irq_t *irq);
static void cuda_irq_receive(irq_t *irq);
static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len);
static void cuda_irq_send_start(irq_t *irq);
static void cuda_irq_send(irq_t *irq);
static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
static void cuda_send_start(cuda_instance_t *instance);
static void cuda_autopoll_set(cuda_instance_t *instance, bool enable);
enum {
TREQ = 0x08,
TACK = 0x10,
TIP = 0x20
};
enum {
IER_CLR = 0x00,
IER_SET = 0x80,
SR_INT = 0x04,
ALL_INT = 0x7f
};
enum {
SR_OUT = 0x10
};
enum {
PT_ADB = 0x00,
PT_CUDA = 0x01
};
enum {
CPT_AUTOPOLL = 0x01
};
cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg)
{
cuda_instance_t *instance =
malloc(sizeof(cuda_instance_t));
if (instance) {
instance->cuda = dev;
instance->kbrdin = NULL;
instance->xstate = cx_listen;
instance->bidx = 0;
instance->snd_bytes = 0;
spinlock_initialize(&instance->dev_lock, "cuda.instance.dev_lock");
pio_write_8(&dev->ier, IER_CLR | ALL_INT);
irq_initialize(&instance->irq);
instance->irq.inr = inr;
instance->irq.claim = cuda_claim;
instance->irq.handler = cuda_irq_handler;
instance->irq.instance = instance;
instance->irq.cir = cir;
instance->irq.cir_arg = cir_arg;
instance->irq.preack = true;
}
return instance;
}
#include <log.h>
void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
{
cuda_t *dev = instance->cuda;
assert(instance);
assert(kbrdin);
instance->kbrdin = kbrdin;
irq_register(&instance->irq);
pio_write_8(&dev->ier, TIP | TREQ);
pio_write_8(&dev->ier, IER_SET | SR_INT);
cuda_autopoll_set(instance, true);
}
static irq_ownership_t cuda_claim(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
uint8_t ifr;
spinlock_lock(&instance->dev_lock);
ifr = pio_read_8(&dev->ifr);
spinlock_unlock(&instance->dev_lock);
if ((ifr & SR_INT) == 0)
return IRQ_DECLINE;
return IRQ_ACCEPT;
}
static void cuda_irq_handler(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
uint8_t rbuf[CUDA_RCV_BUF_SIZE];
size_t len;
bool handle;
handle = false;
len = 0;
spinlock_lock(&instance->dev_lock);
pio_write_8(&instance->cuda->ifr, SR_INT);
switch (instance->xstate) {
case cx_listen:
cuda_irq_listen(irq);
break;
case cx_receive:
cuda_irq_receive(irq);
break;
case cx_rcv_end:
cuda_irq_rcv_end(irq, rbuf, &len);
handle = true;
break;
case cx_send_start:
cuda_irq_send_start(irq);
break;
case cx_send:
cuda_irq_send(irq);
break;
}
spinlock_unlock(&instance->dev_lock);
if (handle)
cuda_packet_handle(instance, rbuf, len);
}
static void cuda_irq_listen(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
uint8_t b;
b = pio_read_8(&dev->b);
if ((b & TREQ) != 0) {
log(LF_OTHER, LVL_ERROR, "cuda_irq_listen: no TREQ?!");
return;
}
pio_read_8(&dev->sr);
pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
instance->xstate = cx_receive;
}
static void cuda_irq_receive(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
uint8_t b, data;
data = pio_read_8(&dev->sr);
if (instance->bidx < CUDA_RCV_BUF_SIZE)
instance->rcv_buf[instance->bidx++] = data;
b = pio_read_8(&dev->b);
if ((b & TREQ) == 0) {
pio_write_8(&dev->b, b ^ TACK);
} else {
pio_write_8(&dev->b, b | TACK | TIP);
instance->xstate = cx_rcv_end;
}
}
static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
uint8_t b;
b = pio_read_8(&dev->b);
pio_read_8(&dev->sr);
if ((b & TREQ) == 0) {
instance->xstate = cx_receive;
pio_write_8(&dev->b, b & ~TIP);
} else {
instance->xstate = cx_listen;
cuda_send_start(instance);
}
memcpy(buf, instance->rcv_buf, instance->bidx);
*len = instance->bidx;
instance->bidx = 0;
}
static void cuda_irq_send_start(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
uint8_t b;
b = pio_read_8(&dev->b);
if ((b & TREQ) == 0) {
pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
pio_read_8(&dev->sr);
pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK);
instance->xstate = cx_listen;
return;
}
pio_write_8(&dev->sr, instance->snd_buf[1]);
pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
instance->bidx = 2;
instance->xstate = cx_send;
}
static void cuda_irq_send(irq_t *irq)
{
cuda_instance_t *instance = irq->instance;
cuda_t *dev = instance->cuda;
if (instance->bidx < instance->snd_bytes) {
pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]);
pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
return;
}
instance->snd_bytes = 0;
instance->bidx = 0;
pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
pio_read_8(&dev->sr);
pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP);
instance->xstate = cx_listen;
}
static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len)
{
if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c &&
data[2] != 0x8c))
return;
if (data[3] != 0xff)
indev_push_character(instance->kbrdin, data[3]);
if (data[4] != 0xff)
indev_push_character(instance->kbrdin, data[4]);
}
static void cuda_autopoll_set(cuda_instance_t *instance, bool enable)
{
instance->snd_buf[0] = PT_CUDA;
instance->snd_buf[1] = CPT_AUTOPOLL;
instance->snd_buf[2] = enable ? 0x01 : 0x00;
instance->snd_bytes = 3;
instance->bidx = 0;
cuda_send_start(instance);
}
static void cuda_send_start(cuda_instance_t *instance)
{
cuda_t *dev = instance->cuda;
assert(instance->xstate == cx_listen);
if (instance->snd_bytes == 0)
return;
if ((pio_read_8(&dev->b) & TREQ) == 0)
return;
pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT);
pio_write_8(&dev->sr, instance->snd_buf[0]);
pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
instance->xstate = cx_send_start;
}
HelenOS homepage, sources at GitHub