# HG changeset patch # User Yoshiki Yazawa # Date 1293172084 -32400 # Node ID 05cc06e88a57675dec5b591400d8e2177e1dd45e # Parent e1a1a181c0d748ac886f817459118c71780fdf13 modified to make use of libhid to access the device diff -r e1a1a181c0d7 -r 05cc06e88a57 Makefile --- a/Makefile Thu Dec 16 20:30:11 2010 +0900 +++ b/Makefile Fri Dec 24 15:28:04 2010 +0900 @@ -2,12 +2,17 @@ TARGET = rcctl SRCS = rcctl.c cdcnv.c +OBJS = rcctl.o cdcnv.o CC = gcc -CCOPT = -O -lusb -Wall -all: - $(CC) $(CCOPT) -o $(TARGET) $(SRCS) +# for debug build +CFLAGS = -O -Wall -g -DVERBOSE -DDEBUG -I/usr/include/libusb-1.0 +# for release build +#CFLAGS = -O -Wall +LDFLAGS = -lhid -lusb -debug: - $(CC) $(CCOPT) -DVERBOSE -DDEBUG -o $(TARGET) $(SRCS) +all: $(OBJS) + $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) +clean: + rm -f *.o $(TARGET) diff -r e1a1a181c0d7 -r 05cc06e88a57 cdcnv.c --- a/cdcnv.c Thu Dec 16 20:30:11 2010 +0900 +++ b/cdcnv.c Fri Dec 24 15:28:04 2010 +0900 @@ -11,11 +11,12 @@ ------------------------------------------------------*/ #include +#include #if defined(__FreeBSD__)||defined(linux) #define stricmp(s, c) strcasecmp(s, c) #endif -const char *mks = "XUGJHBPDSNKMALZTCI"; +const char mks[] = "XUGJHBPDSNKMALZTCI"; #define M_X2 0 /* X2000 */ #define M_UK 1 /* U-kara */ #define M_GI 2 /* GIGA */ @@ -78,8 +79,10 @@ 0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f }, {0x30, 0x00, 0xff, 0x41, 0x08, 0x09, 0x4c, 0x45, 0x44, /* TOEI sys */ 0x13, 0x0f, 0x4f, 0x4e, 0x07, 0x47, 0x46, 0x03, 0x43, 0x42, 0x53, 0x52 }, + {0x10, 0x55, 0xaa, 0x3e, 0x08, 0x09, 0x5c, -1, -1, /* Σ System */ 0x13, 0x0f, 0x4f, 0x4e, 0x07, 0x47, 0x46, 0x03, 0x43, 0x42, 0x53, 0x52 }, + {0x40, 0xae, 0x51, 0xdc, 0x03, 0x02, 0x96, -1, 0xdd, /* 鉄人 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0xda, 0xdb } }; @@ -95,166 +98,174 @@ int cdcnv(int buf[], char *mak, char *cod) { - int maker, i, c, n, *q; + int maker, i, c, n, *q; + char *tmp = NULL; - if ((maker = (int)strchr(mks, *mak & 0xdf)) == NULL) - return -1; - maker -= (int)mks; +#ifdef DEBUG + fprintf(stderr, "mak=%s cod=%s\n", mak, cod); +#endif - q = buf; + tmp = strchr(mks, *mak & 0xdf); + if(!tmp) + return -1; + maker = (int)(tmp - mks); +#ifdef DEBUG + fprintf(stderr, "maker=%d\n", maker); +#endif + q = buf; - *q++ = 0x80; /* wake-up code */ - *q++ = cvt[maker][0]; - *q++ = cvt[maker][1]; - *q++ = cvt[maker][2]; + *q++ = 0x80; /* wake-up code */ + *q++ = cvt[maker][0]; + *q++ = cvt[maker][1]; + *q++ = cvt[maker][2]; - /* 統合機種等でのメーカー名指定 */ - if ((c = *++mak) != 0) { - if ((maker == M_A3)&&('0' <= c)&&(c <= '4')) - cvt[maker][K_SE] = 0x12 + (c - '0'); - else if ((maker == M_AZ)&&('1' <= c)&&(c <= '4')) - *q++ = 0x13 + (c - '1'); - else if ((maker == M_AL)&&('0' <= c)&&(c <= '9')) { - *q++ = cvt[maker][K_NM + (c - '0')]; - *q++ = 0x10; + /* 統合機種等でのメーカー名指定 */ + if ((c = *++mak) != 0) { + if ((maker == M_A3)&&('0' <= c)&&(c <= '4')) + cvt[maker][K_SE] = 0x12 + (c - '0'); + else if ((maker == M_AZ)&&('1' <= c)&&(c <= '4')) + *q++ = 0x13 + (c - '1'); + else if ((maker == M_AL)&&('0' <= c)&&(c <= '9')) { + *q++ = cvt[maker][K_NM + (c - '0')]; + *q++ = 0x10; + } + else if ((maker == M_TS)&&('1' <= c)&&(c <= '8')) + *q++ = tsc[c - '1']; + else if ((maker == M_TJ)&&('0' <= c)&&(c <= '9')) + *q++ = tjc[c - '1']; + else if ((maker == M_UK)&&('2' == c)) { + buf[1] = 0x70; + *q++ = 0xf0; + } } - else if ((maker == M_TS)&&('1' <= c)&&(c <= '8')) - *q++ = tsc[c - '1']; - else if ((maker == M_TJ)&&('0' <= c)&&(c <= '9')) - *q++ = tjc[c - '1']; - else if ((maker == M_UK)&&('2' == c)) { - buf[1] = 0x70; - *q++ = 0xf0; - } - } - if (maker == M_BK) - *q++ = 0xf0; + if (maker == M_BK) + *q++ = 0xf0; + + if (('0' <= *cod)&&(*cod <= '9')) { + if (maker == M_DA) + *q++ = 0x08; + else if (maker == M_MA) + *q++ = 0x10; /* Req.1 */ + else if (maker == M_SI) { + /* [1-9A-F] -> '01','02',...,'15' , NULL -> '00' */ + if (*mak == 0) { + *q++ = cvt[maker][K_NM + 0]; + *q++ = cvt[maker][K_NM + 0]; + } + else { + if (mak[1] != 0) + *q++ = cvt[maker][K_NM + (*mak++ - '0')]; + else + *q++ = cvt[maker][K_NM + ((*mak >= 'A')? 1: 0)]; + *q++ = cvt[maker][K_NM + ((*mak % 0x41) & 0x0f)]; + } + } - if (('0' <= *cod)&&(*cod <= '9')) { - if (maker == M_DA) - *q++ = 0x08; - else if (maker == M_MA) - *q++ = 0x10; /* Req.1 */ - else if (maker == M_SI) { - /* [1-9A-F] -> '01','02',...,'15' , NULL -> '00' */ - if (*mak == 0) { - *q++ = cvt[maker][K_NM + 0]; - *q++ = cvt[maker][K_NM + 0]; - } - else { - if (mak[1] != 0) - *q++ = cvt[maker][K_NM + (*mak++ - '0')]; - else - *q++ = cvt[maker][K_NM + ((*mak >= 'A')? 1: 0)]; - *q++ = cvt[maker][K_NM + ((*mak % 0x41) & 0x0f)]; - } + /* 曲コード変換 */ + while((c = *cod++) != '\0') { + if (('0' <= c)&&(c <= '9')) + *q = cvt[maker][c - '0' + K_NM]; + else if ((c == 'A')||(c == 'a')) + *q = cvt[maker][10 + K_NM]; + else if ((c == 'B')||(c == 'b')) + *q = cvt[maker][11 + K_NM]; + else if (c == '-') { + if (maker == M_TJ) + *q = cvt[maker][K_SE]; + else + continue; + } + else + *q = -1; + if (*q++ == -1) + return -2; + } + + /* 送信直前処理 */ + switch(maker) { + case M_X2: + /* X2000: 曲コードの末尾 2 桁の直前にも SET を送信 */ + q -= 2; + q[3] = cvt[maker][K_SE]; + q[2] = q[1]; + q[1] = q[0]; + q[0] = cvt[maker][K_SE]; + q += 4; + break; + + case M_GI: + /* GIGA: 曲コードが 6 桁以下の場合は最後に'0'を埋める */ + while(q < &buf[10]) + *q++ = cvt[maker][K_NM]; + break; + + case M_PR: + /* Prologue21: */ + for( i=0; i<3; i++ ) { + buf[10-i] = 0; + if (q > &buf[4]) + buf[10-i] = *--q << 4; + if (q > &buf[4]) + buf[10-i] |= *--q; + } + q = &buf[11]; + *q++ = 0x33; + buf[4] = buf[8]; + buf[5] = buf[9]; + buf[6] = buf[10]; + buf[7] = buf[11]; + break; /* q=&buf[8] にしないとバグのような… */ + + case M_SI: + /* Σシステム: コード長 10 バイト(,,)固定 */ + case M_DA: + /* DAM: コード長 9 バイト(0x08,,)固定 */ + case M_BK: + /* B-kara: コード長 9 バイト(0xf0,,)固定 */ + n = (maker == M_SI)? 12: 11; /* 数字の最終桁を buf[n] とした値 */ + for( i=0; i<7; i++ ) { + c = *(q-1); + if ((i == 1)&&((c == cvt[maker][K_NM+10])||(c == cvt[maker][K_NM+11]))) + /* 曲コード中の'A','B'以降の桁数が1桁なら'0'を挿入 */ + buf[n-i] = cvt[maker][K_NM + 0]; + else if ((i == 2)&&(c!=cvt[maker][K_NM+10])&&(c!=cvt[maker][K_NM+11])) + /* 曲コードの末尾 3 文字めが'A','B'でなければ'-'を設定 */ + buf[n-i] = (maker == M_BK)? 0x3d: ((maker == M_SI)? 0x51: 0x3c); + else if (q > &buf[n-6]) + buf[n-i] = *--q; + else + /* 桁数の足らない部分には'0'を設定 */ + buf[n-i] = cvt[maker][K_NM + 0]; + } + q = &buf[n+1]; + default: + *q++ = cvt[maker][K_SE]; + break; + } } - - /* 曲コード変換 */ - while((c = *cod++) != '\0') { - if (('0' <= c)&&(c <= '9')) - *q = cvt[maker][c - '0' + K_NM]; - else if ((c == 'A')||(c == 'a')) - *q = cvt[maker][10 + K_NM]; - else if ((c == 'B')||(c == 'b')) - *q = cvt[maker][11 + K_NM]; - else if (c == '-') { - if (maker == M_TJ) - *q = cvt[maker][K_SE]; - else - continue; - } - else + /* 制御コードの処理 */ + else { *q = -1; - if (*q++ == -1) - return -2; + if (!stricmp(cod, "SE")) + *q = cvt[maker][K_SE]; + else if (!stricmp(cod, "KU")) + *q = cvt[maker][K_KU]; + else if (!stricmp(cod, "KD")) + *q = cvt[maker][K_KD]; + else if (!stricmp(cod, "SP")) + *q = cvt[maker][K_SP]; + else if (!stricmp(cod, "ST")) + *q = cvt[maker][K_ST]; + else if (!stricmp(cod, "CL")) + *q = cvt[maker][K_CL]; + if (*q == -1) + return -3; + q++; } - /* 送信直前処理 */ - switch(maker) { - case M_X2: - /* X2000: 曲コードの末尾 2 桁の直前にも SET を送信 */ - q -= 2; - q[3] = cvt[maker][K_SE]; - q[2] = q[1]; - q[1] = q[0]; - q[0] = cvt[maker][K_SE]; - q += 4; - break; - - case M_GI: - /* GIGA: 曲コードが 6 桁以下の場合は最後に'0'を埋める */ - while(q < &buf[10]) - *q++ = cvt[maker][K_NM]; - break; - - case M_PR: - /* Prologue21: */ - for( i=0; i<3; i++ ) { - buf[10-i] = 0; - if (q > &buf[4]) - buf[10-i] = *--q << 4; - if (q > &buf[4]) - buf[10-i] |= *--q; - } - q = &buf[11]; - *q++ = 0x33; - buf[4] = buf[8]; - buf[5] = buf[9]; - buf[6] = buf[10]; - buf[7] = buf[11]; - break; /* q=&buf[8] にしないとバグのような… */ + if ((maker == M_BK)||((maker == M_UK)&&('2' == *mak))) + *q++ = 0xf7; - case M_SI: - /* Σシステム: コード長 10 バイト(,,)固定 */ - case M_DA: - /* DAM: コード長 9 バイト(0x08,,)固定 */ - case M_BK: - /* B-kara: コード長 9 バイト(0xf0,,)固定 */ - n = (maker == M_SI)? 12: 11; /* 数字の最終桁を buf[n] とした値 */ - for( i=0; i<7; i++ ) { - c = *(q-1); - if ((i == 1)&&((c == cvt[maker][K_NM+10])||(c == cvt[maker][K_NM+11]))) - /* 曲コード中の'A','B'以降の桁数が1桁なら'0'を挿入 */ - buf[n-i] = cvt[maker][K_NM + 0]; - else if ((i == 2)&&(c!=cvt[maker][K_NM+10])&&(c!=cvt[maker][K_NM+11])) - /* 曲コードの末尾 3 文字めが'A','B'でなければ'-'を設定 */ - buf[n-i] = (maker == M_BK)? 0x3d: ((maker == M_SI)? 0x51: 0x3c); - else if (q > &buf[n-6]) - buf[n-i] = *--q; - else - /* 桁数の足らない部分には'0'を設定 */ - buf[n-i] = cvt[maker][K_NM + 0]; - } - q = &buf[n+1]; - default: - *q++ = cvt[maker][K_SE]; - break; - } - } - /* 制御コードの処理 */ - else { - *q = -1; - if (!stricmp(cod, "SE")) - *q = cvt[maker][K_SE]; - else if (!stricmp(cod, "KU")) - *q = cvt[maker][K_KU]; - else if (!stricmp(cod, "KD")) - *q = cvt[maker][K_KD]; - else if (!stricmp(cod, "SP")) - *q = cvt[maker][K_SP]; - else if (!stricmp(cod, "ST")) - *q = cvt[maker][K_ST]; - else if (!stricmp(cod, "CL")) - *q = cvt[maker][K_CL]; - if (*q == -1) - return -3; - q++; - } - - if ((maker == M_BK)||((maker == M_UK)&&('2' == *mak))) - *q++ = 0xf7; - - buf[1] |= q-buf-2; /* 実送信バイト数(PIC 制御用)を埋め込み */ - return q-buf; + buf[1] |= q-buf-2; /* 実送信バイト数(PIC 制御用)を埋め込み */ + return q-buf; } diff -r e1a1a181c0d7 -r 05cc06e88a57 rcctl.c --- a/rcctl.c Thu Dec 16 20:30:11 2010 +0900 +++ b/rcctl.c Fri Dec 24 15:28:04 2010 +0900 @@ -1,207 +1,229 @@ /* rcctl.c --------------------------------------------- -$Id: rcctl.c,v 1.1 2002/12/21 01:13:28 tosy Exp $ + $Id: rcctl.c,v 1.1 2002/12/21 01:13:28 tosy Exp $ - v0.10 97.08.15 初期版(コミケット52) - v0.11 97.08.27 通信タイミング修正 - v0.12 97.09.12 U-kara-2サポート - v0.12a 97.09.15 返り値設定 - v0.12b 97.09.20 Bug fix (JOY:[SP]) - v0.20 97.10.01 FreeBSD版 - v0.20a 97.10.18 Bug fix (X2k:[SP],[ST]) - v0.21 97.12.10 ALISA-3シーケンス修正 - v0.30 97.12.13 コード変換部(cdcnv.c)分離 - v0.40 02.12.16 USB版対応 - 【cdcnv.c の履歴も参照のこと】 -------------------------------------------------------*/ - + v0.10 97.08.15 初期版(コミケット52) + v0.11 97.08.27 通信タイミング修正 + v0.12 97.09.12 U-kara-2サポート + v0.12a 97.09.15 返り値設定 + v0.12b 97.09.20 Bug fix (JOY:[SP]) + v0.20 97.10.01 FreeBSD版 + v0.20a 97.10.18 Bug fix (X2k:[SP],[ST]) + v0.21 97.12.10 ALISA-3シーケンス修正 + v0.30 97.12.13 コード変換部(cdcnv.c)分離 + v0.40 02.12.16 USB版対応 + 【cdcnv.c の履歴も参照のこと】 + ------------------------------------------------------*/ +#define __LINUX__ #include #include #include #include +#include + +#define HID_MAX_USAGES 16 +typedef unsigned int __u32; +typedef unsigned int kernel_ulong_t; + +#include #include -#include -#include -#include -/* #define VERBOSE */ -/* #define NOCTSCHK */ +#include + +#define BITS_PER_LONG 32 -#ifndef SDEV -#define SDEV "/dev/cuaa0" +#include +#include +#include + + +#ifndef S_VERS +#define S_VERS "0.41" #endif -#ifndef UDEV -#define UDEV "/dev/uhid0" -#endif +/* globals */ +HIDInterface *hidif; +extern int errno; -#ifndef S_VERS -#define S_VERS "0.40" -#endif - -int fd; - +/* prototypes */ int cdcnv(int buf[], char *mak, char *cod); extern char *cverrstr[]; -int init_sio(void) +int init_usb(void) { -#ifndef NOCTSCHK - int tcnt = 0; -#endif - struct termios tios; - int md; + hid_return ret; + +// unsigned int report_id; +// unsigned int report_type; +// unsigned int size; + + /* vendor id and product id of okecon */ + HIDInterfaceMatcher matcher = { 0x0bfe, 0x2022, NULL, NULL, 0 }; + + /* see include/debug.h for possible values */ + hid_set_debug(HID_DEBUG_ALL); + hid_set_debug_stream(stderr); + /* passed directly to libusb */ + hid_set_usb_debug(0); + + ret = hid_init(); + if (ret != HID_RET_SUCCESS) { + fprintf(stderr, "hid_init failed with return code %d\n", ret); + return 1; + } - if ((fd = open(SDEV, O_RDWR)) == -1) { - fprintf(stderr, "Cannot open %s.\n", SDEV); - return 255; - } + hidif = hid_new_HIDInterface(); + if (hidif == 0) { + fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n"); + return 1; + } + + ret = hid_force_open(hidif, 0, &matcher, 3); + if (ret != HID_RET_SUCCESS) { + fprintf(stderr, "hid_force_open failed with return code %d\n", ret); + return 1; + } - tcgetattr(fd, &tios); - tios.c_iflag = 0; - tios.c_oflag = 0; - tios.c_cflag = B9600|CS8|CLOCAL; - tios.c_lflag = 0; -/* - cfmakeraw(&tios); - cfsetspeed(&tios, B9600); -*/ - tcsetattr(fd, TCSANOW, &tios); - tcflush(fd, TCOFLUSH); + + +#if 0 + /* read feature */ + ret = hid_get_feature_report(hidif, path, depth, buffer, size); + if(ret != HID_RET_SUCCESS) { + fprintf(stderr, "hid_get_feature_report failed with return code %d\n", ret); + return 1; + } + + /* parse */ - md = TIOCM_LE|TIOCM_DTR|TIOCM_RTS; - ioctl(fd, TIOCMBIS, &md); + /* prepare buffers */ + hid_get_report_size(hidif, report_id, report_type, &size); + if(size != 8) { + fprintf(stderr, "%s is not 'OKCon/USB'?\n", UDEV); + return 1; + }; + - /* wait for CTS: 充電待ち */ -#ifndef NOCTSCHK - for(;;) { - ioctl(fd, TIOCMGET, &md); - if (md & TIOCM_CTS) - break; - if (tcnt == 0) { - fprintf(stderr, "Waiting...."); +// BSD + /* read header */ + if ((rd = hid_get_report_desc(fd)) == 0) { + fprintf(stderr, "Failed on USB_GET_REPORT_DESC.\n"); + return 1; + } + + /* parse */ + hd = hid_start_parse(rd, 1<= 30) { - fprintf(stderr, "Device timeout.\n"); - close(fd); - return 1; + hid_end_parse(hd); + + /* prepare buffers */ + hid_get_report_size(&hidif, report_id, report_type, &size); + if(size != 8) { + fprintf(stderr, "%s is not 'OKCon/USB'?\n", UDEV); + return 1; + }; + + hid_dispose_report_desc(rd); +#endif + + return 0; +} /* end of init_usb() */ + + +int fin_usb() +{ + hid_return ret; + + ret = hid_close(hidif); + if (ret != HID_RET_SUCCESS) { + fprintf(stderr, "hid_close failed with return code %d\n", ret); + return 1; } - sleep(1); - } -#endif /* NOCTSCHK */ + + hid_delete_HIDInterface(&hidif); - md = TIOCM_RTS; - ioctl(fd, TIOCMBIC, &md); - usleep(10000); /* 10ms */ - ioctl(fd, TIOCMBIS, &md); - usleep(50000); /* 50ms */ + ret = hid_cleanup(); + if (ret != HID_RET_SUCCESS) { + fprintf(stderr, "hid_cleanup failed with return code %d\n", ret); + return 1; + } - return 0; + return 0; } -/* CTS が 0.5 秒以上連続して ON になるまで待つ */ -void charge(void) -{ -#ifndef NOCTSCHK - int i, md; - for( i=0; i<50; i++ ) { - usleep(10000); /* 10ms */ - ioctl(fd, TIOCMGET, &md); - if (!(md & TIOCM_CTS)) - i = 0; - } -#endif /* NOCTSCHK */ -} - -int init_usb(void) -{ - report_desc_t rd; - hid_data_t hd; - hid_item_t shi; - - hid_init(NULL); - - if((fd = open(UDEV, O_RDWR)) < 0) { - fprintf(stderr, "Cannot open %s.\n", UDEV); - return 1; - } - - /* read header */ - if ((rd = hid_get_report_desc(fd)) == 0) { - fprintf(stderr, "Failed on USB_GET_REPORT_DESC.\n"); - return 1; - } - - /* parse */ - hd = hid_start_parse(rd, 1< \n"); - return 255; - } + if (ac < 3) { + printf("'Oke-Con' controller, version " S_VERS ".\n"); + printf("Copyright (C) 1997-2002 by Tosy / W341IG.\n"); + printf("Usage: rcctl \n"); + return 255; + } - if ((u = cdcnv(buf, av[1], av[2])) < 0) { - fprintf(stderr, "%s: %s\n", av[0], cverrstr[~u]); - return 1; - } + if ((u = cdcnv(buf, av[1], av[2])) < 0) { + fprintf(stderr, "%s: %s\n", av[0], cverrstr[~u]); + return 1; + } + printf("cdcnv %d\n", u); #ifdef VERBOSE - printf("Initializing...."); + printf("Initializing....\n"); #endif - if (init_usb()) - /* if (init_sio()) */ - return 255; + + if (init_usb()) + return 255; + #ifdef VERBOSE - printf(" done.\n"); + printf(" done.\n"); #endif #ifdef VERBOSE -/* printf("maker %d (%c).\n", maker, mks[maker]); */ - for(i=0; i