Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 450448d in mainline


Ignore:
Timestamp:
2009-07-11T21:47:46Z (12 years ago)
Author:
Jiri Svoboda <jirik.svoboda@…>
Branches:
lfn, master
Children:
9a61ba5
Parents:
4b2c458c
Message:

Implement data transmission to CUDA, use to enable autopolling. Now the driver works both in PearPC and Qemu -M g3beige.

Location:
kernel/genarch
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • kernel/genarch/include/drivers/via-cuda/cuda.h

    r4b2c458c r450448d  
    9898        cx_listen,
    9999        cx_receive,
    100         cx_rcv_end
     100        cx_rcv_end,
     101        cx_send_start,
     102        cx_send
    101103};
    102104
     
    106108        indev_t *kbrdin;
    107109        uint8_t rcv_buf[CUDA_RCV_BUF_SIZE];
     110        uint8_t snd_buf[CUDA_RCV_BUF_SIZE];
    108111        size_t bidx;
     112        size_t snd_bytes;
    109113        enum cuda_xfer_state xstate;
    110114        SPINLOCK_DECLARE(dev_lock);
  • kernel/genarch/src/drivers/via-cuda/cuda.c

    r4b2c458c r450448d  
    4242#include <synch/spinlock.h>
    4343
    44 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
     44static irq_ownership_t cuda_claim(irq_t *irq);
     45static void cuda_irq_handler(irq_t *irq);
     46
    4547static void cuda_irq_listen(irq_t *irq);
    4648static void cuda_irq_receive(irq_t *irq);
    4749static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len);
     50static void cuda_irq_send_start(irq_t *irq);
     51static void cuda_irq_send(irq_t *irq);
     52
     53static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
     54static void cuda_send_start(cuda_instance_t *instance);
     55static void cuda_autopoll_set(cuda_instance_t *instance, bool enable);
    4856
    4957/** B register fields */
     
    6876};
    6977
    70 #include <print.h>
    71 static irq_ownership_t cuda_claim(irq_t *irq)
    72 {
    73         cuda_instance_t *instance = irq->instance;
    74         cuda_t *dev = instance->cuda;
    75         uint8_t ifr;
    76 
    77         ifr = pio_read_8(&dev->ifr);
    78 
    79         if ((ifr & SR_INT) == 0)
    80                 return IRQ_DECLINE;
    81 
    82         return IRQ_ACCEPT;
    83 }
    84 
    85 static void cuda_irq_handler(irq_t *irq)
    86 {
    87         cuda_instance_t *instance = irq->instance;
    88         uint8_t rbuf[CUDA_RCV_BUF_SIZE];
    89         size_t len;
    90         bool handle;
    91 
    92         handle = false;
    93         len = 0;
    94 
    95         spinlock_lock(&instance->dev_lock);
    96 
    97         /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */
    98         pio_write_8(&instance->cuda->ifr, SR_INT);
    99 
    100         switch (instance->xstate) {
    101         case cx_listen: cuda_irq_listen(irq); break;
    102         case cx_receive: cuda_irq_receive(irq); break;
    103         case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len);
    104             handle = true; break;
    105         }
    106 
    107         spinlock_unlock(&instance->dev_lock);
    108 
    109         /* Handle an incoming packet. */
    110         if (handle)
    111                 cuda_packet_handle(instance, rbuf, len);
    112 }
    113 
    114 /** Interrupt in listen state.
    115  *
    116  * Start packet reception.
    117  */
    118 static void cuda_irq_listen(irq_t *irq)
    119 {
    120         cuda_instance_t *instance = irq->instance;
    121         cuda_t *dev = instance->cuda;
    122         uint8_t b;
    123 
    124         b = pio_read_8(&dev->b);
    125 
    126         if ((b & TREQ) != 0) {
    127                 printf("cuda_irq_listen: no TREQ?!\n");
    128                 return;
    129         }
    130 
    131         pio_read_8(&dev->sr);
    132         pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
    133         instance->xstate = cx_receive;
    134 }
    135 
    136 /** Interrupt in receive state.
    137  *
    138  * Receive next byte of packet.
    139  */
    140 static void cuda_irq_receive(irq_t *irq)
    141 {
    142         cuda_instance_t *instance = irq->instance;
    143         cuda_t *dev = instance->cuda;
    144         uint8_t b, data;
    145 
    146         data = pio_read_8(&dev->sr);
    147         if (instance->bidx < CUDA_RCV_BUF_SIZE)
    148                 instance->rcv_buf[instance->bidx++] = data;
    149 
    150         b = pio_read_8(&dev->b);
    151 
    152         if ((b & TREQ) == 0) {
    153                 pio_write_8(&dev->b, b ^ TACK);
    154         } else {
    155                 pio_write_8(&dev->b, b | TACK | TIP);
    156                 instance->xstate = cx_rcv_end;
    157         }
    158 }
    159 
    160 /** Interrupt in rcv_end state.
    161  *
    162  * Terminate packet reception. Either go back to listen state or start
    163  * receiving another packet if CUDA has one for us.
    164  */
    165 static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len)
    166 {
    167         cuda_instance_t *instance = irq->instance;
    168         cuda_t *dev = instance->cuda;
    169         uint8_t data, b;
    170 
    171         b = pio_read_8(&dev->b);
    172         data = pio_read_8(&dev->sr);
    173 
    174         instance->xstate = cx_listen;
    175 
    176         if ((b & TREQ) == 0) {
    177                 instance->xstate = cx_receive;
    178                 pio_write_8(&dev->b, b & ~TIP);
    179         } else {
    180                 instance->xstate = cx_listen;
    181         }
    182 
    183         memcpy(buf, instance->rcv_buf, instance->bidx);
    184         *len = instance->bidx;
    185         instance->bidx = 0;
    186 }
    187 
    188 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len)
    189 {
    190         if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c
    191                 && data[2] != 0x8c))
    192                 return;
    193 
    194         /* The packet contains one or two scancodes. */
    195         if (data[3] != 0xff)
    196                 indev_push_character(instance->kbrdin, data[3]);               
    197         if (data[4] != 0xff)
    198                 indev_push_character(instance->kbrdin, data[4]);
    199 }
     78/** Packet types */
     79enum {
     80        PT_ADB  = 0x00,
     81        PT_CUDA = 0x01
     82};
     83
     84/** CUDA packet types */
     85enum {
     86        CPT_AUTOPOLL    = 0x01
     87};
    20088
    20189cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg)
     
    20896                instance->xstate = cx_listen;
    20997                instance->bidx = 0;
     98                instance->snd_bytes = 0;
    21099
    211100                spinlock_initialize(&instance->dev_lock, "cuda_dev");
     
    228117}
    229118
     119#include <print.h>
    230120void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
    231121{
     
    241131        pio_write_8(&dev->ier, TIP | TREQ);
    242132        pio_write_8(&dev->ier, IER_SET | SR_INT);
    243 }
     133
     134        /* Enable ADB autopolling. */
     135        cuda_autopoll_set(instance, true);
     136}
     137
     138static irq_ownership_t cuda_claim(irq_t *irq)
     139{
     140        cuda_instance_t *instance = irq->instance;
     141        cuda_t *dev = instance->cuda;
     142        uint8_t ifr;
     143
     144        spinlock_lock(&instance->dev_lock);
     145        ifr = pio_read_8(&dev->ifr);
     146        spinlock_unlock(&instance->dev_lock);
     147
     148        if ((ifr & SR_INT) == 0)
     149                return IRQ_DECLINE;
     150
     151        return IRQ_ACCEPT;
     152}
     153
     154static void cuda_irq_handler(irq_t *irq)
     155{
     156        cuda_instance_t *instance = irq->instance;
     157        uint8_t rbuf[CUDA_RCV_BUF_SIZE];
     158        size_t len;
     159        bool handle;
     160
     161        handle = false;
     162        len = 0;
     163
     164        spinlock_lock(&instance->dev_lock);
     165
     166        /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */
     167        pio_write_8(&instance->cuda->ifr, SR_INT);
     168
     169        switch (instance->xstate) {
     170        case cx_listen: cuda_irq_listen(irq); break;
     171        case cx_receive: cuda_irq_receive(irq); break;
     172        case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len);
     173            handle = true; break;
     174        case cx_send_start: cuda_irq_send_start(irq); break;
     175        case cx_send: cuda_irq_send(irq); break;
     176        }
     177
     178        spinlock_unlock(&instance->dev_lock);
     179
     180        /* Handle an incoming packet. */
     181        if (handle)
     182                cuda_packet_handle(instance, rbuf, len);
     183}
     184
     185/** Interrupt in listen state.
     186 *
     187 * Start packet reception.
     188 */
     189static void cuda_irq_listen(irq_t *irq)
     190{
     191        cuda_instance_t *instance = irq->instance;
     192        cuda_t *dev = instance->cuda;
     193        uint8_t b;
     194
     195        b = pio_read_8(&dev->b);
     196
     197        if ((b & TREQ) != 0) {
     198                printf("cuda_irq_listen: no TREQ?!\n");
     199                return;
     200        }
     201
     202        pio_read_8(&dev->sr);
     203        pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
     204        instance->xstate = cx_receive;
     205}
     206
     207/** Interrupt in receive state.
     208 *
     209 * Receive next byte of packet.
     210 */
     211static void cuda_irq_receive(irq_t *irq)
     212{
     213        cuda_instance_t *instance = irq->instance;
     214        cuda_t *dev = instance->cuda;
     215        uint8_t b, data;
     216
     217        data = pio_read_8(&dev->sr);
     218        if (instance->bidx < CUDA_RCV_BUF_SIZE)
     219                instance->rcv_buf[instance->bidx++] = data;
     220
     221        b = pio_read_8(&dev->b);
     222
     223        if ((b & TREQ) == 0) {
     224                pio_write_8(&dev->b, b ^ TACK);
     225        } else {
     226                pio_write_8(&dev->b, b | TACK | TIP);
     227                instance->xstate = cx_rcv_end;
     228        }
     229}
     230
     231/** Interrupt in rcv_end state.
     232 *
     233 * Terminate packet reception. Either go back to listen state or start
     234 * receiving another packet if CUDA has one for us.
     235 */
     236static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len)
     237{
     238        cuda_instance_t *instance = irq->instance;
     239        cuda_t *dev = instance->cuda;
     240        uint8_t data, b;
     241
     242        b = pio_read_8(&dev->b);
     243        data = pio_read_8(&dev->sr);
     244
     245        if ((b & TREQ) == 0) {
     246                instance->xstate = cx_receive;
     247                pio_write_8(&dev->b, b & ~TIP);
     248        } else {
     249                instance->xstate = cx_listen;
     250                cuda_send_start(instance);
     251        }
     252
     253        memcpy(buf, instance->rcv_buf, instance->bidx);
     254        *len = instance->bidx;
     255        instance->bidx = 0;
     256}
     257
     258/** Interrupt in send_start state.
     259 *
     260 * Process result of sending first byte (and send second on success).
     261 */
     262static void cuda_irq_send_start(irq_t *irq)
     263{
     264        cuda_instance_t *instance = irq->instance;
     265        cuda_t *dev = instance->cuda;
     266        uint8_t b;
     267
     268        b = pio_read_8(&dev->b);
     269
     270        if ((b & TREQ) == 0) {
     271                /* Collision */
     272                pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
     273                pio_read_8(&dev->sr);
     274                pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK);
     275                instance->xstate = cx_listen;
     276                return;
     277        }
     278
     279        pio_write_8(&dev->sr, instance->snd_buf[1]);
     280        pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
     281        instance->bidx = 2;
     282
     283        instance->xstate = cx_send;
     284}
     285
     286/** Interrupt in send state.
     287 *
     288 * Send next byte or terminate transmission.
     289 */
     290static void cuda_irq_send(irq_t *irq)
     291{
     292        cuda_instance_t *instance = irq->instance;
     293        cuda_t *dev = instance->cuda;
     294
     295        if (instance->bidx < instance->snd_bytes) {
     296                /* Send next byte. */
     297                pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]);
     298                pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
     299                return;
     300        }
     301
     302        /* End transfer. */
     303        instance->snd_bytes = 0;
     304        instance->bidx = 0;
     305
     306        pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
     307        pio_read_8(&dev->sr);
     308        pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP);
     309
     310        instance->xstate = cx_listen;
     311        /* TODO: Match reply with request. */
     312}
     313
     314static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len)
     315{
     316        if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c
     317                && data[2] != 0x8c))
     318                return;
     319
     320        /* The packet contains one or two scancodes. */
     321        if (data[3] != 0xff)
     322                indev_push_character(instance->kbrdin, data[3]);               
     323        if (data[4] != 0xff)
     324                indev_push_character(instance->kbrdin, data[4]);
     325}
     326
     327static void cuda_autopoll_set(cuda_instance_t *instance, bool enable)
     328{
     329        instance->snd_buf[0] = PT_CUDA;
     330        instance->snd_buf[1] = CPT_AUTOPOLL;
     331        instance->snd_buf[2] = enable ? 0x01 : 0x00;
     332        instance->snd_bytes = 3;
     333        instance->bidx = 0;
     334
     335        cuda_send_start(instance);
     336}
     337
     338static void cuda_send_start(cuda_instance_t *instance)
     339{
     340        cuda_t *dev = instance->cuda;
     341
     342        ASSERT(instance->xstate == cx_listen);
     343
     344        if (instance->snd_bytes == 0)
     345                return;
     346
     347        /* Check for incoming data. */
     348        if ((pio_read_8(&dev->b) & TREQ) == 0)
     349                return;
     350
     351        pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT);
     352        pio_write_8(&dev->sr, instance->snd_buf[0]);
     353        pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
     354
     355        instance->xstate = cx_send_start;
     356}
     357
    244358
    245359/** @}
Note: See TracChangeset for help on using the changeset viewer.