
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "swis.h"
#include "Global/RISCOS.h"

#include "usbjoystick.h"
#include "joydev.h"
#include "device.h"

#include "buffer.h"


int32_t upcallv_hook_handler(_kernel_swi_regs *r, void *pw)
{
  IGNORE(pw);

  // we only care about data received
  if (r->r[0] != UpCall_DeviceRxDataPresent) {
    return VECTOR_PASSON;
  }

  // temporary buffer for holding received data
  byte buffer[JOY_MAX_DATA_LENGTH];
  os_fw fp = (os_fw) (r->r[1]);

  // test our active sticks to see if this is one of ours
  for (uint32_t i=0; i<JOY_MAX; i++) {
    if (joy_data[i].fp == fp) {
      // this is the stick
      joy_data[i].upcalls++;
      joy_data[i].upcalls_delta++;

      // we need to read the bytes into a buffer
      uint32_t read = 0;
      uint32_t offset = joy_data[i].device->report_data_offset;
      uint32_t to_read = joy_data[i].report_length + offset;
      buffer_read(joy_data[i].buffer_internal_id, to_read, buffer, &read, joy_data[i].buffer_service_routine, joy_data[i].buffer_workspace);

      // if we have read the correct number of bytes, so copy to stick 'last known good data'
      if (read == to_read) {
        joy_data[i].good_reads++;
        joy_data[i].good_reads_delta++;
        memcpy(joy_data[i].data_buf, buffer, read);
        joystick_decode(i);
      }
      else {
        joy_data[i].bad_reads++;
        joy_data[i].bad_reads_delta++;
      }
      // can stop here, since this rx event cannot also be for another stick!
      // todo: is pass-on right?  should we return claim?
      return VECTOR_PASSON;
    }
  }

  // upcall was not for one of our sticks
  return VECTOR_PASSON;
}





_kernel_oserror* buffer_read(buffer_internal_id id, uint32_t to_read, byte *data, uint32_t *read, asm_routine code, void *ws)
{
  if (id == 0)
  {
    *read = 0;
    return NULL;
  }

  // find out the used space (buffer manager 6)
  uint32_t bufused = 0;
  __asm
  {
    MOV      R0,#buffer_SERVICE_USED_SPACE
    MOV      R1,id
    MOV      R12,ws
    BLX      code,{R0,R1,R12},{R2},{LR,PSR}
    MOV      bufused,R2
  }

  // max we can read is the size of the buffer
  if (to_read > bufused)
    to_read = bufused;

  // if the buffer is empty, bail
  if (to_read == 0)
  {
    *read = 0;
    return NULL;
  }

  // perform the read, then flush the buffer
  __asm
  {
    MOV      R0,#buffer_SERVICE_REMOVE_BLOCK
    MOV      R1,id
    MOV      R2,data
    MOV      R3,to_read
    MOV      R12,ws
    BLX      code,{R0-R3,R12},{},{R2,R3,LR,PSR}
    MOV      R0,#buffer_SERVICE_PURGE_BUFFER
    BLX      code,{R0,R1,R12},{},{LR,PSR}
  }

  // note how many bytes read from buffer
  *read = to_read;

  return NULL;
}
