From: "Shaun Jackman" <sjackman@gmail.com>
To: Thomas Reitmayr <thomas@devbase.at>
Cc: linux-input@atrey.karlin.mff.cuni.cz
Subject: Re: USB: driver for CM109 chipset
Date: Sun, 26 Aug 2007 09:43:55 -0700 [thread overview]
Message-ID: <7f45d9390708260943x5fd120eek5ebb8e251c00908f@mail.gmail.com> (raw)
In-Reply-To: <46D169A6.4080209@devbase.at>
[-- Attachment #1: Type: text/plain, Size: 3083 bytes --]
The detach-yealink tool worked well; thanks. I generalised it (now
called detach-usb) to take a vendor/product/interface argument on the
command line. The patch is attached.
The EEPROM dumping tool did not work. It failed with
cm109_eeprom_read: Mode check failed witch HID_IR0=0xc0
I tried commenting out the HID_IR0 test, but it then read only zeros.
Thanks!
Shaun
$ sudo ./dump-eeprom
Found device:
idVendor=0x0d8c
idProduct=0x000e
iSerialNumber=0x00
Found HID interface #3
Successfully claimed interface
Manufacturer: "?"
Product: "Generic USB Audio Device "
Serial#: "?"
cm109_eeprom_read: Mode check failed witch HID_IR0=0xc0
On 8/26/07, Thomas Reitmayr <thomas@devbase.at> wrote:
> Hi Shaun,
> the CM109 VID and PID are probably not included in the kernel's
> blacklisted device list (see static array hid_blacklist in hid-core.c).
> Just for your tests you can write a little tool to detach the usbhid
> driver and then load the cm109 module manually using modprobe or insmod.
> An example for this tool (not using libusb) can be found at
> http://www.devbase.at/svn/view.cgi/yealink-tools/trunk/detach-yealink.c?revision=1&root=experimental&view=markup
> or inside the EEPROM tool below.
> BTW, there is still the issue with varying key mappings among different
> models. The EEPROM contents might give a hint for distinguishing the
> models, it would be interesting if you could read the EEPROM and tell us
> what you see. The tool for this task can be found at
> http://www.devbase.at/svn/view.cgi/cm109-tools/trunk/?root=experimental
> Regards,
> -Thomas
>
> Shaun Jackman wrote:
> > I am testing your cm109 driver with my Genius G-Talk USB phone. It
> > identifies itself as a cm109 device (0d8c:000e C-Media Electronics,
> > Inc.). I compiled and loaded the cm109 module. However when I plug the
> > phone in the, the usbhid driver grabs the device rather than the cm109
> > driver. The following snippet is from /proc/bus/usb/devices and shows
> > the Class/Subclass/Protocol 3/0/0 device is nabbed by the usbhid
> > driver. Why isn't the cm109 driver grabbing the device?
> >
> > Thanks for writing the driver, and I hope I can get it to work!
> > Shaun
> >
> > T: Bus=01 Lev=02 Prnt=02 Port=01 Cnt=02 Dev#= 7 Spd=12 MxCh= 0
> > D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
> > P: Vendor=0d8c ProdID=000e Rev= 1.00
> > S: Product=Generic USB Audio Device
> > C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
> > I:* If#= 0 Alt= 0 #EPs= 0 Cls=01(audio) Sub=01 Prot=00 Driver=snd-usb-audio
> > I:* If#= 1 Alt= 0 #EPs= 0 Cls=01(audio) Sub=02 Prot=00 Driver=snd-usb-audio
> > I: If#= 1 Alt= 1 #EPs= 1 Cls=01(audio) Sub=02 Prot=00 Driver=snd-usb-audio
> > E: Ad=01(O) Atr=09(Isoc) MxPS= 200 Ivl=1ms
> > I:* If#= 2 Alt= 0 #EPs= 0 Cls=01(audio) Sub=02 Prot=00 Driver=snd-usb-audio
> > I: If#= 2 Alt= 1 #EPs= 1 Cls=01(audio) Sub=02 Prot=00 Driver=snd-usb-audio
> > E: Ad=82(I) Atr=05(Isoc) MxPS= 100 Ivl=1ms
> > I:* If#= 3 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid
> > E: Ad=83(I) Atr=03(Int.) MxPS= 4 Ivl=32ms
> >
> >
> >
>
>
[-- Attachment #2: detach-usb.diff --]
[-- Type: text/plain, Size: 3389 bytes --]
--- detach-yealink.c 2007-08-26 09:38:38.000000000 -0700
+++ detach-usb.c 2007-08-26 09:24:19.000000000 -0700
@@ -1,5 +1,5 @@
/*
- * detach-yealink.c - a tool to detach a kernel module from a yealink device
+ * detach-usb.c - a tool to detach a kernel module from a USB device
* Copyright (C) 2007 Thomas Reitmayr
*
* This program is free software; you can redistribute it and/or modify
@@ -33,11 +33,6 @@
#include <sys/ioctl.h>
-#define VENDOR 0x6993
-#define PRODUCT 0xb001
-#define INTERFACE 3
-
-
#define USB_PATH1 "/dev/bus/usb"
#define USB_PATH2 "/proc/bus/usb"
@@ -61,7 +56,7 @@
};
-int check_dir(char *dirname)
+int check_dir(char *dirname, unsigned vendor, unsigned product)
{
DIR *dir;
struct dirent *entry;
@@ -78,7 +73,7 @@
continue;
snprintf(filepath, sizeof(filepath) - 1, "%s/%s", dirname, entry->d_name);
if (entry->d_type & DT_DIR) {
- fd = check_dir(filepath);
+ fd = check_dir(filepath, vendor, product);
}
else {
printf("checking %s\n", filepath);
@@ -93,10 +88,10 @@
}
else {
/* compare IDs */
- int vendorid = (device_desc[9] << 8) | device_desc[8];
- int productid = (device_desc[11] << 8) | device_desc[10];
+ unsigned vendorid = (device_desc[9] << 8) | device_desc[8];
+ unsigned productid = (device_desc[11] << 8) | device_desc[10];
printf(" v=%04x, p=%04x\n", vendorid, productid);
- if ((vendorid != VENDOR) || (productid != PRODUCT)) {
+ if ((vendorid != vendor) || (productid != product)) {
close(fd);
fd = -1;
}
@@ -112,13 +107,13 @@
}
-char *driver(int fd)
+char *driver(int fd, unsigned interface)
{
struct usb_getdriver getdrv;
static char drv[USB_MAXDRIVERNAME + 1];
int ret;
- getdrv.interface = INTERFACE;
+ getdrv.interface = interface;
ret = ioctl(fd, IOCTL_USB_GETDRIVER, &getdrv);
if (ret) {
if (errno == ENODATA) {
@@ -136,12 +131,12 @@
}
-int detach(int fd)
+int detach(int fd, unsigned interface)
{
struct usb_ioctl command;
int ret;
- command.ifno = INTERFACE;
+ command.ifno = interface;
command.ioctl_code = IOCTL_USB_DISCONNECT;
command.data = NULL;
@@ -152,28 +147,35 @@
return ret;
}
-
+#define USAGE "Usage: detach-usb VENDOR PRODUCT INTERFACE\n"
int main(int argc, char **argv)
{
- int fd;
- int ret = 0;
+ if (argc < 4) {
+ fputs("detach-usb: missing operands\n" USAGE, stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ unsigned vendor = strtoul(argv[1], NULL, 16);
+ unsigned product = strtoul(argv[2], NULL, 16);
+ unsigned interface = strtoul(argv[3], NULL, 16);
- fd = check_dir(USB_PATH1);
+ int ret = 0;
+ int fd = check_dir(USB_PATH1, vendor, product);
if (fd < 0)
- fd = check_dir(USB_PATH2);
+ fd = check_dir(USB_PATH2, vendor, product);
if (fd < 0) {
- printf("could not find yealink device\n");
+ printf("could not find USB device\n");
ret = 1;
}
else {
char *drv;
- printf("found yealink device\n");
- drv = driver(fd);
+ printf("found USB device\n");
+ drv = driver(fd, interface);
if (drv) {
if (drv[0]) {
- if (detach(fd) == 0) {
+ if (detach(fd, interface) == 0) {
printf("successfully detached driver %s\n", drv);
}
else {
[-- Attachment #3: detach-usb.c --]
[-- Type: text/x-csrc, Size: 5052 bytes --]
/*
* detach-usb.c - a tool to detach a kernel module from a USB device
* Copyright (C) 2007 Thomas Reitmayr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* This program consists of parts of the libusb library, which
* can be found at http://libusb.sourceforge.net/
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#define USB_PATH1 "/dev/bus/usb"
#define USB_PATH2 "/proc/bus/usb"
#define USB_MAXDRIVERNAME 255
#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl)
#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver)
#define IOCTL_USB_DISCONNECT _IO('U', 22)
#define DEVICE_DESC_LENGTH 18
struct usb_ioctl {
int ifno; /* interface 0..N ; negative numbers reserved */
int ioctl_code; /* MUST encode size + direction of data so the
* macros in <asm/ioctl.h> give correct values */
void *data; /* param buffer (in, or out) */
};
struct usb_getdriver {
unsigned int interface;
char driver[USB_MAXDRIVERNAME + 1];
};
int check_dir(char *dirname, unsigned vendor, unsigned product)
{
DIR *dir;
struct dirent *entry;
char filepath[PATH_MAX + 1];
int fd = -1;
// snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
dir = opendir(dirname);
if (!dir)
return -1;
while ((entry = readdir(dir))) {
if (entry->d_name[0] == '.')
continue;
snprintf(filepath, sizeof(filepath) - 1, "%s/%s", dirname, entry->d_name);
if (entry->d_type & DT_DIR) {
fd = check_dir(filepath, vendor, product);
}
else {
printf("checking %s\n", filepath);
fd = open(filepath, O_RDWR); //ONLY);
if (fd >= 0) {
/* check the device descriptor */
unsigned char device_desc[DEVICE_DESC_LENGTH];
if (read(fd, (void *)device_desc, DEVICE_DESC_LENGTH) < 0) {
/* read error */
close(fd);
fd = -1;
}
else {
/* compare IDs */
unsigned vendorid = (device_desc[9] << 8) | device_desc[8];
unsigned productid = (device_desc[11] << 8) | device_desc[10];
printf(" v=%04x, p=%04x\n", vendorid, productid);
if ((vendorid != vendor) || (productid != product)) {
close(fd);
fd = -1;
}
}
}
}
if (fd >= 0)
break;
}
closedir(dir);
return fd;
}
char *driver(int fd, unsigned interface)
{
struct usb_getdriver getdrv;
static char drv[USB_MAXDRIVERNAME + 1];
int ret;
getdrv.interface = interface;
ret = ioctl(fd, IOCTL_USB_GETDRIVER, &getdrv);
if (ret) {
if (errno == ENODATA) {
drv[0] = '\0';
}
else {
printf("Error in driver(): %s, %d\n", strerror(errno), errno);
return NULL;
}
}
else
strncpy(drv, getdrv.driver, USB_MAXDRIVERNAME);
return drv;
}
int detach(int fd, unsigned interface)
{
struct usb_ioctl command;
int ret;
command.ifno = interface;
command.ioctl_code = IOCTL_USB_DISCONNECT;
command.data = NULL;
ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
if (ret) {
printf("Error line __line__: %s\n", strerror(errno));
}
return ret;
}
#define USAGE "Usage: detach-usb VENDOR PRODUCT INTERFACE\n"
int main(int argc, char **argv)
{
if (argc < 4) {
fputs("detach-usb: missing operands\n" USAGE, stderr);
exit(EXIT_FAILURE);
}
unsigned vendor = strtoul(argv[1], NULL, 16);
unsigned product = strtoul(argv[2], NULL, 16);
unsigned interface = strtoul(argv[3], NULL, 16);
int ret = 0;
int fd = check_dir(USB_PATH1, vendor, product);
if (fd < 0)
fd = check_dir(USB_PATH2, vendor, product);
if (fd < 0) {
printf("could not find USB device\n");
ret = 1;
}
else {
char *drv;
printf("found USB device\n");
drv = driver(fd, interface);
if (drv) {
if (drv[0]) {
if (detach(fd, interface) == 0) {
printf("successfully detached driver %s\n", drv);
}
else {
printf("could not detach driver %s\n", drv);
ret = 2;
}
}
else {
printf("no driver attached\n");
}
}
else {
/* error */
ret = 3;
}
close(fd);
}
return ret;
}
next prev parent reply other threads:[~2007-08-26 16:43 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-26 4:28 USB: driver for CM109 chipset Shaun Jackman
2007-08-26 11:53 ` Thomas Reitmayr
2007-08-26 16:43 ` Shaun Jackman [this message]
2007-08-26 18:51 ` Alfred E. Heggestad
2007-08-27 5:57 ` Shaun Jackman
2007-08-27 9:46 ` Jiri Kosina
[not found] ` <7f45d9390708282238w7174d105i351e81cd19037d14@mail.gmail.com>
2007-08-29 8:31 ` Jiri Kosina
2007-08-29 9:59 ` Alfred E. Heggestad
2007-08-29 10:21 ` Jiri Kosina
2007-08-29 19:37 ` Shaun Jackman
2007-08-29 23:07 ` Jiri Kosina
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7f45d9390708260943x5fd120eek5ebb8e251c00908f@mail.gmail.com \
--to=sjackman@gmail.com \
--cc=linux-input@atrey.karlin.mff.cuni.cz \
--cc=thomas@devbase.at \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).