xref: /inferno-os/appl/lib/usb/usbmct.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1#
2# Copyright © 2002 Vita Nuova Holdings Limited
3#
4implement UsbDriver;
5
6# MCT RS232 USB driver
7# 'Documentation' mined from NetBSD
8
9include "sys.m";
10	sys: Sys;
11include "usb.m";
12	usb: Usb;
13
14UMCT_SET_REQUEST: con 1640;
15
16REQ_SET_BAUD_RATE: con 5;
17REQ_SET_LCR: con 7;
18
19LCR_SET_BREAK: con 16r40;
20LCR_PARITY_EVEN: con 16r18;
21LCR_PARITY_ODD: con 16r08;
22LCR_PARITY_NONE: con 16r00;
23LCR_DATA_BITS_5, LCR_DATA_BITS_6, LCR_DATA_BITS_7, LCR_DATA_BITS_8: con iota;
24LCR_STOP_BITS_2: con 16r04;
25LCR_STOP_BITS_1: con 16r00;
26
27setupfd: ref Sys->FD;
28debug: con 1;
29
30ioreaderpid, statusreaderpid: int;
31
32kill(pid: int): int
33{
34	fd := sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE);
35	if (fd == nil)
36		return -1;
37	if (sys->write(fd, array of byte "kill", 4) != 4)
38		return -1;
39	return 0;
40}
41
42ioreader(pidc: chan of int, fd: ref Sys->FD)
43{
44	pid := sys->pctl(0, nil);
45	pidc <-= pid;
46	buf := array [256] of byte;
47	while ((n := sys->read(fd, buf, len buf)) >= 0)
48	{
49		sys->print("[%d]\n", n);
50		sys->write(sys->fildes(1), buf, n);
51	}
52	ioreaderpid = -1;
53}
54
55statusreader(pidc: chan of int, fd: ref Sys->FD)
56{
57	pid := sys->pctl(0, nil);
58	pidc <-= pid;
59	buf := array [2] of byte;
60	while ((n := sys->read(fd, buf, len buf)) >= 0)
61	{
62		sys->print("S(%d)%.2ux%.2ux\n", n, int buf[0], int buf[1]);
63	}
64	statusreaderpid = -1;
65}
66
67set_baud_rate(baud: int)
68{
69	buf := array [1] of byte;
70	val := 12;
71	case baud {
72	300 => val  = 1;
73	1200 => val  = 3;
74	2400 => val  = 4;
75	4800 => val  = 6;
76	9600 => val = 8;
77	19200 => val = 9;
78	38400 => val = 10;
79	57600 => val = 11;
80	115200 => val = 12;
81	}
82	buf[0] = byte val;
83	if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_BAUD_RATE, 0, 0, buf, nil) < 0) {
84		if (debug)
85			sys->print("usbmct: set_baud_rate failed\n");
86	}
87}
88
89set_lcr(val: int)
90{
91	buf := array [1] of byte;
92	buf[0] = byte val;
93	if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_LCR, 0, 0, buf, nil) < 0) {
94		if (debug)
95			sys->print("usbmct: set_lcr failed\n");
96	}
97}
98
99init(usbmod: Usb, psetupfd, pctlfd: ref Sys->FD,
100	dev: ref Usb->Device,
101	conf: array of ref Usb->Configuration, path: string): int
102{
103	statusep, inep, outep: ref Usb->Endpt;
104	usb = usbmod;
105	sys = load Sys Sys->PATH;
106	setupfd = psetupfd;
107	# check the device descriptor to see if it really is an MCT doofer
108	if (dev.vid != 16r0711 || dev.did != 16r0230) {
109		if (debug)
110			sys->print("usbmct: wrong device!\n");
111		return -1;
112	}
113	usb->set_configuration(setupfd, conf[0].id);
114	ai := hd conf[0].iface[0].altiface;
115	statusep = nil;
116	inep = nil;
117	outep = nil;
118	for (e := 0; e < len ai.ep; e++) {
119		ep := ai.ep[e];
120		if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3 && ep.maxpkt == 2)
121			statusep = ep;
122		else if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3)
123			inep = ep;
124		else if ((ep.addr & 16r80) == 0 && (ep.attr & 3) == 2)
125			outep = ep;
126	}
127	if (statusep == nil || outep == nil || inep == nil) {
128		if (debug)
129			sys->print("usbmct: can't find sensible endpoints\n");
130		return -1;
131	}
132	if ((inep.addr & 15) != (outep.addr & 15)) {
133		if (debug)
134			sys->print("usbmct: in and out endpoints not same number\n");
135		return -1;
136	}
137	ioid := inep.addr & 15;
138	statusid := statusep.addr & 15;
139	if (debug)
140		sys->print("ep %d %d r %d 32\n", ioid, inep.maxpkt, inep.interval);
141	if (sys->fprint(pctlfd, "ep %d %d r %d 32", ioid, inep.maxpkt, inep.interval) < 0) {
142		if (debug)
143			sys->print("usbmct: can't create i/o endpoint (i)\n");
144		return -1;
145	}
146#	if (debug)
147#		sys->print("ep %d %d r bulk 32\n", ioid, inep.maxpkt);
148#	if (sys->fprint(pctlfd, "ep %d %d r bulk 32", ioid, inep.maxpkt) < 0) {
149#		if (debug)
150#			sys->print("usbmct: can't create i/o endpoint (i)\n");
151#		return -1;
152#	}
153	if (debug)
154		sys->print("ep %d %d w bulk 8\n", ioid, outep.maxpkt);
155	if (sys->fprint(pctlfd, "ep %d %d w bulk 8", ioid, outep.maxpkt) < 0) {
156		if (debug)
157			sys->print("usbmct: can't create i/o endpoint (o)\n");
158		return -1;
159	}
160	iofd := sys->open(path + "ep" + string ioid + "data", Sys->ORDWR);
161	if (iofd == nil) {
162		if (debug)
163			sys->print("usbmct: can't open i/o endpoint\n");
164		return -1;
165	}
166	if (debug)
167		sys->print("ep %d %d r %d 8\n", statusid, statusep.maxpkt, statusep.interval);
168	if (sys->fprint(pctlfd, "ep %d %d r %d 8", statusid, statusep.maxpkt, statusep.interval) < 0) {
169		if (debug)
170			sys->print("usbmct: can't create status endpoint\n");
171		return -1;
172	}
173	statusfd := sys->open(path + "ep" + string statusid + "data", Sys->ORDWR);
174	if (statusfd == nil) {
175		if (debug)
176			sys->print("usbmct: can't open status endpoint\n");
177		return -1;
178	}
179sys->print("setting baud rate\n");
180	set_baud_rate(9600);
181sys->print("setting lcr\n");
182	set_lcr(LCR_PARITY_NONE | LCR_DATA_BITS_8 | LCR_STOP_BITS_1);
183sys->print("launching reader\n");
184	pidc := chan of int;
185	spawn ioreader(pidc, iofd);
186	ioreaderpid = <- pidc;
187	spawn statusreader(pidc, statusfd);
188	statusreaderpid = <- pidc;
189	buf := array[512] of byte;
190	for (x := 0; x < 512; x += 16) {
191		buf[x:] = array of byte sys->sprint("%.2ux", x / 16);
192		buf[x + 2:] = array of byte "-0123456789-\r\n";
193	}
194	sys->write(iofd, buf, 512);
195	return 0;
196}
197
198shutdown()
199{
200	if (ioreaderpid >= 0)
201		kill(ioreaderpid);
202	if (statusreaderpid >= 0)
203		kill(statusreaderpid);
204}
205