linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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;
}

  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).