/*
Firmware for a Macintosh display adapter connected over USB
Copyright (C) 2010 Jeroen Domburg
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 3 of the License, or
(at your option) any later version.
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, see .
*/
//Implement a simple USB interface thingy which can receive bulk packets.
//No interrupts are used because of timing issues in the main code.
#include "lpc134x.h"
#include
#define NOP() __asm volatile ("NOP")
#define PACKED __attribute__((__packed__))
//Comment out to get debugging stuff on the monitor.
#define printf(bla, ...) {}
extern void gpioSet(int gpio, int val);
typedef struct {
unsigned char bmRequestType;
unsigned char bRequest;
unsigned short wValue;
unsigned short wIndex;
unsigned short wLength;
} PACKED setupPacketTp;
//Descriptor ref:
//http://www.usbmadesimple.co.uk/ums_4.htm
char myDevDescriptor[]={
18, //length (18?)
1, //descriptor type
0x02,0x00, //usb ver
0xff, //class
0, //subclass
0, //protocol
64, //max packet size
0x34,0x12, //vendor id
0xAA,0x55, //product id
0x00,0x01, //device release
0x00, //manuf str index
0x00, //prod str index
0x00, //serial str index
0x01 //no of possible configs
};
char myConfDescriptor[]={
//main config descriptor
9, //length of this descr
02, //type (config descr)
32,0, //total length
01, //no of interfaces
01, //select config no 1 to use this
00, //string descr of this config
0x80, //attributes
100, //max current drawn in 2ma steps
//iface1 condfig descriptor
9, //len
4, //type (iface descr)
0, //iface number this descr describes
0, //alternate setting for this iface
2, //number of endpoints
0xff, //iface class
0, //Iface subclass
0, //Iface protocol
0, //String descr of this iface
//Endpoint descriptor
7, //len
5, //type (endpoint descr)
0x3, //address. IN iface = +0x80
0x2, //attributes
32,0, //max packet size
10, //Interval to poll for data, in ms
//Endpoint descriptor
7, //len
5, //type (endpoint descr)
0x83, //address. IN iface = +0x80
0x2, //attributes
32,0, //max packet size
10, //Interval to poll for data, in ms
};
static int myAddr=0;
static void dumpHex(unsigned char *buf, int len) {
int x;
if (len==0) return;
for (x=0; x0) dumpHex((unsigned char* )data, len);
}
int readFromEp(int ep, unsigned int *data, int maxlen) {
int x, dummy;
USB_CTRL=((ep&0xF)<<2)|(1<<0);
NOP(); NOP(); NOP();
int plen;
do {
plen=USB_RXPLEN;
} while ((plen&0x400)==0);
plen&=0x3ff;
if (plen!=maxlen) printf("Ep %x: recv %i bufflen=%i!\n", ep, plen, maxlen);
for (x=0; x<(plen); x+=4) {
if (xmaxlen?maxlen:plen;
}
inline short swap16(unsigned short word) {
return ((word&0xff)<<8)|(word>>8);
}
static inline void handleSetupPacket(setupPacketTp *p) {
//A printf("Setup packet, type=%i, req=%i, val=%i, idx=%i\n", p->bmRequestType, p->bRequest, p->wValue, p->wIndex);
// dumpHex((unsigned char* )p, 8);
if (p->bmRequestType==0x80 && p->bRequest==6) {
//Get descriptor.
int index=swap16(p->wIndex);
int len=p->wLength;
if (swap16(p->wValue)==1) {
//Dev descriptor. Write to ep.
writeToEp(0, (unsigned int *)myDevDescriptor, myDevDescriptor[0]);
printf("Dev desc written.\n");
} else if (swap16(p->wValue)==2) {
int resplen=myConfDescriptor[2]+(myConfDescriptor[3]<<8);
if (resplen>len) resplen=len;
writeToEp(0, (unsigned int *)myConfDescriptor, len);
printf("Conf desc written.\n");
} else {
printf("EEK! Unhandled descriptor request!\n");
}
} else if (p->bmRequestType==00 && p->bRequest==5) {
//Set address
//First send Ack with our old addresss 0
writeToEp(0, NULL, 0);
//Then set new address.
myAddr=(p->wValue&0x7F);
wrCmd(0xD0);
wrData(myAddr|0x80);
wrCmd(0xD0);
wrData(myAddr|0x80);
printf("Set addr to %i.\n",myAddr);
} else if (p->bmRequestType==00 && p->bRequest==9) {
//Set configuration.
//Just allow, there's only one of them anyway.
writeToEp(0, NULL, 0);
//Ok, other stuff can come in now.
wrCmd(0xD8);
wrData(1);
printf("Enabled other endpoints!\n");
} else if (p->bmRequestType==0x40 && p->bRequest==1) { //vendor specific, gpio control, host->dev
//Modify output wIndex to wValue
gpioSet(p->wIndex, p->wValue);
} else {
printf("EEK! Unhandled setup packet!\n");
}
}
extern char usbData[64];
extern int usbDataLen;
void usbHandle() {
//Handle all the USB stuff by looking at any interrupts that would have been triggered.
int ints=USB_DEVINTST;
USB_DEVINTCLR=ints;
// if ((ints&0x1fe)!=0) printf("Int status %x\n", ints);
if (ints&(1<<7)) {
int epstatus=rdCmd(0x46);
printf("Ep3 int, status=%x\n", epstatus);
usbDataLen=readFromEp(3, usbData, 64);
return;
}
if (ints&(1<<8)) {
int epstatus=rdCmd(0x47);
printf("Ep3.1 int, status=%x\n", epstatus);
}
if (ints&(1<<1)) {
//Endpoint0 int
int epstatus=rdCmd(0x40);
// printf("Ep0 int, status=%x\n", epstatus);
if (epstatus&(1<<2)) {
//Setup-packet.
unsigned char setupPacket[8];
readFromEp(0, (unsigned int *)setupPacket, 8);
handleSetupPacket((setupPacketTp*) setupPacket);
}
}
if (ints&(1<<9)) {
//Device status change
int status=rdCmd(0xfe);
// printf("Dev status is now %x\n",status);
if (!(status&1)) {
//Reconnect, damn you!
/*
wrCmd(0xFE);
wrData(0x1);
myAddr=0;
*/
}
}
}