-
Notifications
You must be signed in to change notification settings - Fork 0
/
usbuhci.c
2697 lines (2143 loc) · 96.8 KB
/
usbuhci.c
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
********************************************************************
* USB stack and host controller driver for SGI IRIX 6.5 *
* *
* Programmed by BSDero *
* bsdero at gmail dot com *
* 2011/2012 *
* *
* *
* File: usbuhci.c *
* Description: UHCI host controller driver *
* *
********************************************************************
*******************************************************************************************************
* FIXLIST (latest at top) *
*-----------------------------------------------------------------------------------------------------*
* Author MM-DD-YYYY Description *
*-----------------------------------------------------------------------------------------------------*
* BSDero 14-02-2013 -Added UHCI priority queues Fixed pipe_t structure *
* -Added PIPE creation and basic functionality for USB CMD SetAddress *
* -Added Queue head priorities lists *
* *
* BSDero 08-03-2012 -Fixed wrong class in trace messages *
* -Added _diaginfo_ string in startup trace messages *
* *
* BSDero 07-23-2012 -Usage usbhub mutex instead usbcore mutex *
* -Added advice to usbhub in port connect/disconnect *
* -Added log of kernel module address *
* *
* BSDero 07-12-2012 -Updated uhci_get_info(), uhci_info_get(), uhci_get_port() *
* -Implemented uhci_port_action(), uhci_set_roothub() *
* -Deleted register_hcd_driver() and unregister_hcd_driver() *
* *
* BSDero 07-10-2012 -Added uhci_process_event() and uhci_process_event_from_usbcore() *
* *
* BSDero 07-05-2012 -Send events to hub implemented *
* *
* BSDero 06-26-2012 -Fixed issues in port reset, added mutex *
* *
* BSDero 06-21-2012 -Updated uhci_hub_info() *
* *
* BSDero 06-15-2012 -Implemented get information from PCI bus. Added uhci_restart(), *
* uhci_port_reset. *
* -Added port polling function *
* -Fixed crashes by using a mutex in usbcore module during attach *
* *
* BSDero 06-03-2012 -Implemented get_usbcore(), register_hcd_driver(), unregister_hcd_driver *
* *
* BSDero 05-03-2012 -Initial version, parts rippen from existing code from a previous file *
* *
*******************************************************************************************************
*/
#include <sys/types.h>
#include <sys/cpu.h>
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/cred.h>
#include <ksys/ddmap.h>
#include <sys/poll.h>
#include <sys/invent.h>
#include <sys/debug.h>
#include <sys/sbd.h>
#include <sys/kmem.h>
#include <sys/edt.h>
#include <sys/dmamap.h>
#include <sys/hwgraph.h>
#include <sys/iobus.h>
#include <sys/iograph.h>
#include <sys/param.h>
#include <sys/pio.h>
#include <sys/sema.h>
#include <sys/ddi.h>
#include <sys/errno.h>
#include <sys/ksynch.h>
#include <sys/atomic_ops.h>
#include <sys/PCI/PCI_defs.h>
#include <sys/PCI/pciio.h>
#include <sys/cmn_err.h>
#include <sys/mload.h>
#include <string.h>
#include <ctype.h>
/*
*******************************************************************************************************
* Headers *
*******************************************************************************************************
*/
#include "config.h"
#include "usbioctl.h"
#include "usb.h"
#include "usbhc.h" /* Host controller defines */
/*
*******************************************************************************************************
* Global for all included sources *
*******************************************************************************************************
*/
USB_trace_class_t global_trace_class = { 12, TRC_ALL};
/*
*******************************************************************************************************
* Included sources *
*******************************************************************************************************
*/
#include "kmaddr.c" /* module initial address */
#include "trace.c" /* trace macros */
#include "kutils.c" /* kernel util functions */
#include "dumphex.c" /* dump utility */
#include "list.c" /* list utility */
#include "gc.c" /* memory lists utility */
#include "dma.c" /* dma lists utility */
#include "queue.c" /* circular queue utility */
#include "uhcireg.h" /* uhci register defines */
/*
*******************************************************************************************************
* Supported UHCI devices *
*******************************************************************************************************
*/
static struct{
uint32_t device_id;
uchar_t *controller_description;
}uhci_descriptions[]={
0x26888086, "Intel 631XESB/632XESB/3100 USB controller USB-1",
0x26898086,"Intel 631XESB/632XESB/3100 USB controller USB-2",
0x268a8086,"Intel 631XESB/632XESB/3100 USB controller USB-3",
0x268b8086,"Intel 631XESB/632XESB/3100 USB controller USB-4",
0x70208086,"Intel 82371SB (PIIX3) USB controller",
0x71128086,"Intel 82371AB/EB (PIIX4) USB controller",
0x24128086,"Intel 82801AA (ICH) USB controller",
0x24228086,"Intel 82801AB (ICH0) USB controller",
0x24428086,"Intel 82801BA/BAM (ICH2) USB controller USB-A",
0x24448086,"Intel 82801BA/BAM (ICH2) USB controller USB-B",
0x24828086,"Intel 82801CA/CAM (ICH3) USB controller USB-A",
0x24848086,"Intel 82801CA/CAM (ICH3) USB controller USB-B",
0x24878086,"Intel 82801CA/CAM (ICH3) USB controller USB-C",
0x24c28086,"Intel 82801DB (ICH4) USB controller USB-A",
0x24c48086,"Intel 82801DB (ICH4) USB controller USB-B",
0x24c78086,"Intel 82801DB (ICH4) USB controller USB-C",
0x24d28086,"Intel 82801EB (ICH5) USB controller USB-A",
0x24d48086,"Intel 82801EB (ICH5) USB controller USB-B",
0x24d78086,"Intel 82801EB (ICH5) USB controller USB-C",
0x24de8086,"Intel 82801EB (ICH5) USB controller USB-D",
0x26588086,"Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-A",
0x26598086,"Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-B",
0x265a8086,"Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-C",
0x265b8086,"Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-D",
0x27c88086,"Intel 82801G (ICH7) USB controller USB-A",
0x27c98086,"Intel 82801G (ICH7) USB controller USB-B",
0x27ca8086,"Intel 82801G (ICH7) USB controller USB-C",
0x27cb8086,"Intel 82801G (ICH7) USB controller USB-D",
0x28308086,"Intel 82801H (ICH8) USB controller USB-A",
0x28318086,"Intel 82801H (ICH8) USB controller USB-B",
0x28328086,"Intel 82801H (ICH8) USB controller USB-C",
0x28348086,"Intel 82801H (ICH8) USB controller USB-D",
0x28358086,"Intel 82801H (ICH8) USB controller USB-E",
0x29348086,"Intel 82801I (ICH9) USB controller",
0x29358086,"Intel 82801I (ICH9) USB controller",
0x29368086,"Intel 82801I (ICH9) USB controller",
0x29378086,"Intel 82801I (ICH9) USB controller",
0x29388086,"Intel 82801I (ICH9) USB controller",
0x29398086,"Intel 82801I (ICH9) USB controller",
0x3a348086,"Intel 82801JI (ICH10) USB controller USB-A",
0x3a358086,"Intel 82801JI (ICH10) USB controller USB-B",
0x3a368086,"Intel 82801JI (ICH10) USB controller USB-C",
0x3a378086,"Intel 82801JI (ICH10) USB controller USB-D",
0x3a388086,"Intel 82801JI (ICH10) USB controller USB-E",
0x3a398086,"Intel 82801JI (ICH10) USB controller USB-F",
0x719a8086,"Intel 82443MX USB controller",
0x76028086,"Intel 82372FB/82468GX USB controller",
0x30381106,"VIA VT6212 UHCI USB 1.0 controller",
0 ,NULL
};
/****************************************************************
* uhci structs and flags
****************************************************************/
#define UHCI_CF_VENDOR_ID 0x00
#define UHCI_CF_DEVICE_ID 0x02
#define UHCI_CF_COMMAND 0x04
#define UHCI_CF_STATUS 0x06
#define UHCI_CF_REVISION_ID 0x08
#define UHCI_CF_CLASS_CODE 0x09
#define UHCI_CF_CACHE_LINE_SIZE 0x0c
#define UHCI_CF_LATENCY_TIME 0x0d
#define UHCI_CF_HEADER_TYPE 0x0e
#define UHCI_CF_BIST 0x0f
#define UHCI_CF_MMAP_IO_BASE_ADDR 0x10
#define UHCI_CF_CIS_BASE_ADDR 0x14
#define UHCI_CF_BASE_ADDR 0x20
#define UHCI_CF_CARDBUS_CIS_PTR 0x28
#define UHCI_CF_SSID 0x2c
#define UHCI_CF_PWR_MGMT_CAPS 0x34
#define UHCI_CF_INTERRUPT_LINE 0x3c
#define UHCI_CF_INTERRUPT_PIN 0x3d
#define UHCI_NUM_CONF_REGISTERS 0xc2
#define UHCI_NUM_IO_REGISTERS 0x14
#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
#define UHCISTS(sc) UREAD2(sc, UHCI_STS)
/*
*******************************************************************************************************
* Specific UHCI Data structures *
*******************************************************************************************************
*/
#define TD_CTRL_SPD (0x20000000) /* Short Packet Detect */
#define TD_CTRL_C_ERR_MASK (0x18000000) /* Error Counter bits */
#define TD_CTRL_C_ERR_SHIFT 27
#define TD_CTRL_LS (0x04000000) /* Low Speed Device */
#define TD_CTRL_IOS (0x02000000) /* Isochronous Select */
#define TD_CTRL_IOC (0x01000000) /* Interrupt on Complete */
#define TD_CTRL_ACTIVE (0x00800000) /* TD Active */
#define TD_CTRL_STALLED (0x00400000) /* TD Stalled */
#define TD_CTRL_DBUFERR (0x00200000) /* Data Buffer Error */
#define TD_CTRL_BABBLE (0x00100000) /* Babble Detected */
#define TD_CTRL_NAK (0x00080000) /* NAK Received */
#define TD_CTRL_CRCTIMEO (0x00040000) /* CRC/Time Out Error */
#define TD_CTRL_BITSTUFF (0x00020000) /* Bit Stuff Error */
#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */
#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \
TD_CTRL_BITSTUFF)
#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
#define TD_TOKEN_DEVADDR_SHIFT 8
#define TD_TOKEN_TOGGLE_SHIFT 19
#define TD_TOKEN_TOGGLE (1 << 19)
#define TD_TOKEN_EXPLEN_SHIFT 21
#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */
#define TD_TOKEN_PID_MASK 0xFF
#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
TD_TOKEN_EXPLEN_SHIFT)
#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \
1) & TD_TOKEN_EXPLEN_MASK)
typedef struct{
uint32_t links[1024];
} uhci_framelist_t;
typedef struct{
uint32_t link;
uint32_t status; //8
uint32_t token;
uint32_t buffer; //16
uint32_t r0, r1, r2, r3, r4; //36 bytes
uint32_t this;//40
uint32_t tags, flags; //48
void *klink;
void *kbuffer;
}uhci_td_t; /* size: 64 bytes */
typedef struct{
uint32_t link;
uint32_t element;
/* kernel address */
uint32_t r0, r1;//16
uint32_t this;
uint32_t prior_link; //24
void *kprior_link; //32
void *klink; //40
void *kelement; //48
}uhci_qh_t; /* size: 48 bytes */
struct usb_uhci_s {
struct usb_s usb;
uint16_t iobase;
uhci_qh_t *control_qh, *bulk_qh;
uhci_framelist_t *framelist;
};
struct usb_uhci_s usb_uhci_t;
struct uhci_pipe {
uhci_qh_t qh;
uhci_td_t *next_td;
struct usb_pipe pipe;
uint16_t iobase;
uchar_t toggle;
};
struct uhci_pipe uhci_pipe_t;
typedef struct {
uhci_qh_t qh;
uhci_td_t td[6];
uchar_t buffer[512];
}uhci_control_chain_t;
#define UHCI_PTR_BITS 0x000F
#define UHCI_PTR_TERM 0x0001
#define UHCI_PTR_QH 0x0002
#define UHCI_PTR_DEPTH 0x0004
#define UHCI_PTR_BREADTH 0x0000
/*
*******************************************************************************************************
* UHCI transfer queues *
*******************************************************************************************************
*/
typedef struct{
#define UHCI_QH1 0
#define UHCI_QH2 1
#define UHCI_QH4 2
#define UHCI_QH8 3
#define UHCI_QH16 4
#define UHCI_QH32 5
#define UHCI_QH64 6
#define UHCI_QH128 7
#define UHCI_QHCTL UHCI_QH128
#define UHCI_QH1S 8
#define UHCI_QH2S 9
#define UHCI_QH4S 10
#define UHCI_QH8S 11
#define UHCI_QH16S 12
#define UHCI_QH32S 13
#define UHCI_QH64S 14
#define UHCI_QH128S 15
#define UHCI_QHCTLS UHCI_QH128S
#define UHCI_QH1E 16
#define UHCI_QH2E 17
#define UHCI_QH4E 18
#define UHCI_QH8E 19
#define UHCI_QH16E 20
#define UHCI_QH32E 21
#define UHCI_QH64E 22
#define UHCI_QH128E 23
#define UHCI_QHCTLE UHCI_QH128E
#define UHCI_QHNUM 8
uhci_qh_t queue_heads[UHCI_QHNUM*3]; /* we have 8 queues */
uhci_qh_t term_qh;
uhci_td_t term_td;
}uhci_transfer_queues_t;
/*
*******************************************************************************************************
* UHCI instance *
*******************************************************************************************************
*/
typedef struct {
device_header_t device_header;
vertex_hdl_t ps_conn; /* connection for pci services */
vertex_hdl_t ps_vhdl; /* backpointer to device vertex */
vertex_hdl_t ps_charv; /* backpointer to device vertex */
USB_func_t ps_event_func; /* function to USBcore event */
uchar_t *ps_cfg; /* cached ptr to my config regs */
uchar_t *ps_regs; /* cached ptr to my regs */
uchar_t *pci_io_caps;
uint32_t sc_offs;
pciio_piomap_t ps_cmap; /* piomap (if any) for ps_cfg */
pciio_piomap_t ps_rmap; /* piomap (if any) for ps_regs */
unsigned ps_sst; /* driver "software state" */
#define usbuhci_SST_RX_READY (0x0001)
#define usbuhci_SST_TX_READY (0x0002)
#define usbuhci_SST_ERROR (0x0004)
#define usbuhci_SST_INUSE (0x8000)
pciio_intr_t ps_intr; /* pciio intr for INTA and INTB */
pciio_dmamap_t ps_ctl_dmamap; /* control channel dma mapping */
pciio_dmamap_t ps_str_dmamap; /* stream channel dma mapping */
struct pollhead *ps_pollhead; /* for poll() */
int ps_blocks; /* block dev size in NBPSCTR blocks */
uint32_t ps_event;
uint8_t ps_noport;
uint32_t ps_eintrs;
toid_t ps_itimeout;
uchar_t ps_stopped_timeout;
pciio_info_t ps_pciio_info_device;
usbcore_instance_t *usbcore;
usbhub_instance_t *roothub;
uhci_framelist_t *framelist;
uhci_transfer_queues_t *tq;
uhci_qh_t *control_qh;
uhci_qh_t *bulk_qh;
int debug_port;
uint32_t debug_port_reset_delay;
uint32_t debug_port_reset_recovery_delay;
uint32_t debug_port_root_reset_delay;
}usbuhci_instance_t;
/*
*******************************************************************************************************
* Global variables *
*******************************************************************************************************
*/
int usbuhci_devflag = D_MP;
char *usbuhci_mversion = M_VERSION; /* for loadable modules */
int usbuhci_inuse = 0; /* number of "usbuhci" devices open */
gc_list_t gc_list;
usbuhci_instance_t *global_soft = NULL;
dma_list_t dma_list;
/*
*******************************************************************************************************
* Helper functions for usbcore *
*******************************************************************************************************
*/
void uhci_ports_poll( usbuhci_instance_t *soft);
usbcore_instance_t *get_usbcore();
/*
*******************************************************************************************************
* Callback functions for usbcore *
*******************************************************************************************************
*/
int uhci_reset( void *hcd);
int uhci_start( void *hcd);
int uhci_init( void *hcd);
int uhci_stop( void *hcd);
int uhci_shutdown( void *hcd);
int uhci_suspend( void *hcd);
int uhci_resume( void *hcd);
int uhci_status( void *hcd);
void uhci_free_pipe( void *hcd, struct usb_pipe *pipe);
usb_pipe_t *uhci_alloc_control_pipe( void *hcd, int port_num, td_addr_t *td_addr);
struct usb_pipe *uhci_alloc_bulk_pipe( void *hcd, struct usb_pipe *pipe, struct usb_endpoint_descriptor *descriptor);
int uhci_send_control( void *hcd, struct usb_pipe *pipe, int dir, void *cmd, int cmdsize, void *data, int datasize);
int uhci_set_address( void *hcd, struct usb_pipe *pipe, int dir, void *cmd, int cmdsize, void *data, int datasize);
int uhci_usb_send_bulk( void *hcd, struct usb_pipe *pipe, int dir, void *data, int datasize);
int uhci_alloc_intr_pipe( void *hcd, struct usb_pipe *pipe, struct usb_endpoint_descriptor *descriptor);
int uhci_usb_poll_intr( void *hcd, struct usb_pipe *pipe, void *data);
int uhci_ioctl( void *hcd, int cmd, void *uarg);
int uhci_set_trace_level( void *hcd, void *trace_level);
int uhci_hub_info( void *hcd, void *info);
int uhci_port_action( void *hcd, int port, int action);
uint32_t uhci_get_port( void *hcd, int port);
int uhci_set_roothub(void *hcd, void *roothub);
int uhci_set_debug_values( void *hcd, void *pv);
/*
*******************************************************************************************************
* Methods for usbcore *
*******************************************************************************************************
*/
hcd_methods_t uhci_methods={
uhci_reset,
uhci_start,
uhci_init,
uhci_stop,
uhci_shutdown,
uhci_suspend,
uhci_resume,
uhci_status,
uhci_free_pipe,
uhci_alloc_control_pipe,
uhci_alloc_bulk_pipe,
uhci_send_control,
uhci_set_address,
uhci_usb_send_bulk,
uhci_alloc_intr_pipe,
uhci_usb_poll_intr,
uhci_ioctl,
uhci_set_trace_level,
uhci_hub_info,
uhci_port_action,
uhci_get_port,
uhci_set_roothub,
uhci_set_debug_values,
0x00000000
};
int uhci_process_event( void *origin, void *dest, int event_id, void *arg);
int uhci_process_event_from_usbcore( void *dest, int event_id, void *arg0, void *arg1, void *arg2);
module_header_t uhci_header={
USB_MOD_UHCI,
"usbuhci",
"USB Host Controller Interface (USB 1.0)",
"usbuhci.o",
USB_DRIVER_IS_HCD,
{
uhci_set_trace_level,
uhci_process_event,
uhci_process_event_from_usbcore,
0x0000
}
};
/*
*******************************************************************************************************
* Entry points *
*******************************************************************************************************
*/
void usbuhci_init(void);
int usbuhci_unload(void);
int usbuhci_reg(void);
int usbuhci_unreg(void);
int usbuhci_attach(vertex_hdl_t conn);
int usbuhci_detach(vertex_hdl_t conn);
static pciio_iter_f usbuhci_reloadme;
static pciio_iter_f usbuhci_unloadme;
int usbuhci_open(dev_t *devp, int oflag, int otyp, cred_t *crp);
int usbuhci_close(dev_t dev, int oflag, int otyp, cred_t *crp);
int usbuhci_ioctl(dev_t dev, int cmd, void *arg, int mode, cred_t *crp, int *rvalp);
int usbuhci_read(dev_t dev, uio_t * uiop, cred_t *crp);
int usbuhci_write(dev_t dev, uio_t * uiop,cred_t *crp);
int usbuhci_strategy(struct buf *bp);
int usbuhci_poll(dev_t dev, short events, int anyyet,
short *reventsp, struct pollhead **phpp, unsigned int *genp);
int usbuhci_map(dev_t dev, vhandl_t *vt, off_t off, size_t len, uint_t prot);
int usbuhci_unmap(dev_t dev, vhandl_t *vt);
void usbuhci_dma_intr(intr_arg_t arg);
static error_handler_f usbuhci_error_handler;
void usbuhci_halt(void);
int usbuhci_size(dev_t dev);
int usbuhci_print(dev_t dev, char *str);
/*
*******************************************************************************************************
* Host controller specific hardware functions *
*******************************************************************************************************
*/
/*
PUT YOUR FUNCTIONS HERE
*
*
*
*
*
*
*/
usbcore_instance_t *get_usbcore(){
vertex_hdl_t vhdl;
usbcore_instance_t *usbcore;
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
TRACE( class | TRC_START_END, 10, "start", "");
if (GRAPH_SUCCESS != hwgraph_traverse(GRAPH_VERTEX_NONE, "/usb/usbcore", &vhdl)){
TRACEWAR( class | TRC_WARNING,
"hwgraph_traverse() could not follow /usb/usbcore path", "");
return(NULL);
}
usbcore = (usbcore_instance_t *) device_info_get( vhdl);
if( usbcore == NULL){
TRACEWAR( class | TRC_WARNING,
"could not get usbcore information from device_info_get()", "");
}
TRACE( class | TRC_START_END, 10, "end", "");
return( usbcore);
}
uchar_t uhci_restart( usbuhci_instance_t *soft){
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
int rc;
TRACE( class | TRC_START_END, 10, "start", "");
if ( UREAD2( soft, UHCI_CMD) & UHCI_CMD_RS) {
TRACE( class, 10, "Already started", "");
rc = 0;
goto uhci_restart_exit;
}
TRACE( class | TRC_START_END, 10, "restarting", "");
/* Reload fresh base address */
/* UWRITE4(sc, UHCI_FLBASEADDR, buf_res.physaddr);*/
/*
* Assume 64 byte packets at frame end and start HC controller:
*/
UHCICMD(soft, (UHCI_CMD_MAXP | UHCI_CMD_RS));
/* wait 10 milliseconds */
USECDELAY( 10000);
/* check that controller has started */
if (UREAD2(soft, UHCI_STS) & UHCI_STS_HCH) {
TRACE( class, 10, "failed", "");
rc = 1;
goto uhci_restart_exit;
}
rc = 0;
uhci_restart_exit:
TRACE( class | TRC_START_END, 10, "end", "");
return (rc);
}
int uhci_port_reset(usbuhci_instance_t *soft, unsigned int index){
unsigned int port, x, lim, port_mapped;
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
int rc;
TRACE( class | TRC_START_END, 10, "start", "");
TRACE( class, 12, "hcd driver = '%s'", soft->device_header.module_header->short_description);
port_mapped = soft->device_header.spec_device_instance_id * 2 + (index % 2);
TRACE( class, 12, "port mapped=%d", port_mapped);
TRACE( class, 10, "soft=%x, uhciport=%d", soft, index);
if (index == 1)
port = UHCI_PORTSC1;
else if (index == 2)
port = UHCI_PORTSC2;
else
return ( 1);
/*
* Before we do anything, turn on SOF messages on the USB
* BUS. Some USB devices do not cope without them!
*/
x = URWMASK(UREAD2(soft, port));
UWRITE2(soft, port, x | UHCI_PORTSC_PR);
USECDELAY( soft->debug_port_root_reset_delay);
x = URWMASK(UREAD2(soft, port));
UWRITE2(soft, port, x & ~UHCI_PORTSC_PR);
/*
* This delay needs to be exactly 100us, else some USB devices
* fail to attach!
*/
USECDELAY( soft->debug_port_reset_recovery_delay);
x = URWMASK(UREAD2(soft, port));
/* UWRITE2(soft, port, x & ~UHCI_PORTSC_CSC & ~UHCI_PORTSC_POEDC);*/
UWRITE2(soft, port, x | UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC);
for (lim = 0; lim < 500; lim++) {
x = UREAD2(soft, port);
TRACE( class, 4, "uhci port %d iteration %u, status = 0x%04x",
index, lim, x);
TRACE( class, 12, "port mapped=%d", port_mapped);
TRACE( class, 10, "soft=%x, uhciport=%d", soft, index);
if (!(x & UHCI_PORTSC_CCS)) {
/*
* No device is connected (or was disconnected
* during reset). Consider the port reset.
* The delay must be long enough to ensure on
* the initial iteration that the device
* connection will have been registered. 50ms
* appears to be sufficient, but 20ms is not.
*/
TRACE( class, 4, "uhci port %d loop %u, device detached",
index, lim);
rc = 0;
goto uhci_portreset_done;
}
if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
/*
* Port enabled changed and/or connection
* status changed were set. Reset either or
* both raised flags (by writing a 1 to that
* bit), and wait again for state to settle.
*/
UWRITE2(soft, port, URWMASK(x) |
(x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
TRACE( class, 4, "CSC still enabled, continue",
index, lim);
USECDELAY(10);
continue;
}
if (x & UHCI_PORTSC_PE) {
/* port is enabled */
TRACE( class, 2, "port enabled", "");
rc = 0;
goto uhci_portreset_done;
}
UWRITE2(soft, port, URWMASK(x) | UHCI_PORTSC_PE);
USECDELAY( soft->debug_port_reset_delay);
}
TRACE( class, 4, "uhci port %d reset timed out", index);
rc = 1;
uhci_portreset_done:
TRACE( class | TRC_START_END, 10, "end", "");
return (rc);
}
void uhci_ports_poll( usbuhci_instance_t *soft){
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
uint16_t reg;
usbcore_instance_t *usbcore = soft->usbcore;
usbhub_instance_t *roothub = soft->roothub;
hub_methods_t *hub_methods;
uint32_t port_num;
int event = 0, rc = 0;
if( soft == NULL)
return;
if( soft->ps_itimeout == 0){
soft->ps_stopped_timeout = 0;
return;
}
MUTEX_LOCK( &roothub->uhci_mutex, -1);
reg = UREAD2( soft, UHCI_PORTSC1);
if( reg & UHCI_PORTSC_CSC){
port_num = soft->device_header.spec_device_instance_id * 2 + 1;
TRACE( class, 10, "portnum %d changed", port_num);
UWRITE2( soft, UHCI_PORTSC1, reg);
if( reg & UHCI_PORTSC_CCS){
TRACE( class, 10, "device connected", "");
event = USB_EVENT_PORT_CONNECT;
uhci_port_reset( soft, 1);
}else{
TRACE( class, 10, "device disconnected", "");
event = USB_EVENT_PORT_DISCONNECT;
}
}
reg = UREAD2( soft, UHCI_PORTSC2);
if( reg & UHCI_PORTSC_CSC){
port_num = soft->device_header.spec_device_instance_id * 2;
TRACE( class, 10, "portnum %d changed", port_num);
UWRITE2( soft, UHCI_PORTSC2, reg);
if( reg & UHCI_PORTSC_CCS){
TRACE( class, 10, "device connected", "");
event = USB_EVENT_PORT_CONNECT;
uhci_port_reset( soft, 2);
}else{
TRACE( class, 10, "device disconnected", "");
event = USB_EVENT_PORT_DISCONNECT;
}
}
MUTEX_UNLOCK( &roothub->uhci_mutex);
hub_methods = roothub->device_header.methods;
if( event != 0){
TRACE( class, 10, "soft=%x, port=%d", soft, port_num);
hub_methods->process_event_from_hcd( (void *) soft, (void *) roothub, event,
(void *) &port_num, NULL);
}
/*
if( soft->ps_itimeout == 0){
soft->ps_stopped_timeout = 0;
return;
}else{
*/
soft->ps_itimeout = itimeout(uhci_ports_poll, soft, drv_usectohz(100000), 0);
/*}*/
}
/*
*******************************************************************************************************
* Host controller callback implementation for USBcore *
*******************************************************************************************************
*/
int uhci_reset( void *hcd){
usbuhci_instance_t *soft = ( usbuhci_instance_t *) hcd;
int rc = 0;
int n;
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
TRACE( class | TRC_START_END, 10, "start", "");
TRACE( class, 12, "hcd driver = '%s'", soft->device_header.module_header->short_description);
/* disable interrupts */
UWRITE2(soft, UHCI_INTR, 0);
/* global reset */
UHCICMD(soft, UHCI_CMD_GRESET);
/* wait */
USECDELAY( 10000);
/* terminate all transfers */
UHCICMD(soft, UHCI_CMD_HCRESET);
/* the reset bit goes low when the controller is done */
n = 100;
while (n--) {
/* wait one millisecond */
USECDELAY( 1000);
if (!(UREAD2(soft, UHCI_CMD) & UHCI_CMD_HCRESET)) {
rc = 0;
goto done_1;
}
}
rc = 1;
TRACE( class, 8, "controller did not reset", "");
done_1:
TRACE( class | TRC_START_END, 10, "end, rc = %d", rc);
return( rc);
}
int uhci_start( void *hcd){
usbuhci_instance_t *soft = ( usbuhci_instance_t *) hcd;
int rc;
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
TRACE( class | TRC_START_END, 10, "start", "");
TRACE( class, 12, "hcd driver = '%s'", soft->device_header.module_header->short_description);
soft->ps_stopped_timeout = 1;
soft->ps_itimeout = itimeout(uhci_ports_poll, soft, drv_usectohz(200000), 0);
TRACE( class, 12, "ps_itimeout = %d", soft->ps_itimeout);
TRACE( class | TRC_START_END, 10, "end", "");
return( rc);
}
int uhci_init( void *hcd){
usbuhci_instance_t *soft = ( usbuhci_instance_t *) hcd;
uhci_transfer_queues_t *tq;
int rc, i;
uint64_t class = TRC_HELPER | TRC_MOD_UHCI;
dma_node_t *dma_node_tq;
dma_node_t *dma_node_fl;
uhci_framelist_t *fl;
TRACE( class | TRC_START_END, 10, "start", "");
TRACE( class, 12, "hcd driver = '%s'", soft->device_header.module_header->short_description);
rc = uhci_reset( hcd);
dma_list_init( &dma_list);
/* dma alloc of transfer queues */
dma_node_tq = dma_alloc( soft->ps_conn, &dma_list, sizeof(uhci_transfer_queues_t));
/* dma alloc of framelist */
dma_node_fl = dma_alloc( soft->ps_conn, &dma_list, sizeof(uhci_framelist_t));
if( dma_node_tq == NULL || dma_node_fl == NULL){
TRACE( class, 4, "Error in dma_alloc()!!!", "");
return( -1);
}
TRACE( class, 10, "dma reserved", "");
fl = ( uhci_framelist_t *) dma_node_fl->mem;
tq = ( uhci_transfer_queues_t *) dma_node_tq->mem;
memset( tq, 0, sizeof( uhci_transfer_queues_t ));
memset( fl, 0, sizeof( uhci_framelist_t ));
/* Work around for PIIX errata */
/* create the next terminator TD and QH
* term_td --> END OF QUEUE
* term_qh --> term_td
* At end we get a structure like this: term_qh->term_td->EOQ (END OF QUEUE)
*/
tq->term_td.link = UHCI_PTR_TERM;
tq->term_td.token = ( uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN);
tq->term_td.klink = (void *) UHCI_PTR_TERM;
tq->term_qh.link = UHCI_PTR_TERM;
tq->term_qh.element = kaddr_2_daddr( dma_node_tq->daddr, dma_node_tq->kaddr, &tq->term_td);
tq->term_qh.klink = (void *) UHCI_PTR_TERM;
tq->term_qh.kprior_link = (void *) UHCI_PTR_TERM;
tq->term_qh.this = kaddr_2_daddr( dma_node_tq->daddr, dma_node_tq->kaddr, &tq->term_qh);
/* Build schedule queues
*
* make the first queue point to the term QH
* queue_heads[UHCI_QH1].link->term_qh.link->EOQ
* but the element field should point to our queue.
* A start and an end queue heads are added in each queue.
* RQUEUE ---> start queue ---> end queue --> term.qh
*
* */
tq->queue_heads[UHCI_QH1].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->term_qh) | UHCI_PTR_QH;
tq->queue_heads[UHCI_QH1].element = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[UHCI_QH1S]) | UHCI_PTR_QH;
tq->queue_heads[UHCI_QH1].klink = (void *) &tq->term_qh;
tq->queue_heads[UHCI_QH1].kelement = (void *) &tq->queue_heads[UHCI_QH1S];
/* setup start qeueu head */
tq->queue_heads[UHCI_QH1S].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[UHCI_QH1E]) | UHCI_PTR_QH;
tq->queue_heads[UHCI_QH1S].element = UHCI_PTR_TERM;
tq->queue_heads[UHCI_QH1S].klink = (void *) &tq->queue_heads[UHCI_QH1E];
tq->queue_heads[UHCI_QH1S].kelement = (void *) UHCI_PTR_TERM;
tq->queue_heads[UHCI_QH1S].prior_link = UHCI_PTR_TERM;
tq->queue_heads[UHCI_QH1S].kprior_link = (void *) NULL;
tq->queue_heads[UHCI_QH1S].this = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[UHCI_QH1S]) ;
/* setup start end head */
tq->queue_heads[UHCI_QH1E].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->term_qh) | UHCI_PTR_QH;
tq->queue_heads[UHCI_QH1E].element = UHCI_PTR_TERM;
tq->queue_heads[UHCI_QH1E].klink = (void *) &tq->term_qh;
tq->queue_heads[UHCI_QH1E].kelement = (void *) UHCI_PTR_TERM;
tq->queue_heads[UHCI_QH1E].prior_link = tq->queue_heads[UHCI_QH1S].this;
tq->queue_heads[UHCI_QH1E].kprior_link = (void *) &tq->queue_heads[UHCI_QH1S];
tq->queue_heads[UHCI_QH1E].this = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[UHCI_QH1E]) ;
/* Create the next queue heads this way: each one should be pointing to the previous one
* creating a pool of queues like this:
* queue_heads[UHCI_QH2]->queue_heads[UHCI_QH1]
* queue_heads[UHCI_QH4]->queue_heads[UHCI_QH2]->queue_heads[UHCI_QH1]
* queue_heads[UHCI_QH8]->queue_heads[UHCI_QH4]->queue_heads[UHCI_QH2]->queue_heads[UHCI_QH1]
* ...
* ...
* until we got the last queue
* queue_heads[UHCI_128]->queue_heads[UHCI_QH64]->....queue_heads[UHCI_QH2]->queue_heads[UHCI_QH1]
*/
for( i = 1; i < UHCI_QHNUM; i++){
tq->queue_heads[i].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[i-1]) | UHCI_PTR_QH;
tq->queue_heads[i].element = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[i+8]) | UHCI_PTR_QH;
tq->queue_heads[i].klink = (void *) &tq->queue_heads[i-1];
tq->queue_heads[i].kelement = (void *) &tq->queue_heads[i+8];
tq->queue_heads[i+8].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[i+16]) | UHCI_PTR_QH;
tq->queue_heads[i+8].element = UHCI_PTR_TERM;
tq->queue_heads[i+8].klink = (void *) &tq->queue_heads[i+16];
tq->queue_heads[i+8].kelement = (void *) UHCI_PTR_TERM;
tq->queue_heads[i+8].prior_link = UHCI_PTR_TERM;
tq->queue_heads[i+8].kprior_link = (void *) NULL;
tq->queue_heads[i+8].this = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[i+8]) ;
tq->queue_heads[i+16].link = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->term_qh) | UHCI_PTR_QH;
tq->queue_heads[i+16].element = UHCI_PTR_TERM;
tq->queue_heads[i+16].klink = (void *) &tq->term_qh;
tq->queue_heads[i+16].kelement = (void *) UHCI_PTR_TERM;
tq->queue_heads[i+16].prior_link = tq->queue_heads[i+8].this;
tq->queue_heads[i+16].kprior_link = (void *) &tq->queue_heads[i+8].this;
tq->queue_heads[i+16].this = kaddr_2_daddr( dma_node_tq->daddr,
dma_node_tq->kaddr, &tq->queue_heads[i+16]);
}
/* Now assign pointers for each queue in list, this should be completed this way:
*
* links[0]->queue_heads[UHCI_QH1]
* links[1]->queue_heads[UHCI_QH2]->queue_heads[UHCI_QH1]