/* $Id: firm.c,v 1.22 2004/04/01 05:31:12 jmuelmen Exp $ */ /* This code borrows heavily from the Sun mouse/keyboard code by Arnim Laeuger, * sunkbd_hid.c (Copyright (C) 2001, Arnim Laeuger), distributed as part of the * EzHID project. Here is his license. */ /* * $Id: firm.c,v 1.22 2004/04/01 05:31:12 jmuelmen Exp $ * * Copyright (C) 2001, Arnim Laeuger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. See also the file COPYING which * came with this application. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * Credits: * ======== * * + Vojtech Pavlik * For providing a lot of hints about the keyboard protocol in his * Sun keyboard driver (Linux Input Drivers package). * * + Miguel de Icaza and David S. Miller * For the Linux Sun mouse driver which was my only source of knowledge * about Sun's mouse. * */ #define VERBOSE_DEBUG /* no, forget about it for now */ #undef VERBOSE_DEBUG #define TOY_BOARD /* i.e. devasys development board */ /* #undef TOY_BOARD*/ /* real SuRF board */ #include <8051.h> #include "ezusb_reg.h" #include "firm.h" #undef SURF_DRIVER #include "surf_drv.h" #include "i2c.h" #include "surf_mem.h" #include "dac.h" #define V2DAC (i, a, V) \ do { \ float Req = Rdp((i)) * ((V) / Vref - 1); \ float R = Req * Rtset / (Rtset - Req); \ a = (byte)(255 - 256 * (R - Rw((i))) / Rv((i))); \ } while (0) #define DAC2V (i, V, a) \ do { \ float R = Rw((i)) + Rv((i)) * (255 - ((a))) / 256.0; \ float Req = R * Rtset / (R + Rtset); \ V = Vref * (Rdp + Req) / Rdp; \ } while (0) /***************************************************************************** * setup_usb_int() * * Setup the USB interrupts. *****************************************************************************/ #define setup_usb_int() \ { \ /* disable global interrupt */ \ EA = 0; \ \ /* don't pair endpoints */ \ USBPAIR = 0; \ /* clear autovector enable */ \ USBBAV = 0x00; \ /* enable SUDAV and URES interrupts */ \ USBIEN = 0x11; \ \ /* disable IN0 interrupt */ \ IN07IEN = 0x01; \ /* enable OUT0..4 interrupt */ \ OUT07IEN = 0x1f; \ \ /* validate endpoints */ \ IN07VAL = 0x1f; \ OUT07VAL = 0x1f; \ \ /* for (i = 1; i < 5; ++i) */ \ /* OUTBC(i) = 0; */ \ \ /* enable external 2 interrupt */ \ EUSB = 1; \ \ /* enable global interrupt */ \ EA = 1; \ } /***************************************************************************** * setup_timer2_int() * * Setup timer 2 interrupt. *****************************************************************************/ #define setup_timer2_int() \ { \ /* disable timer 2 interrupt */ \ ET2 = 0; \ /* clear timer 2 interrupt */ \ TF2 = 0; \ } #define setup_v_table() \ { \ BUF(0) = (SURF_LOOKUP_ADDR >> 8); \ BUF(1) = (SURF_LOOKUP_ADDR & 0xff); \ if (i2c_write(0x51, _buf, 2) != 2) \ FLASH; \ if (i2c_read(0x51, _vtable, 0x0800) != 0x0800) \ FLASH; \ } /***************************************************************************** * main() * * Main function. * Call initializers, trigger re-enumeration and stay busy in endless loop. * All functionality is handled in the interrupt service routines. *****************************************************************************/ void main() { register unsigned int count; register unsigned char i; /* port A */ PORTACFG = 0x0; /* is a port */ OUTA = 0x0; /* initialized to 0 */ OEA = 0xff; /* and used for output */ /* port B */ PORTBCFG = 0x0; /* is a port */ OUTB = 0x01; /* initialized to 1 (bit 0 is the NRESET line) */ OEB = 0xc9; /* and used partly for input, partly for output */ /* only use port C for the status LED */ PORTCCFG = 0x03; OUTC |= 0x08; /* LED is off to begin with */ OEC |= 0x09; ISOCTL = 0x01; /* no isochronous endpoints */ for (i = 0; i < 4; ++i) { RESISTOR(2 * i) = 0xa6; /* analog supplies at 1.8 V */ } for (i = 0; i < 4; ++i) { RESISTOR(2 * i + 1) = 0x85; /* digital supplies at 2.0 V */ } _firm_regulate = 0xff; for (i = 0; i < 8; ++i) { VOLT(i) = 0; _vtol[i] = 0x40; } /* as far as we know, we're recovering from a power failure. */ /* _power_fail = 1; */ /* fix me: uncomment the line above and comment the line below */ _power_fail = 0; setup_usb_int(); setup_timer2_int(); setup_v_table(); /* disable I2C interrupt */ EIE = 0xe1; /* disable serial interrupts */ ES1 = 0; ES0 = 0; /* init ADCs */ BUF(0) = 0xd2; /* 1101 0010 */ BUF(1) = 0x17; /* 0001 0111 */ if (i2c_write(ADC1ADDR, _buf, 2) != 2) { ERROR(EI2CNACK, ADC1ADDR); } BUF(0) = 0xd2; /* 1101 0010 */ BUF(1) = 0x17; /* 0001 0111 */ if (i2c_write(ADC2ADDR, _buf, 2) != 2) { ERROR(EI2CNACK, ADC2ADDR); } for (i = 0; i < 4; ++i) { /* first write to RDAC 0 */ BUF(0) = 0x00; BUF(1) = 0x10; if (i2c_write(RDACADDR(i), _buf, 2) != 2) { ERROR(EI2CNACK, RDACADDR(i)); } /* then to RDAC 1 */ BUF(0) = 0x80; BUF(1) = 0x10; if (i2c_write(RDACADDR(i), _buf, 2) != 2) { ERROR(EI2CNACK, RDACADDR(i)); } } count = 0xff; while (1) { register int i; #if 0 if (!count--) { FLASH; count = 0xff; } #endif /* don't do anything while we're interlocked */ if (_power_fail) continue; /*************************************************************/ /* write DACs */ /*************************************************************/ for (i = 0; i < 4; ++i) { /* first write to RDAC 0 */ BUF(0) = 0x00; BUF(1) = RESISTOR(2 * i); if (i2c_write(RDACADDR(i), _buf, 2) != 2) { ERROR(EI2CNACK, RDACADDR(i)); } /* then to RDAC 1 */ BUF(0) = 0x80; BUF(1) = RESISTOR(2 * i + 1); if (i2c_write(RDACADDR(i), _buf, 2) != 2) { ERROR(EI2CNACK, RDACADDR(i)); } } /*************************************************************/ /* read ADCs */ /*************************************************************/ if (i2c_read(ADC1ADDR, _buf, 24) != 24) { ERROR(EI2CNACK, ADC1ADDR); } else { EA = 0; for (i = 0; i < 24; ++i) ADC(i) = BUF(i); EA = 1; } if (i2c_read(ADC2ADDR, _buf, 24) != 24) { ERROR(EI2CNACK, ADC2ADDR); } else { EA = 0; for (i = 0; i < 24; ++i) ADC(i + 24) = BUF(i); EA = 1; } /*************************************************************/ /* check if there's adjusting to be done */ /*************************************************************/ for (i = 0; i < 8; ++i) { register signed int v_sense, v_diff; register signed int v_board; EA = 0; /* check if we're supposed to regulate this channel */ if (!(_firm_regulate & (1 << i))) { EA = 1; continue; } /* change this: even i means analog, odd i means digital */ if (i & 1) { v_sense = (signed int)((((unsigned int)(ADCDIGVH((i >> 1) + 1) & 0x0f) << 8) + ADCDIGVL((i >> 1) + 1)) << 1); } else { v_sense = (signed int)((((unsigned int)(ADCANLVH((i >> 1) + 1) & 0x0f) << 8) + ADCANLVL((i >> 1) + 1)) << 1); } v_sense -= (signed int)(((unsigned int)(ADCGNDVH((i >> 1) + 1) & 0x0f) << 8) + ADCGNDVL((i >> 1) + 1)); /* leave channels for which we don't have sense alone! */ if (v_sense < 1024) { EA = 1; continue; } v_diff = v_sense - VOLT(i); if (ABS(v_diff) < (signed int)_vtol[i]) { EA = 1; continue; } /* FLASH; */ v_board = (LOOKUP(RESISTOR(i), i) << 4) + 0x0960; v_board -= v_diff; RESISTOR(i) = rev_lookup(v_board, i); EA = 1; } } }