OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [usb/] [serial/] [xircom_pgs.S] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*  $Id: xircom_pgs.S,v 1.1.1.1 2004-04-15 01:55:36 phoenix Exp $
2
 *
3
 *  Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
4
 *  the EzUSB microcontroller.
5
 *
6
 *  (C) Copyright 2000 Brian Warner 
7
 *
8
 *      This program is free software; you can redistribute it and/or modify
9
 *      it under the terms of the GNU General Public License as published by
10
 *      the Free Software Foundation; either version 2 of the License, or
11
 *      (at your option) any later version.
12
 *
13
 *  "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
14
 *  company.
15
 *
16
 *  This serial adapter is basically an EzUSB chip and an RS-232 line driver
17
 *  in a little widget that has a DB-9 on one end and a USB plug on the other.
18
 *  It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
19
 *  as a baud-rate generator. The wiring is:
20
 *   PC0/RxD0 <- rxd (DB9 pin 2)         PC4 <- dsr pin 6
21
 *   PC1/TxD0 -> txd pin 3               PC5 <- ri  pin 9
22
 *   PC2      -> rts pin 7               PC6 <- dcd pin 1
23
 *   PC3      <- cts pin 8               PC7 -> dtr pin 4
24
 *   PB1 -> line driver standby
25
 *
26
 *  The EzUSB register constants below come from their excellent documentation
27
 *  and sample code (which used to be available at www.anchorchips.com, but
28
 *  that has now been absorbed into Cypress' site and the CD-ROM contents
29
 *  don't appear to be available online anymore). If we get multiple
30
 *  EzUSB-based drivers into the kernel, it might be useful to pull them out
31
 *  into a separate .h file.
32
 *
33
 * THEORY OF OPERATION:
34
 *
35
 *   There are two 256-byte ring buffers, one for tx, one for rx.
36
 *
37
 *   EP2out is pure tx data. When it appears, the data is copied into the tx
38
 *   ring and serial transmission is started if it wasn't already running. The
39
 *   "tx buffer empty" interrupt may kick off another character if the ring
40
 *   still has data. If the host is tx-blocked because the ring filled up,
41
 *   it will request a "tx unthrottle" interrupt. If sending a serial character
42
 *   empties the ring below the desired threshold, we set a bit that will send
43
 *   up the tx unthrottle message as soon as the rx buffer becomes free.
44
 *
45
 *   EP2in (interrupt) is used to send both rx chars and rx status messages
46
 *   (only "tx unthrottle" at this time) back up to the host. The first byte
47
 *   of the rx message indicates data (0) or status msg (1). Status messages
48
 *   are sent before any data.
49
 *
50
 *   Incoming serial characters are put into the rx ring by the serial
51
 *   interrupt, and the EP2in buffer sent if it wasn't already in transit.
52
 *   When the EP2in buffer returns, the interrupt prompts us to send more
53
 *   rx chars (or status messages) if they are pending.
54
 *
55
 *   Device control happens through "vendor specific" control messages on EP0.
56
 *   All messages are destined for the "Interface" (with the index always 0,
57
 *   so that if their two-port device might someday use similar firmware, we
58
 *   can use index=1 to refer to the second port). The messages defined are:
59
 *
60
 *    bRequest = 0 : set baud/bits/parity
61
 *               1 : unused
62
 *               2 : reserved for setting HW flow control (CTSRTS)
63
 *               3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
64
 *               4 : set break (on/off)
65
 *               5 : reserved for requesting interrupts on pin state change
66
 *               6 : query buffer room or chars in tx buffer
67
 *               7 : request tx unthrottle interrupt
68
 *
69
 *  The host-side driver is set to recognize the device ID values stashed in
70
 *  serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
71
 *  start it running. This firmware will use EzUSB's "renumeration" trick by
72
 *  simulating a bus disconnect, then reconnect with a different device ID
73
 *  (encoded in the desc_device descriptor below). The host driver then
74
 *  recognizes the new device ID and glues it to the real serial driver code.
75
 *
76
 * USEFUL DOCS:
77
 *  EzUSB Technical Reference Manual: 
78
 *  8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
79
 *   basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
80
 *   use totally different registers!
81
 *  USB 1.1 spec: www.usb.org
82
 *
83
 * HOW TO BUILD:
84
 *  gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
85
 *  as31 -l keyspan_pda.asm
86
 *  mv keyspan_pda.obj keyspan_pda.hex
87
 *  perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
88
 * Get as31 from , and hack on it
89
 * a bit to make it build.
90
 *
91
 * THANKS:
92
 *  Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
93
 *  AnchorChips, for making such an incredibly useful little microcontroller.
94
 *  KeySpan, for making a handy, cheap ($40) widget that was so easy to take
95
 *           apart and trace with an ohmmeter.
96
 *
97
 * TODO:
98
 *  lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
99
 *  control. Interrupting host upon change in DCD, etc, counting transitions.
100
 *  Need to find a safe device id to use (the one used by the Keyspan firmware
101
 *  under Windows would be ideal.. can anyone figure out what it is?). Parity.
102
 *  More baud rates. Oh, and the string-descriptor-length silicon bug
103
 *  workaround should be implemented, but I'm lazy, and the consequence is
104
 *  that the device name strings that show up in your kernel log will have
105
 *  lots of trailing binary garbage in them (appears as ????). Device strings
106
 *  should be made more accurate.
107
 *
108
 * Questions, bugs, patches to Brian.
109
 *
110
 *  -Brian Warner 
111
 *
112
 */
113
 
114
#define HIGH(x) (((x) & 0xff00) / 256)
115
#define LOW(x) ((x) & 0xff)
116
 
117
#define dpl1 0x84
118
#define dph1 0x85
119
#define dps 0x86
120
 
121
;;; our bit assignments
122
#define TX_RUNNING 0
123
#define DO_TX_UNTHROTTLE 1
124
 
125
        ;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
126
#define STACK #0x60-1
127
 
128
#define EXIF 0x91
129
#define EIE 0xe8
130
        .flag EUSB, EIE.0
131
        .flag ES0, IE.4
132
 
133
#define EP0CS #0x7fb4
134
#define EP0STALLbit #0x01
135
#define IN0BUF #0x7f00
136
#define IN0BC #0x7fb5
137
#define OUT0BUF #0x7ec0
138
#define OUT0BC #0x7fc5
139
#define IN2BUF #0x7e00
140
#define IN2BC #0x7fb9
141
#define IN2CS #0x7fb8
142
#define OUT2BC #0x7fc9
143
#define OUT2CS #0x7fc8
144
#define OUT2BUF #0x7dc0
145
#define IN4BUF #0x7d00
146
#define IN4BC #0x7fbd
147
#define IN4CS #0x7fbc
148
#define OEB #0x7f9d
149
#define OUTB #0x7f97
150
#define OEC #0x7f9e
151
#define OUTC #0x7f98
152
#define PINSC #0x7f9b
153
#define PORTBCFG #0x7f94
154
#define PORTCCFG #0x7f95
155
#define OEA     #0x7f9c
156
#define IN07IRQ #0x7fa9
157
#define OUT07IRQ #0x7faa
158
#define IN07IEN #0x7fac
159
#define OUT07IEN #0x7fad
160
#define USBIRQ #0x7fab
161
#define USBIEN #0x7fae
162
#define USBBAV #0x7faf
163
#define USBCS #0x7fd6
164
#define SUDPTRH #0x7fd4
165
#define SUDPTRL #0x7fd5
166
#define SETUPDAT #0x7fe8
167
 
168
        ;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
169
 
170
        .org 0
171
        ljmp start
172
        ;; interrupt vectors
173
        .org 23H
174
        ljmp serial_int
175
        .byte 0
176
 
177
        .org 43H
178
        ljmp USB_Jump_Table
179
        .byte 0                 ; filled in by the USB core
180
 
181
;;; local variables. These are not initialized properly: do it by hand.
182
        .org 30H
183
rx_ring_in:     .byte 0
184
rx_ring_out:    .byte 0
185
tx_ring_in:     .byte 0
186
tx_ring_out:    .byte 0
187
tx_unthrottle_threshold:        .byte 0
188
 
189
        .org 0x100H             ; wants to be on a page boundary
190
USB_Jump_Table:
191
        ljmp    ISR_Sudav       ; Setup Data Available
192
        .byte 0
193
        ljmp    0                ; Start of Frame
194
        .byte 0
195
        ljmp    0                ; Setup Data Loading
196
        .byte 0
197
        ljmp    0                ; Global Suspend
198
        .byte   0
199
        ljmp    0                ; USB Reset
200
        .byte   0
201
        ljmp    0                ; Reserved
202
        .byte   0
203
        ljmp    0                ; End Point 0 In
204
        .byte   0
205
        ljmp    0                ; End Point 0 Out
206
        .byte   0
207
        ljmp    0                ; End Point 1 In
208
        .byte   0
209
        ljmp    0                ; End Point 1 Out
210
        .byte   0
211
        ljmp    ISR_Ep2in
212
        .byte   0
213
        ljmp    ISR_Ep2out
214
        .byte   0
215
 
216
 
217
        .org 0x200
218
 
219
start:  mov SP,STACK-1 ; set stack
220
        ;; clear local variables
221
        clr a
222
        mov tx_ring_in, a
223
        mov tx_ring_out, a
224
        mov rx_ring_in, a
225
        mov rx_ring_out, a
226
        mov tx_unthrottle_threshold, a
227
        clr TX_RUNNING
228
        clr DO_TX_UNTHROTTLE
229
 
230
        ;; clear fifo with "fe"
231
        mov r1, 0
232
        mov a, #0xfe
233
        mov dptr, #tx_ring
234
clear_tx_ring_loop:
235
        movx @dptr, a
236
        inc dptr
237
        djnz r1, clear_tx_ring_loop
238
 
239
        mov a, #0xfd
240
        mov dptr, #rx_ring
241
clear_rx_ring_loop:
242
        movx @dptr, a
243
        inc dptr
244
        djnz r1, clear_rx_ring_loop
245
 
246
;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
247
;;; on Xircom the STANDBY is wired to PB6 and PC4
248
        mov dptr, PORTBCFG
249
        mov a, #0xBf
250
        movx @dptr, a
251
        mov dptr, PORTCCFG
252
        mov a, #0xef
253
        movx @dptr, a
254
 
255
        ;; set OEC.4
256
        mov a, #0x10
257
        mov dptr,OEC
258
        movx @dptr,a
259
 
260
        ;; clear PC4
261
        mov a, #0x00
262
        mov dptr,OUTC
263
        movx @dptr,a
264
 
265
        ;; set OEB.6
266
        mov a, #0x40
267
        mov dptr,OEB
268
        movx @dptr,a
269
 
270
        ;; clear PB6
271
        mov a, #0x00
272
        mov dptr,OUTB
273
        movx @dptr,a
274
 
275
        ;; set OEC.[17]
276
        mov a, #0x82
277
        mov dptr,OEC
278
        movx @dptr,a
279
 
280
 
281
        ;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
282
        mov dptr, PORTCCFG
283
        mov a, #0x03
284
        movx @dptr, a
285
 
286
        ;; set up interrupts, autovectoring
287
        ;; set BKPT
288
        mov dptr, USBBAV
289
        movx a,@dptr
290
        setb acc.0              ; AVEN bit to 0
291
        movx @dptr, a
292
 
293
        mov a,#0x01             ; enable SUDAV: setup data available (for ep0)
294
        mov dptr, USBIRQ
295
        movx @dptr, a           ; clear SUDAVI
296
        mov dptr, USBIEN
297
        movx @dptr, a
298
 
299
        mov dptr, IN07IEN
300
        mov a,#0x04             ; enable IN2 int
301
        movx @dptr, a
302
 
303
        mov dptr, OUT07IEN
304
        mov a,#0x04             ; enable OUT2 int
305
        movx @dptr, a
306
        mov dptr, OUT2BC
307
        movx @dptr, a           ; arm OUT2
308
 
309
;;      mov a, #0x84            ; turn on RTS, DTR
310
;;      mov dptr,OUTC
311
;;      movx @dptr, a
312
 
313
        mov a, #0x7             ; turn on  DTR
314
        mov dptr,USBBAV
315
        movx @dptr, a
316
 
317
        mov a, #0x20             ; turn on the RED led
318
        mov dptr,OEA
319
        movx @dptr, a
320
 
321
        mov a, #0x80            ; turn on  RTS
322
        mov dptr,OUTC
323
        movx @dptr, a
324
 
325
        ;; setup the serial port. 9600 8N1.
326
        mov a,#0x53             ; mode 1, enable rx, clear int
327
        mov SCON, a
328
        ;;  using timer2, in 16-bit baud-rate-generator mode
329
        ;;   (xtal 12MHz, internal fosc 24MHz)
330
        ;;  RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
331
        ;;  57600: 0xFFF2.F, say 0xFFF3
332
        ;;   9600: 0xFFB1.E, say 0xFFB2
333
        ;;    300: 0xF63C
334
#define BAUD 9600
335
#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
336
#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
337
#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
338
 
339
        mov T2CON, #030h        ; rclk=1,tclk=1,cp=0,tr2=0(enable later)
340
        mov r3, #5
341
        acall set_baud
342
        setb TR2
343
        mov SCON, #050h
344
 
345
#if 0
346
        mov r1, #0x40
347
        mov a, #0x41
348
send:
349
        mov SBUF, a
350
        inc a
351
        anl a, #0x3F
352
        orl a, #0x40
353
;       xrl a, #0x02
354
wait1:
355
        jnb TI, wait1
356
        clr TI
357
        djnz r1, send
358
;done:  sjmp done
359
 
360
#endif
361
 
362
        setb EUSB
363
        setb EA
364
        setb ES0
365
        ;acall dump_stat
366
 
367
        ;; hey, what say we RENUMERATE! (TRM p.62)
368
        mov a, #0
369
        mov dps, a
370
        mov dptr, USBCS
371
        mov a, #0x02            ; DISCON=0, DISCOE=0, RENUM=1
372
        movx @dptr, a
373
        ;; now presence pin is floating, simulating disconnect. wait 0.5s
374
        mov r1, #46
375
renum_wait1:
376
        mov r2, #0
377
renum_wait2:
378
        mov r3, #0
379
renum_wait3:
380
        djnz r3, renum_wait3
381
        djnz r2, renum_wait2
382
        djnz r1, renum_wait1    ; wait about n*(256^2) 6MHz clocks
383
        mov a, #0x06            ; DISCON=0, DISCOE=1, RENUM=1
384
        movx @dptr, a
385
        ;; we are back online. the host device will now re-query us
386
 
387
 
388
main:   sjmp main
389
 
390
 
391
 
392
ISR_Sudav:
393
        push dps
394
        push dpl
395
        push dph
396
        push dpl1
397
        push dph1
398
        push acc
399
        mov a,EXIF
400
        clr acc.4
401
        mov EXIF,a              ; clear INT2 first
402
        mov dptr, USBIRQ        ; clear USB int
403
        mov a,#01h
404
        movx @dptr,a
405
 
406
        ;; get request type
407
        mov dptr, SETUPDAT
408
        movx a, @dptr
409
        mov r1, a               ; r1 = bmRequestType
410
        inc dptr
411
        movx a, @dptr
412
        mov r2, a               ; r2 = bRequest
413
        inc dptr
414
        movx a, @dptr
415
        mov r3, a               ; r3 = wValueL
416
        inc dptr
417
        movx a, @dptr
418
        mov r4, a               ; r4 = wValueH
419
 
420
        ;; main switch on bmRequest.type: standard or vendor
421
        mov a, r1
422
        anl a, #0x60
423
        cjne a, #0x00, setup_bmreq_type_not_standard
424
        ;; standard request: now main switch is on bRequest
425
        ljmp setup_bmreq_is_standard
426
 
427
setup_bmreq_type_not_standard:
428
        ;; a still has bmreq&0x60
429
        cjne a, #0x40, setup_bmreq_type_not_vendor
430
        ;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
431
        ;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
432
        cjne r2, #0x00, setup_ctrl_not_00
433
        ;; 00 is set baud, wValue[0] has baud rate index
434
        lcall set_baud          ; index in r3, carry set if error
435
        jc setup_bmreq_type_not_standard__do_stall
436
        ljmp setup_done_ack
437
setup_bmreq_type_not_standard__do_stall:
438
        ljmp setup_stall
439
setup_ctrl_not_00:
440
        cjne r2, #0x01, setup_ctrl_not_01
441
        ;; 01 is reserved for set bits (parity). TODO
442
        ljmp setup_stall
443
setup_ctrl_not_01:
444
        cjne r2, #0x02, setup_ctrl_not_02
445
        ;; 02 is set HW flow control. TODO
446
        ljmp setup_stall
447
setup_ctrl_not_02:
448
        cjne r2, #0x03, setup_ctrl_not_03
449
        ;; 03 is control pins (RTS, DTR).
450
        ljmp control_pins       ; will jump to setup_done_ack,
451
                                ;  or setup_return_one_byte
452
setup_ctrl_not_03:
453
        cjne r2, #0x04, setup_ctrl_not_04
454
        ;; 04 is send break (really "turn break on/off"). TODO
455
        cjne r3, #0x00, setup_ctrl_do_break_on
456
        ;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
457
        mov dptr, PORTCCFG
458
        movx a, @dptr
459
        orl a, #0x02
460
        movx @dptr, a
461
        ljmp setup_done_ack
462
setup_ctrl_do_break_on:
463
        ;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
464
        mov dptr, OUTC
465
        movx a, @dptr
466
        anl a, #0xfd            ; ~0x02
467
        movx @dptr, a
468
        mov dptr, PORTCCFG
469
        movx a, @dptr
470
        anl a, #0xfd            ; ~0x02
471
        movx @dptr, a
472
        ljmp setup_done_ack
473
setup_ctrl_not_04:
474
        cjne r2, #0x05, setup_ctrl_not_05
475
        ;; 05 is set desired interrupt bitmap. TODO
476
        ljmp setup_stall
477
setup_ctrl_not_05:
478
        cjne r2, #0x06, setup_ctrl_not_06
479
        ;; 06 is query room
480
        cjne r3, #0x00, setup_ctrl_06_not_00
481
        ;; 06, wValue[0]=0 is query write_room
482
        mov a, tx_ring_out
483
        setb c
484
        subb a, tx_ring_in      ; out-1-in = 255 - (in-out)
485
        ljmp setup_return_one_byte
486
setup_ctrl_06_not_00:
487
        cjne r3, #0x01, setup_ctrl_06_not_01
488
        ;; 06, wValue[0]=1 is query chars_in_buffer
489
        mov a, tx_ring_in
490
        clr c
491
        subb a, tx_ring_out     ; in-out
492
        ljmp setup_return_one_byte
493
setup_ctrl_06_not_01:
494
        ljmp setup_stall
495
setup_ctrl_not_06:
496
        cjne r2, #0x07, setup_ctrl_not_07
497
        ;; 07 is request tx unthrottle interrupt
498
        mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
499
        ljmp setup_done_ack
500
setup_ctrl_not_07:
501
        ljmp setup_stall
502
 
503
setup_bmreq_type_not_vendor:
504
        ljmp setup_stall
505
 
506
 
507
setup_bmreq_is_standard:
508
        cjne r2, #0x00, setup_breq_not_00
509
        ;; 00:  Get_Status (sub-switch on bmRequestType: device, ep, int)
510
        cjne r1, #0x80, setup_Get_Status_not_device
511
        ;; Get_Status(device)
512
        ;;  are we self-powered? no. can we do remote wakeup? no
513
        ;;   so return two zero bytes. This is reusable
514
setup_return_two_zero_bytes:
515
        mov dptr, IN0BUF
516
        clr a
517
        movx @dptr, a
518
        inc dptr
519
        movx @dptr, a
520
        mov dptr, IN0BC
521
        mov a, #2
522
        movx @dptr, a
523
        ljmp setup_done_ack
524
setup_Get_Status_not_device:
525
        cjne r1, #0x82, setup_Get_Status_not_endpoint
526
        ;; Get_Status(endpoint)
527
        ;;  must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
528
        ;; for now: cheat. TODO
529
        sjmp setup_return_two_zero_bytes
530
setup_Get_Status_not_endpoint:
531
        cjne r1, #0x81, setup_Get_Status_not_interface
532
        ;; Get_Status(interface): return two zeros
533
        sjmp setup_return_two_zero_bytes
534
setup_Get_Status_not_interface:
535
        ljmp setup_stall
536
 
537
setup_breq_not_00:
538
        cjne r2, #0x01, setup_breq_not_01
539
        ;; 01:  Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
540
        cjne r3, #0x00, setup_Clear_Feature_not_stall
541
        ;; Clear_Feature(stall). should clear a stall bit. TODO
542
        ljmp setup_stall
543
setup_Clear_Feature_not_stall:
544
        cjne r3, #0x01, setup_Clear_Feature_not_rwake
545
        ;; Clear_Feature(remote wakeup). ignored.
546
        ljmp setup_done_ack
547
setup_Clear_Feature_not_rwake:
548
        ljmp setup_stall
549
 
550
setup_breq_not_01:
551
        cjne r2, #0x03, setup_breq_not_03
552
        ;; 03:  Set_Feature (sub-switch on wValueL: stall, remote wakeup)
553
        cjne r3, #0x00, setup_Set_Feature_not_stall
554
        ;; Set_Feature(stall). Should set a stall bit. TODO
555
        ljmp setup_stall
556
setup_Set_Feature_not_stall:
557
        cjne r3, #0x01, setup_Set_Feature_not_rwake
558
        ;; Set_Feature(remote wakeup). ignored.
559
        ljmp setup_done_ack
560
setup_Set_Feature_not_rwake:
561
        ljmp setup_stall
562
 
563
setup_breq_not_03:
564
        cjne r2, #0x06, setup_breq_not_06
565
        ;; 06:  Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
566
        cjne r4, #0x01, setup_Get_Descriptor_not_device
567
        ;; Get_Descriptor(device)
568
        mov dptr, SUDPTRH
569
        mov a, #HIGH(desc_device)
570
        movx @dptr, a
571
        mov dptr, SUDPTRL
572
        mov a, #LOW(desc_device)
573
        movx @dptr, a
574
        ljmp setup_done_ack
575
setup_Get_Descriptor_not_device:
576
        cjne r4, #0x02, setup_Get_Descriptor_not_config
577
        ;; Get_Descriptor(config[n])
578
        cjne r3, #0x00, setup_stall; only handle n==0
579
        ;; Get_Descriptor(config[0])
580
        mov dptr, SUDPTRH
581
        mov a, #HIGH(desc_config1)
582
        movx @dptr, a
583
        mov dptr, SUDPTRL
584
        mov a, #LOW(desc_config1)
585
        movx @dptr, a
586
        ljmp setup_done_ack
587
setup_Get_Descriptor_not_config:
588
        cjne r4, #0x03, setup_Get_Descriptor_not_string
589
        ;; Get_Descriptor(string[wValueL])
590
        ;;  if (wValueL >= maxstrings) stall
591
        mov a, #((desc_strings_end-desc_strings)/2)
592
        clr c
593
        subb a,r3               ; a=4, r3 = 0..3 . if a<=0 then stall
594
        jc  setup_stall
595
        jz  setup_stall
596
        mov a, r3
597
        add a, r3               ; a = 2*wValueL
598
        mov dptr, #desc_strings
599
        add a, dpl
600
        mov dpl, a
601
        mov a, #0
602
        addc a, dph
603
        mov dph, a              ; dph = desc_strings[a]. big endian! (handy)
604
        ;; it looks like my adapter uses a revision of the EZUSB that
605
        ;; contains "rev D errata number 8", as hinted in the EzUSB example
606
        ;; code. I cannot find an actual errata description on the Cypress
607
        ;; web site, but from the example code it looks like this bug causes
608
        ;; the length of string descriptors to be read incorrectly, possibly
609
        ;; sending back more characters than the descriptor has. The workaround
610
        ;; is to manually send out all of the data. The consequence of not
611
        ;; using the workaround is that the strings gathered by the kernel
612
        ;; driver are too long and are filled with trailing garbage (including
613
        ;; leftover strings). Writing this out by hand is a nuisance, so for
614
        ;; now I will just live with the bug.
615
        movx a, @dptr
616
        mov r1, a
617
        inc dptr
618
        movx a, @dptr
619
        mov r2, a
620
        mov dptr, SUDPTRH
621
        mov a, r1
622
        movx @dptr, a
623
        mov dptr, SUDPTRL
624
        mov a, r2
625
        movx @dptr, a
626
        ;; done
627
        ljmp setup_done_ack
628
 
629
setup_Get_Descriptor_not_string:
630
        ljmp setup_stall
631
 
632
setup_breq_not_06:
633
        cjne r2, #0x08, setup_breq_not_08
634
        ;; Get_Configuration. always 1. return one byte.
635
        ;; this is reusable
636
        mov a, #1
637
setup_return_one_byte:
638
        mov dptr, IN0BUF
639
        movx @dptr, a
640
        mov a, #1
641
        mov dptr, IN0BC
642
        movx @dptr, a
643
        ljmp setup_done_ack
644
setup_breq_not_08:
645
        cjne r2, #0x09, setup_breq_not_09
646
        ;; 09: Set_Configuration. ignored.
647
        ljmp setup_done_ack
648
setup_breq_not_09:
649
        cjne r2, #0x0a, setup_breq_not_0a
650
        ;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
651
        ;;  since we only have one interface, ignore wIndexL, return a 0
652
        mov a, #0
653
        ljmp setup_return_one_byte
654
setup_breq_not_0a:
655
        cjne r2, #0x0b, setup_breq_not_0b
656
        ;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
657
        ljmp setup_done_ack
658
setup_breq_not_0b:
659
        ljmp setup_stall
660
 
661
 
662
setup_done_ack:
663
        ;; now clear HSNAK
664
        mov dptr, EP0CS
665
        mov a, #0x02
666
        movx @dptr, a
667
        sjmp setup_done
668
setup_stall:
669
        ;; unhandled. STALL
670
        ;EP0CS |= bmEPSTALL
671
        mov dptr, EP0CS
672
        movx a, @dptr
673
        orl a, EP0STALLbit
674
        movx @dptr, a
675
        sjmp setup_done
676
 
677
setup_done:
678
        pop acc
679
        pop dph1
680
        pop dpl1
681
        pop dph
682
        pop dpl
683
        pop dps
684
        reti
685
 
686
;;; ==============================================================
687
 
688
set_baud:                       ; baud index in r3
689
        ;; verify a < 10
690
        mov a, r3
691
        jb ACC.7, set_baud__badbaud
692
        clr c
693
        subb a, #10
694
        jnc set_baud__badbaud
695
        mov a, r3
696
        rl a                    ; a = index*2
697
        add a, #LOW(baud_table)
698
        mov dpl, a
699
        mov a, #HIGH(baud_table)
700
        addc a, #0
701
        mov dph, a
702
        ;; TODO: shut down xmit/receive
703
        ;; TODO: wait for current xmit char to leave
704
        ;; TODO: shut down timer to avoid partial-char glitch
705
        movx a,@dptr            ; BAUD_HIGH
706
        mov RCAP2H, a
707
        mov TH2, a
708
        inc dptr
709
        movx a,@dptr            ; BAUD_LOW
710
        mov RCAP2L, a
711
        mov TL2, a
712
        ;; TODO: restart xmit/receive
713
        ;; TODO: reenable interrupts, resume tx if pending
714
        clr c                   ; c=0: success
715
        ret
716
set_baud__badbaud:
717
        setb c                  ; c=1: failure
718
        ret
719
 
720
;;; ==================================================
721
control_pins:
722
        cjne r1, #0x41, control_pins_in
723
control_pins_out:
724
                ;TODO BKPT is DTR
725
        mov a, r3 ; wValue[0] holds new bits:   b7 is new RTS
726
        xrl a, #0xff            ; 1 means active, 0V, +12V ?
727
        anl a, #0x80
728
        mov r3, a
729
        mov dptr, OUTC
730
        movx a, @dptr           ; only change bit 7
731
        anl a, #0x7F            ; ~0x84
732
        orl a, r3
733
        movx @dptr, a           ; other pins are inputs, bits ignored
734
        ljmp setup_done_ack
735
control_pins_in:
736
        mov dptr, PINSC
737
        movx a, @dptr
738
        xrl a, #0xff
739
        ljmp setup_return_one_byte
740
 
741
;;; ========================================
742
 
743
ISR_Ep2in:
744
        push dps
745
        push dpl
746
        push dph
747
        push dpl1
748
        push dph1
749
        push acc
750
        mov a,EXIF
751
        clr acc.4
752
        mov EXIF,a              ; clear INT2 first
753
        mov dptr, IN07IRQ       ; clear USB int
754
        mov a,#04h
755
        movx @dptr,a
756
 
757
        mov a, #0x20             ; Turn off the green LED
758
        mov dptr,OEA
759
        movx @dptr, a
760
 
761
 
762
        ;; do stuff
763
        lcall start_in
764
 
765
        mov a, #0x20             ; Turn off the green LED
766
        mov dptr,OEA
767
        movx @dptr, a
768
 
769
 
770
 
771
        pop acc
772
        pop dph1
773
        pop dpl1
774
        pop dph
775
        pop dpl
776
        pop dps
777
        reti
778
 
779
ISR_Ep2out:
780
        push dps
781
        push dpl
782
        push dph
783
        push dpl1
784
        push dph1
785
        push acc
786
 
787
        mov a, #0x10             ; Turn the green LED
788
        mov dptr,OEA
789
        movx @dptr, a
790
 
791
 
792
 
793
        mov a,EXIF
794
        clr acc.4
795
        mov EXIF,a              ; clear INT2 first
796
        mov dptr, OUT07IRQ      ; clear USB int
797
        mov a,#04h
798
        movx @dptr,a
799
 
800
        ;; do stuff
801
 
802
        ;; copy data into buffer. for now, assume we will have enough space
803
        mov dptr, OUT2BC        ; get byte count
804
        movx a,@dptr
805
        mov r1, a
806
        clr a
807
        mov dps, a
808
        mov dptr, OUT2BUF       ; load DPTR0 with source
809
        mov dph1, #HIGH(tx_ring)        ; load DPTR1 with target
810
        mov dpl1, tx_ring_in
811
OUT_loop:
812
        movx a,@dptr            ; read
813
        inc dps                 ; switch to DPTR1: target
814
        inc dpl1                ; target = tx_ring_in+1
815
        movx @dptr,a            ; store
816
        mov a,dpl1
817
        cjne a, tx_ring_out, OUT_no_overflow
818
        sjmp OUT_overflow
819
OUT_no_overflow:
820
        inc tx_ring_in          ; tx_ring_in++
821
        inc dps                 ; switch to DPTR0: source
822
        inc dptr
823
        djnz r1, OUT_loop
824
        sjmp OUT_done
825
OUT_overflow:
826
        ;; signal overflow
827
        ;; fall through
828
OUT_done:
829
        ;; ack
830
        mov dptr,OUT2BC
831
        movx @dptr,a
832
 
833
        ;; start tx
834
        acall maybe_start_tx
835
        ;acall dump_stat
836
 
837
        mov a, #0x20             ; Turn off the green LED
838
        mov dptr,OEA
839
        movx @dptr, a
840
 
841
        pop acc
842
        pop dph1
843
        pop dpl1
844
        pop dph
845
        pop dpl
846
        pop dps
847
        reti
848
 
849
dump_stat:
850
        ;; fill in EP4in with a debugging message:
851
        ;;   tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
852
        ;;   tx_active
853
        ;;   tx_ring[0..15]
854
        ;;   0xfc
855
        ;;   rx_ring[0..15]
856
        clr a
857
        mov dps, a
858
 
859
        mov dptr, IN4CS
860
        movx a, @dptr
861
        jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
862
        mov dptr, IN4BUF
863
 
864
        mov a, tx_ring_in
865
        movx @dptr, a
866
        inc dptr
867
        mov a, tx_ring_out
868
        movx @dptr, a
869
        inc dptr
870
 
871
        mov a, rx_ring_in
872
        movx @dptr, a
873
        inc dptr
874
        mov a, rx_ring_out
875
        movx @dptr, a
876
        inc dptr
877
 
878
        clr a
879
        jnb TX_RUNNING, dump_stat__no_tx_running
880
        inc a
881
dump_stat__no_tx_running:
882
        movx @dptr, a
883
        inc dptr
884
        ;; tx_ring[0..15]
885
        inc dps
886
        mov dptr, #tx_ring      ; DPTR1: source
887
        mov r1, #16
888
dump_stat__tx_ring_loop:
889
        movx a, @dptr
890
        inc dptr
891
        inc dps
892
        movx @dptr, a
893
        inc dptr
894
        inc dps
895
        djnz r1, dump_stat__tx_ring_loop
896
        inc dps
897
 
898
        mov a, #0xfc
899
        movx @dptr, a
900
        inc dptr
901
 
902
        ;; rx_ring[0..15]
903
        inc dps
904
        mov dptr, #rx_ring      ; DPTR1: source
905
        mov r1, #16
906
dump_stat__rx_ring_loop:
907
        movx a, @dptr
908
        inc dptr
909
        inc dps
910
        movx @dptr, a
911
        inc dptr
912
        inc dps
913
        djnz r1, dump_stat__rx_ring_loop
914
 
915
        ;; now send it
916
        clr a
917
        mov dps, a
918
        mov dptr, IN4BC
919
        mov a, #38
920
        movx @dptr, a
921
dump_stat__done:
922
        ret
923
 
924
;;; ============================================================
925
 
926
maybe_start_tx:
927
        ;; make sure the tx process is running.
928
        jb TX_RUNNING, start_tx_done
929
start_tx:
930
        ;; is there work to be done?
931
        mov a, tx_ring_in
932
        cjne a,tx_ring_out, start_tx__work
933
        ret                     ; no work
934
start_tx__work:
935
        ;; tx was not running. send the first character, setup the TI int
936
        inc tx_ring_out         ; [++tx_ring_out]
937
        mov dph, #HIGH(tx_ring)
938
        mov dpl, tx_ring_out
939
        movx a, @dptr
940
        mov sbuf, a
941
        setb TX_RUNNING
942
start_tx_done:
943
        ;; can we unthrottle the host tx process?
944
        ;;  step 1: do we care?
945
        mov a, #0
946
        cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
947
        ;; nope
948
start_tx_really_done:
949
        ret
950
start_tx__maybe_unthrottle_tx:
951
        ;;  step 2: is there now room?
952
        mov a, tx_ring_out
953
        setb c
954
        subb a, tx_ring_in
955
        ;; a is now write_room. If thresh >= a, we can unthrottle
956
        clr c
957
        subb a, tx_unthrottle_threshold
958
        jc start_tx_really_done ; nope
959
        ;; yes, we can unthrottle. remove the threshold and mark a request
960
        mov tx_unthrottle_threshold, #0
961
        setb DO_TX_UNTHROTTLE
962
        ;; prod rx, which will actually send the message when in2 becomes free
963
        ljmp start_in
964
 
965
 
966
serial_int:
967
        push dps
968
        push dpl
969
        push dph
970
        push dpl1
971
        push dph1
972
        push acc
973
        jnb TI, serial_int__not_tx
974
        ;; tx finished. send another character if we have one
975
        clr TI                  ; clear int
976
        clr TX_RUNNING
977
        lcall start_tx
978
serial_int__not_tx:
979
        jnb RI, serial_int__not_rx
980
        lcall get_rx_char
981
        clr RI                  ; clear int
982
serial_int__not_rx:
983
        ;; return
984
        pop acc
985
        pop dph1
986
        pop dpl1
987
        pop dph
988
        pop dpl
989
        pop dps
990
        reti
991
 
992
get_rx_char:
993
        mov dph, #HIGH(rx_ring)
994
        mov dpl, rx_ring_in
995
        inc dpl                 ; target = rx_ring_in+1
996
        mov a, sbuf
997
        movx @dptr, a
998
        ;; check for overflow before incrementing rx_ring_in
999
        mov a, dpl
1000
        cjne a, rx_ring_out, get_rx_char__no_overflow
1001
        ;; signal overflow
1002
        ret
1003
get_rx_char__no_overflow:
1004
        inc rx_ring_in
1005
        ;; kick off USB INpipe
1006
        acall start_in
1007
        ret
1008
 
1009
start_in:
1010
        ;; check if the inpipe is already running.
1011
        mov  a,#0x10
1012
        mov dptr, OEA
1013
        movx @dptr,a
1014
 
1015
        mov dptr, IN2CS
1016
        movx a, @dptr
1017
        jb acc.1, start_in__done; int will handle it
1018
        jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
1019
        ;; see if there is any work to do. a serial interrupt might occur
1020
        ;; during this sequence?
1021
        mov a, rx_ring_in
1022
        cjne a, rx_ring_out, start_in__have_work
1023
        ret                     ; nope
1024
start_in__have_work:
1025
        ;; now copy as much data as possible into the pipe. 63 bytes max.
1026
        clr a
1027
        mov dps, a
1028
        mov dph, #HIGH(rx_ring) ; load DPTR0 with source
1029
        inc dps
1030
        mov dptr, IN2BUF        ; load DPTR1 with target
1031
        movx @dptr, a           ; in[0] signals that rest of IN is rx data
1032
        inc dptr
1033
        inc dps
1034
        ;; loop until we run out of data, or we have copied 64 bytes
1035
        mov r1, #1              ; INbuf size counter
1036
start_in__loop:
1037
        mov a, rx_ring_in
1038
        cjne a, rx_ring_out, start_in__still_copying
1039
        sjmp start_in__kick
1040
start_in__still_copying:
1041
        inc rx_ring_out
1042
        mov dpl, rx_ring_out
1043
        movx a, @dptr
1044
        inc dps
1045
        movx @dptr, a           ; write into IN buffer
1046
        inc dptr
1047
        inc dps
1048
        inc r1
1049
        cjne r1, #64, start_in__loop; loop
1050
start_in__kick:
1051
        ;; either we ran out of data, or we copied 64 bytes. r1 has byte count
1052
        ;; kick off IN
1053
        mov a, #0x10             ; Turn the green LED
1054
        mov dptr,OEA
1055
        movx @dptr, a
1056
        mov dptr, IN2BC
1057
        mov a, r1
1058
        jz start_in__done
1059
        movx @dptr, a
1060
        ;; done
1061
start_in__done:
1062
        ;acall dump_stat
1063
        ret
1064
start_in__do_tx_unthrottle:
1065
        ;; special sequence: send a tx unthrottle message
1066
        clr DO_TX_UNTHROTTLE
1067
        clr a
1068
        mov dps, a
1069
        mov dptr, IN2BUF
1070
        mov a, #1
1071
        movx @dptr, a
1072
        inc dptr
1073
        mov a, #2
1074
        movx @dptr, a
1075
        mov dptr, IN2BC
1076
        movx @dptr, a
1077
        ret
1078
 
1079
putchar:
1080
        clr TI
1081
        mov SBUF, a
1082
putchar_wait:
1083
        jnb TI, putchar_wait
1084
        clr TI
1085
        ret
1086
 
1087
 
1088
baud_table:                     ; baud_high, then baud_low
1089
        ;; baud[0]: 110
1090
        .byte BAUD_HIGH(110)
1091
        .byte BAUD_LOW(110)
1092
        ;; baud[1]: 300
1093
        .byte BAUD_HIGH(300)
1094
        .byte BAUD_LOW(300)
1095
        ;; baud[2]: 1200
1096
        .byte BAUD_HIGH(1200)
1097
        .byte BAUD_LOW(1200)
1098
        ;; baud[3]: 2400
1099
        .byte BAUD_HIGH(2400)
1100
        .byte BAUD_LOW(2400)
1101
        ;; baud[4]: 4800
1102
        .byte BAUD_HIGH(4800)
1103
        .byte BAUD_LOW(4800)
1104
        ;; baud[5]: 9600
1105
        .byte BAUD_HIGH(9600)
1106
        .byte BAUD_LOW(9600)
1107
        ;; baud[6]: 19200
1108
        .byte BAUD_HIGH(19200)
1109
        .byte BAUD_LOW(19200)
1110
        ;; baud[7]: 38400
1111
        .byte BAUD_HIGH(38400)
1112
        .byte BAUD_LOW(38400)
1113
        ;; baud[8]: 57600
1114
        .byte BAUD_HIGH(57600)
1115
        .byte BAUD_LOW(57600)
1116
        ;; baud[9]: 115200
1117
        .byte BAUD_HIGH(115200)
1118
        .byte BAUD_LOW(115200)
1119
 
1120
desc_device:
1121
        .byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
1122
        .byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
1123
;;; The "real" device id, which must match the host driver, is that
1124
;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
1125
 
1126
desc_config1:
1127
        .byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
1128
        .byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
1129
        .byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
1130
        .byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
1131
 
1132
desc_strings:
1133
        .word string_langids, string_mfg, string_product, string_serial
1134
desc_strings_end:
1135
 
1136
string_langids: .byte string_langids_end-string_langids
1137
        .byte 3
1138
        .word 0
1139
string_langids_end:
1140
 
1141
        ;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
1142
        ;; *that* is a pain in the ass to encode. And they are little-endian
1143
        ;; too. Use this perl snippet to get the bytecodes:
1144
        /* while (<>) {
1145
            @c = split(//);
1146
            foreach $c (@c) {
1147
             printf("0x%02x, 0x00, ", ord($c));
1148
            }
1149
           }
1150
        */
1151
 
1152
string_mfg:     .byte string_mfg_end-string_mfg
1153
        .byte 3
1154
;       .byte "ACME usb widgets"
1155
        .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
1156
string_mfg_end:
1157
 
1158
string_product: .byte string_product_end-string_product
1159
        .byte 3
1160
;       .byte "ACME USB serial widget"
1161
        .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
1162
string_product_end:
1163
 
1164
string_serial:  .byte string_serial_end-string_serial
1165
        .byte 3
1166
;       .byte "47"
1167
        .byte 0x34, 0x00, 0x37, 0x00
1168
string_serial_end:
1169
 
1170
;;; ring buffer memory
1171
        ;; tx_ring_in+1 is where the next input byte will go
1172
        ;; [tx_ring_out] has been sent
1173
        ;; if tx_ring_in == tx_ring_out, theres no work to do
1174
        ;; there are (tx_ring_in - tx_ring_out) chars to be written
1175
        ;; dont let _in lap _out
1176
        ;;   cannot inc if tx_ring_in+1 == tx_ring_out
1177
        ;;  write [tx_ring_in+1] then tx_ring_in++
1178
        ;;   if (tx_ring_in+1 == tx_ring_out), overflow
1179
        ;;   else tx_ring_in++
1180
        ;;  read/send [tx_ring_out+1], then tx_ring_out++
1181
 
1182
        ;; rx_ring_in works the same way
1183
 
1184
        .org 0x1000
1185
tx_ring:
1186
        .skip 0x100             ; 256 bytes
1187
rx_ring:
1188
        .skip 0x100             ; 256 bytes
1189
 
1190
 
1191
        .END
1192
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.