summaryrefslogtreecommitdiff
path: root/cpu/ppc4xx/usbdev.c
blob: f0901ac518d97229e1eefc2739071e5c26bc76f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*USB 1.1,2.0 device*/

#include <common.h>
#include <asm/processor.h>

#ifdef CONFIG_440_EP

#include <usb.h>
#include "usbdev.h"
#include "vecnum.h"

#define USB_DT_DEVICE        0x01
#define USB_DT_CONFIG        0x02
#define USB_DT_STRING        0x03
#define USB_DT_INTERFACE     0x04
#define USB_DT_ENDPOINT      0x05

unsigned char set_value = -1;

void process_endpoints(unsigned short usb2d0_intrin)
{
	/*will hold the packet received */
	struct usb_device_descriptor usb_device_packet;
	struct usb_config_descriptor usb_config_packet;
	struct usb_string_descriptor usb_string_packet;
	struct devrequest setup_packet;
	unsigned int *setup_packet_pt;
	unsigned char *packet_pt;
	int temp, temp1;

	int i;

	/*printf("{USB device} - endpoint 0x%X \n", usb2d0_intrin); */

	/*set usb address, seems to not work unless it is done in the next
	   interrupt, so that is why it is done this way */
	if (set_value != -1)
		*(unsigned char *)USB2D0_FADDR_8 = set_value;

	/*endpoint 1 */
	if (usb2d0_intrin & 0x01) {
		setup_packet_pt = (unsigned int *)&setup_packet;

		/*copy packet */
		setup_packet_pt[0] = *(unsigned int *)USB2D0_FIFO_0;
		setup_packet_pt[1] = *(unsigned int *)USB2D0_FIFO_0;
		temp = *(unsigned int *)USB2D0_FIFO_0;
		temp1 = *(unsigned int *)USB2D0_FIFO_0;

		/*do some swapping */
		setup_packet.value = swap_16(setup_packet.value);
		setup_packet.index = swap_16(setup_packet.index);
		setup_packet.length = swap_16(setup_packet.length);

		/*clear rx packet */
		*(unsigned short *)USB2D0_INCSR0_8 = 0x48;

		/*printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", setup_packet.requesttype,
		   setup_packet.request, setup_packet.value,
		   setup_packet.index, setup_packet.length, temp, temp1 ); */

		switch (setup_packet.request) {
		case USB_REQ_GET_DESCRIPTOR:

			switch (setup_packet.value >> 8) {
			case USB_DT_DEVICE:
				/*create packet */
				usb_device_packet.bLength = 18;
				usb_device_packet.bDescriptorType =
				    USB_DT_DEVICE;
#ifdef USB_2_0_DEVICE
				usb_device_packet.bcdUSB = swap_16(0x200);
#else
				usb_device_packet.bcdUSB = swap_16(0x110);
#endif
				usb_device_packet.bDeviceClass = 0xff;
				usb_device_packet.bDeviceSubClass = 0;
				usb_device_packet.bDeviceProtocol = 0;
				usb_device_packet.bMaxPacketSize0 = 32;
				usb_device_packet.idVendor = swap_16(1);
				usb_device_packet.idProduct = swap_16(2);
				usb_device_packet.bcdDevice = swap_16(0x300);
				usb_device_packet.iManufacturer = 1;
				usb_device_packet.iProduct = 1;
				usb_device_packet.iSerialNumber = 1;
				usb_device_packet.bNumConfigurations = 1;

				/*put packet in fifo */
				packet_pt = (unsigned char *)&usb_device_packet;
				break;

			case USB_DT_CONFIG:
				/*create packet */
				usb_config_packet.bLength = 9;
				usb_config_packet.bDescriptorType =
				    USB_DT_CONFIG;
				usb_config_packet.wTotalLength = swap_16(25);
				usb_config_packet.bNumInterfaces = 1;
				usb_config_packet.bConfigurationValue = 1;
				usb_config_packet.iConfiguration = 0;
				usb_config_packet.bmAttributes = 0x40;
				usb_config_packet.MaxPower = 0;

				/*put packet in fifo */
				packet_pt = (unsigned char *)&usb_config_packet;
				break;

			case USB_DT_STRING:
				/*create packet */
				usb_string_packet.bLength = 2;
				usb_string_packet.bDescriptorType =
				    USB_DT_STRING;
				usb_string_packet.wData[0] = 0x0094;

				/*put packet in fifo */
				packet_pt = (unsigned char *)&usb_string_packet;
				break;
			}

			/*put packet in fifo */
			for (i = 0; i < (setup_packet.length); i++) {
				*(unsigned char *)USB2D0_FIFO_0 = packet_pt[i];
			}

			/*give tx command */
			*(unsigned short *)USB2D0_INCSR0_8 = 0x0a;

			break;

		case USB_REQ_SET_ADDRESS:

			/*copy usb address */
			set_value = setup_packet.value;

			break;
		}

	}
}

void process_other(unsigned char usb2d0_intrusb)
{

	/*check for sof */
	if (usb2d0_intrusb & 0x08) {
		/*printf("{USB device} - sof detected\n"); */
	}

	/*check for reset */
	if (usb2d0_intrusb & 0x04) {
		/*printf("{USB device} - reset detected\n"); */

		/*copy usb address of zero, need to do this when usb reset */
		set_value = 0;
	}

	if (usb2d0_intrusb & 0x02) {
		/*printf("{USB device} - resume detected\n"); */
	}

	if (usb2d0_intrusb & 0x01) {
		/*printf("{USB device} - suspend detected\n"); */
	}
}

int usbInt(void)
{
	/*Must read these 2 registers and use values to clear interrupts.  If you
	   do not read them then the interrupt will not be cleared.  If you do not
	   use the variable the optimizer will not do a read. */
	volatile unsigned short usb2d0_intrin =
	    *(unsigned short *)USB2D0_INTRIN_16;
	volatile unsigned char usb2d0_intrusb =
	    *(unsigned char *)USB2D0_INTRUSB_8;

	/*check if there was an endpoint interrupt */
	if (usb2d0_intrin != 0) {
		process_endpoints(usb2d0_intrin);
	}

	/*check for other interrupts */
	if (usb2d0_intrusb != 0) {
		process_other(usb2d0_intrusb);
	}

	return 0;
}

void usb_dev_init()
{
#ifdef USB_2_0_DEVICE
	printf("USB 2.0 Device init\n");
	/*select 2.0 device */
	mtsdr(sdr_usb0, 0x0);	/* 2.0 */

	/*usb dev init */
	*(unsigned char *)USB2D0_POWER_8 = 0xa1;	/* 2.0 */
#else
	printf("USB 1.1 Device init\n");
	/*select 1.1 device */
	mtsdr(sdr_usb0, 0x2);	/* 1.1 */

	/*usb dev init */
	*(unsigned char *)USB2D0_POWER_8 = 0xc0;	/* 1.1 */
#endif

	/*enable interrupts */
	*(unsigned char *)USB2D0_INTRUSBE_8 = 0x0f;

	irq_install_handler(VECNUM_USBDEV, (interrupt_handler_t *) usbInt,
			    NULL);
}

#endif				/*CONFIG_440_EP */