# # Copyright © 2002 Vita Nuova Holdings Limited # implement UsbDriver; # MCT RS232 USB driver # 'Documentation' mined from NetBSD include "sys.m"; sys: Sys; include "usb.m"; usb: Usb; UMCT_SET_REQUEST: con 1640; REQ_SET_BAUD_RATE: con 5; REQ_SET_LCR: con 7; LCR_SET_BREAK: con 16r40; LCR_PARITY_EVEN: con 16r18; LCR_PARITY_ODD: con 16r08; LCR_PARITY_NONE: con 16r00; LCR_DATA_BITS_5, LCR_DATA_BITS_6, LCR_DATA_BITS_7, LCR_DATA_BITS_8: con iota; LCR_STOP_BITS_2: con 16r04; LCR_STOP_BITS_1: con 16r00; setupfd: ref Sys->FD; debug: con 1; ioreaderpid, statusreaderpid: int; kill(pid: int): int { fd := sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE); if (fd == nil) return -1; if (sys->write(fd, array of byte "kill", 4) != 4) return -1; return 0; } ioreader(pidc: chan of int, fd: ref Sys->FD) { pid := sys->pctl(0, nil); pidc <-= pid; buf := array [256] of byte; while ((n := sys->read(fd, buf, len buf)) >= 0) { sys->print("[%d]\n", n); sys->write(sys->fildes(1), buf, n); } ioreaderpid = -1; } statusreader(pidc: chan of int, fd: ref Sys->FD) { pid := sys->pctl(0, nil); pidc <-= pid; buf := array [2] of byte; while ((n := sys->read(fd, buf, len buf)) >= 0) { sys->print("S(%d)%.2ux%.2ux\n", n, int buf[0], int buf[1]); } statusreaderpid = -1; } set_baud_rate(baud: int) { buf := array [1] of byte; val := 12; case baud { 300 => val = 1; 1200 => val = 3; 2400 => val = 4; 4800 => val = 6; 9600 => val = 8; 19200 => val = 9; 38400 => val = 10; 57600 => val = 11; 115200 => val = 12; } buf[0] = byte val; if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_BAUD_RATE, 0, 0, buf, nil) < 0) { if (debug) sys->print("usbmct: set_baud_rate failed\n"); } } set_lcr(val: int) { buf := array [1] of byte; buf[0] = byte val; if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_LCR, 0, 0, buf, nil) < 0) { if (debug) sys->print("usbmct: set_lcr failed\n"); } } init(usbmod: Usb, psetupfd, pctlfd: ref Sys->FD, dev: ref Usb->Device, conf: array of ref Usb->Configuration, path: string): int { statusep, inep, outep: ref Usb->Endpt; usb = usbmod; sys = load Sys Sys->PATH; setupfd = psetupfd; # check the device descriptor to see if it really is an MCT doofer if (dev.vid != 16r0711 || dev.did != 16r0230) { if (debug) sys->print("usbmct: wrong device!\n"); return -1; } usb->set_configuration(setupfd, conf[0].id); ai := hd conf[0].iface[0].altiface; statusep = nil; inep = nil; outep = nil; for (e := 0; e < len ai.ep; e++) { ep := ai.ep[e]; if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3 && ep.maxpkt == 2) statusep = ep; else if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3) inep = ep; else if ((ep.addr & 16r80) == 0 && (ep.attr & 3) == 2) outep = ep; } if (statusep == nil || outep == nil || inep == nil) { if (debug) sys->print("usbmct: can't find sensible endpoints\n"); return -1; } if ((inep.addr & 15) != (outep.addr & 15)) { if (debug) sys->print("usbmct: in and out endpoints not same number\n"); return -1; } ioid := inep.addr & 15; statusid := statusep.addr & 15; if (debug) sys->print("ep %d %d r %d 32\n", ioid, inep.maxpkt, inep.interval); if (sys->fprint(pctlfd, "ep %d %d r %d 32", ioid, inep.maxpkt, inep.interval) < 0) { if (debug) sys->print("usbmct: can't create i/o endpoint (i)\n"); return -1; } # if (debug) # sys->print("ep %d %d r bulk 32\n", ioid, inep.maxpkt); # if (sys->fprint(pctlfd, "ep %d %d r bulk 32", ioid, inep.maxpkt) < 0) { # if (debug) # sys->print("usbmct: can't create i/o endpoint (i)\n"); # return -1; # } if (debug) sys->print("ep %d %d w bulk 8\n", ioid, outep.maxpkt); if (sys->fprint(pctlfd, "ep %d %d w bulk 8", ioid, outep.maxpkt) < 0) { if (debug) sys->print("usbmct: can't create i/o endpoint (o)\n"); return -1; } iofd := sys->open(path + "ep" + string ioid + "data", Sys->ORDWR); if (iofd == nil) { if (debug) sys->print("usbmct: can't open i/o endpoint\n"); return -1; } if (debug) sys->print("ep %d %d r %d 8\n", statusid, statusep.maxpkt, statusep.interval); if (sys->fprint(pctlfd, "ep %d %d r %d 8", statusid, statusep.maxpkt, statusep.interval) < 0) { if (debug) sys->print("usbmct: can't create status endpoint\n"); return -1; } statusfd := sys->open(path + "ep" + string statusid + "data", Sys->ORDWR); if (statusfd == nil) { if (debug) sys->print("usbmct: can't open status endpoint\n"); return -1; } sys->print("setting baud rate\n"); set_baud_rate(9600); sys->print("setting lcr\n"); set_lcr(LCR_PARITY_NONE | LCR_DATA_BITS_8 | LCR_STOP_BITS_1); sys->print("launching reader\n"); pidc := chan of int; spawn ioreader(pidc, iofd); ioreaderpid = <- pidc; spawn statusreader(pidc, statusfd); statusreaderpid = <- pidc; buf := array[512] of byte; for (x := 0; x < 512; x += 16) { buf[x:] = array of byte sys->sprint("%.2ux", x / 16); buf[x + 2:] = array of byte "-0123456789-\r\n"; } sys->write(iofd, buf, 512); return 0; } shutdown() { if (ioreaderpid >= 0) kill(ioreaderpid); if (statusreaderpid >= 0) kill(statusreaderpid); }