/* glitterdrv.c code by SASANO Takayoshi --- public domain, no warranty. */ #include #include #include #include #include #include #define DEFAULTPRI 80 #define STACKSIZE 2048 #ifdef DEBUG #define DP(x) printf x #else #define DP(x) /* */ #endif LOCAL ID PorID; LOCAL ID TskID; LOCAL W Brightness = 4; LOCAL W usbDevID = -1; LOCAL W usbIfID = -1; LOCAL W usbEpID = -1; #define CMD_REDRAW 0x40000000 #define CMD_BRIGHTNESS 0x41000000 #define CMD_FILL 0x42000000 #define CMD_REVERSE 0x43000000 #define CMD_MASK 0xff000000 #define DAT_MASK 0x0000ffff #define CMD_SIZE 6 #define DAT_SIZE 32 #define BUF_SIZE (CMD_SIZE + DAT_SIZE) LOCAL UB XferBuf[BUF_SIZE]; LOCAL UB DummyBuf[BUF_SIZE]; /* USBイベント処理 */ LOCAL W usb_event(DevReq *q, DevRsp *r) { #define VENDOR_ID 0x0f30 #define PRODUCT_ID 0x0040 #define EP_ADR_IN 0x81 #define EP_ADR_OUT 0x02 W er, did, iid, pid, ifno; usbDeviceDescriptor d; /* デバイス解除要求 */ if (q->datano == USB_UNMOUNT) { DP(("usb_event: detach\n")); iid = usbIfID; pid = usbEpID; usbDevID = usbIfID = usbEpID = -1; er = USB_OK; goto fin2; } did = q->devid & 0x7f; ifno = (q->devid >> 8) & 0xff; /* 製品のチェック */ if (usbDescriptorDevice(did, (UB *)&d, sizeof(d), NULL) < USB_OK || d.idVendor != VENDOR_ID || d.idProduct != PRODUCT_ID) { DP(("usb_event: not target\n")); er = USB_ERR_DEVICE; goto fin0; } /* インタフェースのオープン */ er = usbOpenInterface(did, ifno); if (er < USB_OK) { DP(("usb_event: usbOpenInterface %d\n", er)); goto fin0; } iid = er; /* エンドポイントのオープン */ er = usbOpenPipe(iid, EP_ADR_OUT, USB_WAIT, -1); if (er < USB_OK) { DP(("usb_event: usbOpenPipe %d\n", er)); goto fin1; } pid = er; /* エンドポイントの初期化 */ er = usbStallPipe(pid, 2); if (er < USB_OK) { DP(("usb_event: usbOpenPipe %d\n", er)); goto fin2; } usbDevID = did; usbIfID = iid; usbEpID = pid; er = USB_OK; DP(("usb_event: attached\n")); goto fin0; fin2: usbClosePipe(pid); fin1: usbCloseInterface(iid); fin0: return (er < USB_OK) ? USB_NONE : USB_OWN; } /* 再描画指示 */ LOCAL W redraw(void) { W er; if (Brightness == 0) { /* ダミーのバッファを使用し、表示offと見せかける */ er = usbIoPipe(usbEpID, DummyBuf, sizeof(DummyBuf), NULL); } else { XferBuf[2] = 0x50 | ((Brightness - 1) << 2); er = usbIoPipe(usbEpID, XferBuf, sizeof(XferBuf), NULL); } if (er < USB_OK) { DP(("redraw: usbIoPipe %d\n", er)); er = ER_IO; } return er; } /* 書き込み処理 */ LOCAL W read_write_request(DevReq *q, DevRsp *r) { W er, i, ix; UB *b; if (q->datano < 0) { er = ER_PAR; goto fin0; } switch (q->datano & CMD_MASK) { case CMD_REDRAW: // 再描画 er = redraw(); break; case CMD_BRIGHTNESS: // 輝度調整(再描画あり) Brightness = q->datano & 0x07; if (Brightness > 4) Brightness = 4; er = redraw(); break; case CMD_FILL: // パターンフィル(再描画あり) b = &XferBuf[CMD_SIZE]; for (i = 0; i < DAT_SIZE; i += 2) { b[i + 0] = q->datano >> 8; b[i + 1] = q->datano; } er = redraw(); break; case CMD_REVERSE: // 反転(再描画あり) b = &XferBuf[CMD_SIZE]; for (i = 0; i < DAT_SIZE; i++) b[i] = ~b[i]; er = redraw(); break; default: // データ設定(再描画なし) /* bit[27:24]がライン番号、bit[15:0]がビットマップデータ */ ix = (q->datano & CMD_MASK) >> 24; if (ix >= 16) { er = ER_NOSPT; goto fin0; } b = &XferBuf[ix * 2 + CMD_SIZE]; if (q->cmd.cmd == DC_WRITE) { b[0] = q->datano >> 8; b[1] = q->datano; } er = (b[0] << 8) | b[1]; break; } fin0: return er; } /* ドライバ要求処理 */ LOCAL W io_request(DevReq *q, DevRsp *r) { W er; switch(q->cmd.cmd) { case DC_READ: case DC_WRITE: er = (usbDevID < 0) ? ER_NOMDA : read_write_request(q, r); break; case DC_OPEN: er = (usbDevID < 0) ? ER_NOMDA : 0; break; case DC_CLOSE: case DC_CLOSEALL: er = ER_OK; break; case DC_ABORT: case DC_SUSPEND: case DC_RESUME: case DC_CARDEVENT: er = ER_OK; break; case DC_USBEVENT: er = usb_event(q, r); break; default: er = ER_NOSPT; break; } return er; } /* 処理タスク */ LOCAL void io_maintask(void) { W er, size; RNO rno; DevReq q; DevRsp r; while (1) { /* 要求待ち */ er = acp_por(&rno, (VP)&q, &size, PorID, D_ABORT_PTN | D_NORM_PTN); if (er < E_OK) goto fin0; /* サイズの異なるパケットは無視 */ if (size != sizeof(DevReq)) { DP(("io_maintask: bad packet size %d\n", size)); continue; } /* 返答用パケットの準備および要求処理の実行 */ r.devid = q.devid; r.cmd = q.cmd; r.datano = q.datano; r.datacnt = 0; r.error.err = io_request(&q, &r); /* ランデブへの返答 */ er = rpl_rdv(rno, (VP)&r, sizeof(DevRsp)); if (er < E_OK) { DP(("io_maintask: rpl_por %d\n", er)); } } fin0: exd_tsk(); } /* ドライバ・エントリポイント */ EXPORT W main(Bool start, TC *arg) { W er; T_CPOR cpor; T_CTSK ctsk; LOCAL DevDef devdef = { .attr.devinfo = 0, /* 特に設定しない */ .attr.devkind = DK_UNDEF, /* 未定義 */ .attr.reserved = 0, /* 予約(0) */ .attr.openreq = 1, /* open/close要求あり */ .attr.lockreq = 0, /* lock不要 */ .attr.diskinfo = 0, /* DN_DISKINFO非対応 */ .attr.chardev = 1, /* 文字型デバイス */ .attr.nowait = 0, /* nowaitモード非対応 */ .attr.eject = 0, /* eject不要 */ .subunits = 0, /* サブユニット数 */ .name = {TK_g, TK_l, TK_i, TK_t, TK_t, TK_e, TK_r, TK_NULL}, .portid = 0, /* ランデブポートID */ }; usbEventPattern evp = { .bClass = 0xff, .bSubClass = 0xff, .bProtocol = 0xff, .mask = EVENT_CLASS | EVENT_SUBCLASS | EVENT_PROTOCOL, }; /* 終了要求 */ if (!start) { er = E_OK; goto fin5; } /* 転送用バッファ初期化 */ memset(XferBuf, 0, sizeof(XferBuf)); XferBuf[0] = 0x80; XferBuf[1] = 0x03; XferBuf[2] = 0x5c; XferBuf[3] = 0x08; memcpy(DummyBuf, XferBuf, sizeof(XferBuf)); // Dummy (display off) /* ランデブポート作成 */ cpor.exinf = NULL; cpor.poratr = TA_NULL; cpor.maxcmsz = sizeof(DevReq); cpor.maxrmsz = sizeof(DevRsp); er = vcre_por(&cpor); if (er < E_OK) { DP(("main: vcre_por %d\n", er)); goto fin0; } PorID = (ID)er; /* 処理受け付けタスク作成 */ ctsk.exinf = NULL; ctsk.task = io_maintask; ctsk.itskpri = DEFAULTPRI; ctsk.stksz = STACKSIZE; ctsk.tskatr = TA_HLNG | TA_RNG0; er = vcre_tsk(&ctsk); if (er < E_OK) { DP(("main: vcre_tsk %d\n", er)); goto fin1; } TskID = (ID)er; /* 処理受け付けタスク起動 */ er = sta_tsk(TskID, 0); if (er < E_OK) { DP(("main: sta_tsk %d\n", er)); goto fin2; } /* USBインタフェースドライバとして宣言 */ er = usbRegistInterface(PorID, &evp); if (er < USB_OK) { DP(("main: usbRegistInterface %d\n", er)); goto fin3; } /* デバイスの登録 */ devdef.portid = PorID; er = DefDevice(&devdef, NULL); if (er < E_OK) { DP(("main: DefDevice %d\n", er)); goto fin4; } er = ER_OK; goto fin0; fin5: devdef.portid = 0; DefDevice(&devdef, NULL); fin4: usbRegistInterface(PorID, NULL); fin3: ter_tsk(TskID); fin2: del_tsk(TskID); fin1: del_por(PorID); fin0: return er; }