Subversion Repositories HelenOS

Rev

Rev 4327 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Martin Decky
  3.  * Copyright (c) 2009 Jiri Svoboda
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. /** @addtogroup genarch
  31.  * @{
  32.  */
  33. /** @file
  34.  */
  35.  
  36. #include <genarch/drivers/via-cuda/cuda.h>
  37. #include <console/chardev.h>
  38. #include <ddi/irq.h>
  39. #include <arch/asm.h>
  40. #include <mm/slab.h>
  41. #include <ddi/device.h>
  42. #include <synch/spinlock.h>
  43.  
  44. static irq_ownership_t cuda_claim(irq_t *irq);
  45. static void cuda_irq_handler(irq_t *irq);
  46.  
  47. static void cuda_irq_listen(irq_t *irq);
  48. static void cuda_irq_receive(irq_t *irq);
  49. static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len);
  50. static void cuda_irq_send_start(irq_t *irq);
  51. static void cuda_irq_send(irq_t *irq);
  52.  
  53. static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
  54. static void cuda_send_start(cuda_instance_t *instance);
  55. static void cuda_autopoll_set(cuda_instance_t *instance, bool enable);
  56.  
  57. /** B register fields */
  58. enum {
  59.     TREQ    = 0x08,
  60.     TACK    = 0x10,
  61.     TIP = 0x20
  62. };
  63.  
  64. /** IER register fields */
  65. enum {
  66.     IER_CLR = 0x00,
  67.     IER_SET = 0x80,
  68.  
  69.     SR_INT  = 0x04,
  70.     ALL_INT = 0x7f
  71. };
  72.  
  73. /** ACR register fields */
  74. enum {
  75.     SR_OUT  = 0x10
  76. };
  77.  
  78. /** Packet types */
  79. enum {
  80.     PT_ADB  = 0x00,
  81.     PT_CUDA = 0x01
  82. };
  83.  
  84. /** CUDA packet types */
  85. enum {
  86.     CPT_AUTOPOLL    = 0x01
  87. };
  88.  
  89. cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg)
  90. {
  91.     cuda_instance_t *instance
  92.         = malloc(sizeof(cuda_instance_t), FRAME_ATOMIC);
  93.     if (instance) {
  94.         instance->cuda = dev;
  95.         instance->kbrdin = NULL;
  96.         instance->xstate = cx_listen;
  97.         instance->bidx = 0;
  98.         instance->snd_bytes = 0;
  99.  
  100.         spinlock_initialize(&instance->dev_lock, "cuda_dev");
  101.  
  102.         /* Disable all interrupts from CUDA. */
  103.         pio_write_8(&dev->ier, IER_CLR | ALL_INT);
  104.  
  105.         irq_initialize(&instance->irq);
  106.         instance->irq.devno = device_assign_devno();
  107.         instance->irq.inr = inr;
  108.         instance->irq.claim = cuda_claim;
  109.         instance->irq.handler = cuda_irq_handler;
  110.         instance->irq.instance = instance;
  111.         instance->irq.cir = cir;
  112.         instance->irq.cir_arg = cir_arg;
  113.         instance->irq.preack = true;
  114.     }
  115.    
  116.     return instance;
  117. }
  118.  
  119. #include <print.h>
  120. void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
  121. {
  122.     cuda_t *dev = instance->cuda;
  123.  
  124.     ASSERT(instance);
  125.     ASSERT(kbrdin);
  126.  
  127.     instance->kbrdin = kbrdin;
  128.     irq_register(&instance->irq);
  129.  
  130.     /* Enable SR interrupt. */
  131.     pio_write_8(&dev->ier, TIP | TREQ);
  132.     pio_write_8(&dev->ier, IER_SET | SR_INT);
  133.  
  134.     /* Enable ADB autopolling. */
  135.     cuda_autopoll_set(instance, true);
  136. }
  137.  
  138. static 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.  
  154. static 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.  */
  189. static 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.  */
  211. static 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.  */
  236. static 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.  */
  262. static 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.  */
  290. static 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.  
  314. static 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.  
  327. static 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.  
  338. static 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.  
  358.  
  359. /** @}
  360.  */
  361.