* Re: USB: driver for CM109 chipset
@ 2007-08-26 4:28 Shaun Jackman
2007-08-26 11:53 ` Thomas Reitmayr
2007-08-26 18:51 ` Alfred E. Heggestad
0 siblings, 2 replies; 11+ messages in thread
From: Shaun Jackman @ 2007-08-26 4:28 UTC (permalink / raw)
To: aeh; +Cc: linux-input
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
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
2007-08-26 18:51 ` Alfred E. Heggestad
1 sibling, 1 reply; 11+ messages in thread
From: Thomas Reitmayr @ 2007-08-26 11:53 UTC (permalink / raw)
To: Shaun Jackman; +Cc: linux-input
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
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-26 11:53 ` Thomas Reitmayr
@ 2007-08-26 16:43 ` Shaun Jackman
0 siblings, 0 replies; 11+ messages in thread
From: Shaun Jackman @ 2007-08-26 16:43 UTC (permalink / raw)
To: Thomas Reitmayr; +Cc: linux-input
[-- 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;
}
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-26 4:28 USB: driver for CM109 chipset Shaun Jackman
2007-08-26 11:53 ` Thomas Reitmayr
@ 2007-08-26 18:51 ` Alfred E. Heggestad
2007-08-27 5:57 ` Shaun Jackman
1 sibling, 1 reply; 11+ messages in thread
From: Alfred E. Heggestad @ 2007-08-26 18:51 UTC (permalink / raw)
To: Shaun Jackman; +Cc: linux-input
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?
>
I have made a new version of the CM109 driver which updates the
usb hid-quirks.c blacklist, please find it here:
http://aeh.db.org/patch/cm109-20070826.patch
(All versions here: http://aeh.db.org/patch/)
You can also try to unload the usbhid.ko module (while the USB phone
is plugged in), and then manually load the cm109.ko driver
Another outstanding issue with the CM109 driver is that it seems
like all phone vendors have different key-mappings. That means
that the keymapping defined in my version of the cm109 driver
works with the KIP-1000 USB phone. I have got reports from other
users with other phones, that the keymapping is different. It
would be very interesting to see which keymapping your phone
(Genius G-talk) has.
I am not sure how to fix this problem, does anyone on this list
have any good suggestions?
/alfred
> 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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-26 18:51 ` Alfred E. Heggestad
@ 2007-08-27 5:57 ` Shaun Jackman
2007-08-27 9:46 ` Jiri Kosina
0 siblings, 1 reply; 11+ messages in thread
From: Shaun Jackman @ 2007-08-27 5:57 UTC (permalink / raw)
To: Alfred E. Heggestad; +Cc: linux-input
On 8/26/07, Alfred E. Heggestad <aeh@db.org> wrote:
> I have made a new version of the CM109 driver which updates the
> usb hid-quirks.c blacklist, please find it here:
>
> http://aeh.db.org/patch/cm109-20070826.patch
>
> (All versions here: http://aeh.db.org/patch/)
In fact, I already tried adding the CM109 to the blacklist. Oddly
enough, the usbhid driver still grabs the CM109 HID device. I must be
doing something wrong...
$ grep -1 CMEDIA drivers/hid/usbhid/hid-quirks.c
#define USB_VENDOR_ID_CMEDIA 0x0d8c
#define USB_DEVICE_ID_CMEDIA_CM109 0x000e
--
{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_CM109, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM,
HID_QUIRK_IGNORE },
$ make modules
CHK include/linux/version.h
CHK include/linux/utsrelease.h
CALL scripts/checksyscalls.sh
CC [M] drivers/hid/usbhid/hid-quirks.o
LD [M] drivers/hid/usbhid/usbhid.o
Building modules, stage 2.
MODPOST 1648 modules
LD [M] drivers/hid/usbhid/usbhid.ko
$ sudo cp drivers/hid/usbhid/usbhid.ko
/lib/modules/2.6.23-rc3/kernel/drivers/hid/usbhid/usbhid.ko
> You can also try to unload the usbhid.ko module (while the USB phone
> is plugged in), and then manually load the cm109.ko driver
That's difficult for me, as both my keyboard and mouse are HID
devices. The detach-usb utility is working for me until I can get the
blacklist working.
> Another outstanding issue with the CM109 driver is that it seems
> like all phone vendors have different key-mappings. That means
> that the keymapping defined in my version of the cm109 driver
> works with the KIP-1000 USB phone. I have got reports from other
> users with other phones, that the keymapping is different. It
> would be very interesting to see which keymapping your phone
> (Genius G-talk) has.
It's one of the guarantees in electronics that if two people are given
an arbitrary binary choice, they will certainly choose opposite each
other. A keyboard matrix, which is well more than a binary choice,
will yield endless different key arrangements. The Genius G-Talk
keymap follows this mail.
> I am not sure how to fix this problem, does anyone on this list
> have any good suggestions?
I haven't been able to dump the EEPROM yet. I'll think on it.
Cheers,
Shaun
/*
Genius G-Talk keyboard matrix
0 1 2 3
4: 0 4 8 Talk
5: 1 5 9 End
6: 2 6 # Up
7: 3 7 * Down
*/
case 0x11: return KEY_0;
case 0x21: return KEY_1;
case 0x41: return KEY_2;
case 0x81: return KEY_3;
case 0x12: return KEY_4;
case 0x22: return KEY_5;
case 0x42: return KEY_6;
case 0x82: return KEY_7;
case 0x14: return KEY_8;
case 0x24: return KEY_9;
case 0x44: return KEY_LEFTSHIFT | KEY_3 << 8; /* # */
case 0x84: return KEY_KPASTERISK;
case 0x18: return KEY_ENTER; /* Talk (green handset) */
case 0x28: return KEY_ESC; /* End (red handset) */
case 0x48: return KEY_UP; /* Menu up (rocker switch) */
case 0x88: return KEY_DOWN; /* Menu down (rocker switch) */
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-27 5:57 ` Shaun Jackman
@ 2007-08-27 9:46 ` Jiri Kosina
[not found] ` <7f45d9390708282238w7174d105i351e81cd19037d14@mail.gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Jiri Kosina @ 2007-08-27 9:46 UTC (permalink / raw)
To: Shaun Jackman; +Cc: Alfred E. Heggestad, linux-input
On Sun, 26 Aug 2007, Shaun Jackman wrote:
> In fact, I already tried adding the CM109 to the blacklist. Oddly
> enough, the usbhid driver still grabs the CM109 HID device. I must be
> doing something wrong...
Hi,
first, it is now also possible to pass additional quirks to the usbhid
module using the 'quirks' parameter.
> $ grep -1 CMEDIA drivers/hid/usbhid/hid-quirks.c
> #define USB_VENDOR_ID_CMEDIA 0x0d8c
> #define USB_DEVICE_ID_CMEDIA_CM109 0x000e
>
> --
> { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
> { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_CM109, HID_QUIRK_IGNORE },
> { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM,
> HID_QUIRK_IGNORE },
Adding a HID_QUIRK_IGNORE entry to the blacklist is sufficient. Could you
please double check that this patched driver really binds to the device?
If so, could you please compile with CONFIG_HID_DEBUG enabled and modprobe
the usbhid module with 'debug=1' parameter and send me the kernel output?
--
Jiri Kosina
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
[not found] ` <7f45d9390708282238w7174d105i351e81cd19037d14@mail.gmail.com>
@ 2007-08-29 8:31 ` Jiri Kosina
2007-08-29 9:59 ` Alfred E. Heggestad
0 siblings, 1 reply; 11+ messages in thread
From: Jiri Kosina @ 2007-08-29 8:31 UTC (permalink / raw)
To: Shaun Jackman; +Cc: Alfred E. Heggestad, linux-input
On Tue, 28 Aug 2007, Shaun Jackman wrote:
> > Adding a HID_QUIRK_IGNORE entry to the blacklist is sufficient. Could you
> > please double check that this patched driver really binds to the device?
> Ah, found the problem. The usbhid.ko module was being loaded from the
> initramfs image, not from /lib/modules of my root partition. I updated
> the initramfs image and all is good!
BTW when you are ready with the CM109 driver, please don't forget to send
me a patch which will add the device to the HID blacklist.
Thanks,
--
Jiri Kosina
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
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
0 siblings, 2 replies; 11+ messages in thread
From: Alfred E. Heggestad @ 2007-08-29 9:59 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Shaun Jackman, linux-input
Jiri Kosina wrote:
> On Tue, 28 Aug 2007, Shaun Jackman wrote:
>
>>> Adding a HID_QUIRK_IGNORE entry to the blacklist is sufficient. Could you
>>> please double check that this patched driver really binds to the device?
>> Ah, found the problem. The usbhid.ko module was being loaded from the
>> initramfs image, not from /lib/modules of my root partition. I updated
>> the initramfs image and all is good!
>
> BTW when you are ready with the CM109 driver, please don't forget to send
> me a patch which will add the device to the HID blacklist.
>
here is an updated version of the CM109 driver, now supporting both KIP1000
and Genius G-talk USB phones. The keymap can be selecting when loading the
module using the "phone" parameter.
# insmod cm109 phone=gtalk
Thanks for Shaun for the Genius G-talk keymap
The patch is below, and can also be downloaded from here:
http://aeh.db.org/patch/cm109-20070829.patch
comments are welcome
/alfred
diff -uprN -X linux-2.6.22.5/Documentation/dontdiff linux-2.6.22.5-orig/drivers/hid/usbhid/hid-quirks.c
linux-2.6.22.5/drivers/hid/usbhid/hid-quirks.c
--- linux-2.6.22.5-orig/drivers/hid/usbhid/hid-quirks.c 2007-08-29 11:51:07.000000000 +0200
+++ linux-2.6.22.5/drivers/hid/usbhid/hid-quirks.c 2007-08-27 21:21:01.000000000 +0200
@@ -259,6 +259,9 @@
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CM109 0x000e
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -405,6 +408,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
diff -uprN -X linux-2.6.22.5/Documentation/dontdiff linux-2.6.22.5-orig/drivers/input/misc/cm109.c
linux-2.6.22.5/drivers/input/misc/cm109.c
--- linux-2.6.22.5-orig/drivers/input/misc/cm109.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22.5/drivers/input/misc/cm109.c 2007-08-29 11:53:10.000000000 +0200
@@ -0,0 +1,662 @@
+/*
+ * drivers/input/misc/cm109.c
+ *
+ * Copyright (C) 2007 Alfred E. Heggestad <aeh@db.org>
+ *
+ * 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, version 2.
+ */
+
+/*
+ * Description:
+ * Driver for the VoIP USB phones with CM109 chipsets.
+ *
+ * Tested devices:
+ * - Komunikate KIP1000
+ * - Genius G-talk
+ * - ...
+ *
+ * This driver is based on the yealink.c driver
+ *
+ * Thanks to:
+ * - Authors of yealink.c
+ * - Thomas Reitmayr
+ * - Oliver Neukum for good review comments
+ * - Shaun Jackman <sjackman@gmail.com> for Genius G-talk keymap
+ *
+ * History:
+ * 20070829 alfredh Added keymap for Genius G-talk (thanks Shaun)
+ * 20070826 alfredh 2.6.22.5, added to blacklist in hid-quirks.c
+ * 20070626 alfredh 2.6.22-rc6, linux-input peer review
+ * 20070616 alfredh Adapt for kernel 2.6.22-rc4
+ * 20070615 alfredh Change GFP_KERNEL -> GFP_ATOMIC
+ * 20070610 alfredh Buzzer through input SND_TONE/SND_BELL
+ * 20070227 alfredh Draft version with keyboard scan and buzzer
+ *
+ * Todo:
+ * - Run-time selection of phone keymap
+ * - Read/write EEPROM
+ * - Report input events volume up/down
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+
+/* #define CM109_DEBUG 1 */
+
+#define DRIVER_VERSION "20070829"
+#define DRIVER_AUTHOR "Alfred E. Heggestad"
+#define DRIVER_DESC "CM109 phone driver"
+
+static char *phone = "kip1000";
+module_param(phone, charp, S_IRUSR);
+MODULE_PARM_DESC(phone, "Phone name {kip1000, gtalk}");
+
+
+enum {
+ /* HID Registers */
+ HID_IR0 = 0x00, /* Record/Playback-mute button, Volume up/down */
+ HID_IR1 = 0x01, /* GPI, generic registers or EEPROM_DATA0 */
+ HID_IR2 = 0x02, /* Generic registers or EEPROM_DATA1 */
+ HID_IR3 = 0x03, /* Generic registers or EEPROM_CTRL */
+ HID_OR0 = 0x00, /* Mapping control, buzzer, SPDIF (offset 0x04) */
+ HID_OR1 = 0x01, /* GPO - General Purpose Output */
+ HID_OR2 = 0x02, /* Set GPIO to input/output mode */
+ HID_OR3 = 0x03, /* SPDIF status channel or EEPROM_CTRL */
+
+ /* HID_IR0 */
+ RECORD_MUTE = 1 << 3,
+ PLAYBACK_MUTE = 1 << 2,
+ VOLUME_DOWN = 1 << 1,
+ VOLUME_UP = 1 << 0,
+
+ /* HID_OR0 */
+ /* bits 7-6
+ 0: HID_OR1-2 are used for GPO; HID_OR0, 3 are used for buzzer
+ and SPDIF
+ 1: HID_OR0-3 are used as generic HID registers
+ 2: Values written to HID_OR0-3 are also mapped to MCU_CTRL,
+ EEPROM_DATA0-1, EEPROM_CTRL (see Note)
+ 3: Reserved
+ */
+ HID_OR_GPO_BUZ_SPDIF = 0 << 6,
+ HID_OR_GENERIC_HID_REG = 1 << 6,
+ HID_OR_MAP_MCU_EEPROM = 2 << 6,
+
+ BUZZER_ON = 1 << 5,
+};
+
+/* CM109 protocol packet */
+struct cm109_ctl_packet {
+ u8 byte[4];
+} __attribute__ ((packed));
+
+enum {USB_PKT_LEN = sizeof(struct cm109_ctl_packet)};
+
+/* CM109 device structure */
+struct cm109_dev {
+ struct input_dev *idev; /* input device */
+ struct usb_device *udev; /* usb device */
+
+ /* irq input channel */
+ struct cm109_ctl_packet *irq_data;
+ dma_addr_t irq_dma;
+ struct urb *urb_irq;
+
+ /* control output channel */
+ struct cm109_ctl_packet *ctl_data;
+ dma_addr_t ctl_dma;
+ struct usb_ctrlrequest *ctl_req;
+ dma_addr_t ctl_req_dma;
+ struct urb *urb_ctl;
+
+ spinlock_t submit_lock;
+ int disconnecting;
+
+ char phys[64]; /* physical device path */
+ int key_code; /* last reported key */
+ int keybit; /* 0=new scan 1,2,4,8=scan columns */
+ u8 gpi; /* Cached value of GPI (high nibble) */
+};
+
+/*******************************************************************************
+ * CM109 key interface
+ ******************************************************************************/
+
+
+/* Map device buttons to internal key events.
+ *
+ * TODO: This needs a better solutions, so the user can select the
+ * appropriate keymap for the phone in run-time.
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+
+ Komunikate KIP1000 Keyboard Matrix
+
+ -> -- 1 -- 2 -- 3 --> GPI pin 4 (0x10)
+ | | | |
+ <- -- 4 -- 5 -- 6 --> GPI pin 5 (0x20)
+ | | | |
+ END - 7 -- 8 -- 9 --> GPI pin 6 (0x40)
+ | | | |
+ OK -- * -- 0 -- # --> GPI pin 7 (0x80)
+ | | | |
+
+ /|\ /|\ /|\ /|\
+ | | | |
+GPO
+pin: 3 2 1 0
+ 0x8 0x4 0x2 0x1
+
+ */
+static int keymap_kip1000(int scancode)
+{
+ switch (scancode) { /* phone key: */
+ case 0x82: return KEY_0; /* 0 */
+ case 0x14: return KEY_1; /* 1 */
+ case 0x12: return KEY_2; /* 2 */
+ case 0x11: return KEY_3; /* 3 */
+ case 0x24: return KEY_4; /* 4 */
+ case 0x22: return KEY_5; /* 5 */
+ case 0x21: return KEY_6; /* 6 */
+ case 0x44: return KEY_7; /* 7 */
+ case 0x42: return KEY_8; /* 8 */
+ case 0x41: return KEY_9; /* 9 */
+ case 0x81: return KEY_LEFTSHIFT | KEY_3 << 8; /* # */
+ case 0x84: return KEY_KPASTERISK; /* * */
+ case 0x88: return KEY_ENTER; /* pickup */
+ case 0x48: return KEY_ESC; /* hangup */
+ case 0x28: return KEY_LEFT; /* IN */
+ case 0x18: return KEY_RIGHT; /* OUT */
+ }
+ return -EINVAL;
+}
+
+/*
+ Contributed by Shaun Jackman <sjackman@gmail.com>
+
+ Genius G-Talk keyboard matrix
+ 0 1 2 3
+ 4: 0 4 8 Talk
+ 5: 1 5 9 End
+ 6: 2 6 # Up
+ 7: 3 7 * Down
+*/
+static int keymap_gtalk(int scancode)
+{
+ switch (scancode) {
+ case 0x11: return KEY_0;
+ case 0x21: return KEY_1;
+ case 0x41: return KEY_2;
+ case 0x81: return KEY_3;
+ case 0x12: return KEY_4;
+ case 0x22: return KEY_5;
+ case 0x42: return KEY_6;
+ case 0x82: return KEY_7;
+ case 0x14: return KEY_8;
+ case 0x24: return KEY_9;
+ case 0x44: return KEY_LEFTSHIFT | KEY_3 << 8; /* # */
+ case 0x84: return KEY_KPASTERISK;
+ case 0x18: return KEY_ENTER; /* Talk (green handset) */
+ case 0x28: return KEY_ESC; /* End (red handset) */
+ case 0x48: return KEY_UP; /* Menu up (rocker switch) */
+ case 0x88: return KEY_DOWN; /* Menu down (rocker switch) */
+ }
+ return -EINVAL;
+}
+
+static int (*keymap)(int) = keymap_kip1000;
+
+
+/* Completes a request by converting the data into events for the
+ * input subsystem.
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+static void report_key(struct cm109_dev *dev, int key)
+{
+ struct input_dev *idev = dev->idev;
+
+ if (dev->key_code >= 0) {
+ /* old key up */
+ input_report_key(idev, dev->key_code & 0xff, 0);
+ if (dev->key_code >> 8)
+ input_report_key(idev, dev->key_code >> 8, 0);
+ }
+
+ dev->key_code = key;
+ if (key >= 0) {
+ /* new valid key */
+ input_report_key(idev, key & 0xff, 1);
+ if (key >> 8)
+ input_report_key(idev, key >> 8, 1);
+ }
+ input_sync(idev);
+}
+
+/*******************************************************************************
+ * CM109 usb communication interface
+ ******************************************************************************/
+
+
+/*
+ * IRQ handler
+ */
+static void urb_irq_callback(struct urb *urb)
+{
+ struct cm109_dev *dev = urb->context;
+ int ret;
+
+#ifdef CM109_DEBUG
+ dbg("### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x",
+ dev->irq_data->byte[0],
+ dev->irq_data->byte[1],
+ dev->irq_data->byte[2],
+ dev->irq_data->byte[3],
+ dev->keybit);
+#endif
+
+ if (urb->status) {
+ if (-ESHUTDOWN == urb->status)
+ return;
+ err("%s - urb status %d", __FUNCTION__, urb->status);
+ }
+
+ /* Scan key column */
+ if (0xf == dev->keybit) {
+
+ /* Any changes ? */
+ if ((dev->gpi & 0xf0) == (dev->irq_data->byte[HID_IR1] & 0xf0)) {
+ goto out;
+ }
+
+ dev->gpi = dev->irq_data->byte[HID_IR1] & 0xf0;
+
+ dev->keybit = 0x1;
+ } else {
+ report_key(dev, keymap(dev->irq_data->byte[HID_IR1]));
+
+ dev->keybit <<= 1;
+ if (dev->keybit > 0x8)
+ dev->keybit = 0xf;
+ }
+
+ dev->ctl_data->byte[HID_OR1] = dev->keybit;
+ dev->ctl_data->byte[HID_OR2] = dev->keybit;
+
+ out:
+ ret = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+ if (ret)
+ err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+static void urb_ctl_callback(struct urb *urb)
+{
+ struct cm109_dev *dev = urb->context;
+ int ret = 0;
+
+#ifdef CM109_DEBUG
+ dbg("### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]",
+ dev->ctl_data->byte[0],
+ dev->ctl_data->byte[1],
+ dev->ctl_data->byte[2],
+ dev->ctl_data->byte[3]);
+#endif
+
+ if (urb->status)
+ err("%s - urb status %d", __FUNCTION__, urb->status);
+
+ spin_lock(&dev->submit_lock);
+ /* ask for a response */
+ if (!dev->disconnecting)
+ ret = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
+ spin_unlock(&dev->submit_lock);
+
+ if (ret)
+ err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+/*******************************************************************************
+ * input event interface
+ ******************************************************************************/
+
+static DEFINE_SPINLOCK(cm109_buzz_lock);
+
+static int input_open(struct input_dev *idev)
+{
+ struct cm109_dev *dev = input_get_drvdata(idev);
+ int ret;
+
+ dev->key_code = -1; /* no keys pressed */
+ dev->keybit = 0xf;
+
+ /* issue INIT */
+ dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
+ dev->ctl_data->byte[HID_OR1] = dev->keybit;
+ dev->ctl_data->byte[HID_OR2] = dev->keybit;
+ dev->ctl_data->byte[HID_OR3] = 0x00;
+
+ if ((ret = usb_submit_urb(dev->urb_ctl, GFP_KERNEL)) != 0) {
+ err("%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void input_close(struct input_dev *idev)
+{
+ struct cm109_dev *dev = input_get_drvdata(idev);
+
+ usb_kill_urb(dev->urb_ctl);
+ usb_kill_urb(dev->urb_irq);
+}
+
+static void buzz(struct cm109_dev *dev, int on)
+{
+ int ret;
+
+ if (dev == NULL) {
+ err("buzz: dev is NULL");
+ return;
+ }
+
+ dbg("Buzzer %s", on ? "on" : "off");
+ if (on)
+ dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+ else
+ dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+ ret = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+ if (ret)
+ err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+static int input_ev(struct input_dev *idev, unsigned int type,
+ unsigned int code, int value)
+{
+ struct cm109_dev *dev = input_get_drvdata(idev);
+ unsigned long flags;
+
+#ifdef CM109_DEBUG
+ info("input_ev: type=%u code=%u value=%d", type, code, value);
+#endif
+
+ if (type != EV_SND)
+ return -EINVAL;
+
+ switch (code) {
+ case SND_TONE:
+ case SND_BELL:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&cm109_buzz_lock, flags);
+ buzz(dev, value);
+ spin_unlock_irqrestore(&cm109_buzz_lock, flags);
+
+ return 0;
+}
+
+
+/*******************************************************************************
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+struct driver_info {
+ char *name;
+};
+
+static const struct driver_info info_cm109 = {
+ .name = "CM109 USB driver",
+};
+
+enum {
+ VENDOR_ID = 0x0d8c, /* C-Media Electronics */
+ PRODUCT_ID_CM109 = 0x000e, /* CM109 defines range 0x0008 - 0x000f */
+};
+
+/* table of devices that work with this driver */
+static const struct usb_device_id usb_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = VENDOR_ID,
+ .idProduct = PRODUCT_ID_CM109,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t) & info_cm109},
+ /* you can add more devices here with product ID 0x0008 - 0x000f */
+ {}
+};
+
+static int usb_cleanup(struct cm109_dev *dev, int err)
+{
+ if (dev == NULL)
+ return err;
+
+ usb_kill_urb(dev->urb_irq); /* parameter validation in core/urb */
+ usb_kill_urb(dev->urb_ctl); /* parameter validation in core/urb */
+
+ if (dev->idev) {
+ if (err)
+ input_free_device(dev->idev);
+ else
+ input_unregister_device(dev->idev);
+ }
+ if (dev->ctl_req)
+ usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)),
+ dev->ctl_req, dev->ctl_req_dma);
+ if (dev->ctl_data)
+ usb_buffer_free(dev->udev, USB_PKT_LEN,
+ dev->ctl_data, dev->ctl_dma);
+ if (dev->irq_data)
+ usb_buffer_free(dev->udev, USB_PKT_LEN,
+ dev->irq_data, dev->irq_dma);
+
+ usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
+ usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
+ kfree(dev);
+
+ return err;
+}
+
+static void usb_disconnect(struct usb_interface *interface)
+{
+ struct cm109_dev *dev;
+
+ dev = usb_get_intfdata(interface);
+
+ /* Wait for URB idle */
+ spin_lock_irq(&dev->submit_lock);
+ dev->disconnecting = 1;
+ spin_unlock_irq(&dev->submit_lock);
+
+ usb_set_intfdata(interface, NULL);
+
+ usb_cleanup(dev, 0);
+}
+
+static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct driver_info *nfo = (struct driver_info *)id->driver_info;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct cm109_dev *dev;
+ struct input_dev *input_dev;
+ int ret, pipe, i;
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+
+ if (!usb_endpoint_is_int_in(endpoint))
+ return -ENODEV;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ spin_lock_init(&dev->submit_lock);
+ dev->disconnecting = 0;
+
+ dev->udev = udev;
+
+ dev->idev = input_dev = input_allocate_device();
+ if (!input_dev)
+ goto err;
+
+ /* allocate usb buffers */
+ dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+ GFP_KERNEL, &dev->irq_dma);
+ if (dev->irq_data == NULL)
+ goto err;
+
+ dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+ GFP_KERNEL, &dev->ctl_dma);
+ if (!dev->ctl_data)
+ goto err;
+
+ dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)),
+ GFP_KERNEL, &dev->ctl_req_dma);
+ if (dev->ctl_req == NULL)
+ goto err;
+
+ /* allocate urb structures */
+ dev->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (dev->urb_irq == NULL)
+ goto err;
+
+ dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+ if (dev->urb_ctl == NULL)
+ goto err;
+
+ /* get a handle to the interrupt data pipe */
+ pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+ ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ if (ret != USB_PKT_LEN)
+ err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+
+ /* initialise irq urb */
+ usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
+ USB_PKT_LEN,
+ urb_irq_callback, dev, endpoint->bInterval);
+ dev->urb_irq->transfer_dma = dev->irq_dma;
+ dev->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ dev->urb_irq->dev = udev;
+
+ /* initialise ctl urb */
+ dev->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+ USB_DIR_OUT;
+ dev->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
+ dev->ctl_req->wValue = cpu_to_le16(0x200);
+ dev->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
+ dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
+
+ usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+ (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
+ urb_ctl_callback, dev);
+ dev->urb_ctl->setup_dma = dev->ctl_req_dma;
+ dev->urb_ctl->transfer_dma = dev->ctl_dma;
+ dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
+ URB_NO_TRANSFER_DMA_MAP;
+ dev->urb_ctl->dev = udev;
+
+ /* find out the physical bus location */
+ usb_make_path(udev, dev->phys, sizeof(dev->phys));
+ strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+ /* register settings for the input device */
+ input_dev->name = nfo->name;
+ input_dev->phys = dev->phys;
+ usb_to_input_id(udev, &input_dev->id);
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, dev);
+ input_dev->open = input_open;
+ input_dev->close = input_close;
+ input_dev->event = input_ev;
+
+ /* register available key events */
+ input_dev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; i < 256; i++) {
+ int k = keymap(i);
+ if (k >= 0) {
+ set_bit(k & 0xff, input_dev->keybit);
+ if (k >> 8)
+ set_bit(k >> 8, input_dev->keybit);
+ }
+ }
+
+ input_dev->evbit[0] |= BIT(EV_SND);
+ input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+
+ ret = input_register_device(dev->idev);
+ if (ret)
+ goto err;
+
+ usb_set_intfdata(intf, dev);
+
+ return 0;
+
+ err:
+ return usb_cleanup(dev, -ENOMEM);
+}
+
+static struct usb_driver cm109_driver = {
+ .name = "cm109",
+ .probe = usb_probe,
+ .disconnect = usb_disconnect,
+ .id_table = usb_table,
+};
+
+static int __init cm109_dev_init(void)
+{
+ int ret;
+
+ /* Load the phone keymap */
+ if (0 == strcasecmp(phone, "kip1000")) {
+ keymap = keymap_kip1000;
+ info("Keymap for Komunikate KIP1000 phone loaded");
+ }
+ else if (0 == strcasecmp(phone, "gtalk")) {
+ keymap = keymap_gtalk;
+ info("Keymap for Genius G-talk phone loaded");
+ }
+ else {
+ err("Unsupported phone: %s", phone);
+ return -EINVAL;
+ }
+
+ ret = usb_register(&cm109_driver);
+ if (ret == 0)
+ info(DRIVER_DESC ": " DRIVER_VERSION " (C) " DRIVER_AUTHOR);
+
+ return ret;
+}
+
+static void __exit cm109_dev_exit(void)
+{
+ usb_deregister(&cm109_driver);
+}
+
+module_init(cm109_dev_init);
+module_exit(cm109_dev_exit);
+
+MODULE_DEVICE_TABLE(usb, usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -uprN -X linux-2.6.22.5/Documentation/dontdiff linux-2.6.22.5-orig/drivers/input/misc/Kconfig
linux-2.6.22.5/drivers/input/misc/Kconfig
--- linux-2.6.22.5-orig/drivers/input/misc/Kconfig 2007-08-29 11:51:07.000000000 +0200
+++ linux-2.6.22.5/drivers/input/misc/Kconfig 2007-08-27 21:21:01.000000000 +0200
@@ -161,6 +161,18 @@ config INPUT_YEALINK
To compile this driver as a module, choose M here: the module will be
called yealink.
+config INPUT_CM109
+ tristate "C-Media CM109 USB I/O Controller"
+ depends on INPUT && EXPERIMENTAL
+ select USB
+ ---help---
+ Say Y here if you want to enable keyboard and buzzer functions of the
+ C-Media CM109 usb phones. The audio part is enabled by the generic
+ usb sound driver, so you might want to enable that as well.
+
+ To compile this driver as a module, choose M here: the module will be
+ called cm109.
+
config INPUT_UINPUT
tristate "User level driver support"
help
diff -uprN -X linux-2.6.22.5/Documentation/dontdiff linux-2.6.22.5-orig/drivers/input/misc/Makefile
linux-2.6.22.5/drivers/input/misc/Makefile
--- linux-2.6.22.5-orig/drivers/input/misc/Makefile 2007-08-29 11:51:07.000000000 +0200
+++ linux-2.6.22.5/drivers/input/misc/Makefile 2007-08-27 21:21:01.000000000 +0200
@@ -16,5 +16,6 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
+obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-29 9:59 ` Alfred E. Heggestad
@ 2007-08-29 10:21 ` Jiri Kosina
2007-08-29 19:37 ` Shaun Jackman
1 sibling, 0 replies; 11+ messages in thread
From: Jiri Kosina @ 2007-08-29 10:21 UTC (permalink / raw)
To: Alfred E. Heggestad; +Cc: Shaun Jackman, linux-input
On Wed, 29 Aug 2007, Alfred E. Heggestad wrote:
> here is an updated version of the CM109 driver, now supporting both
> KIP1000 and Genius G-talk USB phones. The keymap can be selecting when
> loading the module using the "phone" parameter.
I will queue the addition to usbhid quirk list in my tree. The driver
itself should be submitted to Dmitry.
Thanks,
--
Jiri Kosina
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
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
1 sibling, 1 reply; 11+ messages in thread
From: Shaun Jackman @ 2007-08-29 19:37 UTC (permalink / raw)
To: Alfred E. Heggestad; +Cc: Jiri Kosina, linux-input
On 8/29/07, Alfred E. Heggestad <aeh@db.org> wrote:
> here is an updated version of the CM109 driver, now supporting both KIP1000
...
> diff -uprN -X linux-2.6.22.5/Documentation/dontdiff linux-2.6.22.5-orig/drivers/hid/usbhid/hid-quirks.c
> linux-2.6.22.5/drivers/hid/usbhid/hid-quirks.c
> --- linux-2.6.22.5-orig/drivers/hid/usbhid/hid-quirks.c 2007-08-29 11:51:07.000000000 +0200
> +++ linux-2.6.22.5/drivers/hid/usbhid/hid-quirks.c 2007-08-27 21:21:01.000000000 +0200
> @@ -259,6 +259,9 @@
> #define USB_VENDOR_ID_YEALINK 0x6993
> #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
>
> +#define USB_VENDOR_ID_CMEDIA 0x0d8c
> +#define USB_DEVICE_ID_CM109 0x000e
> +
> /*
> * Alphabetically sorted blacklist by quirk type.
> */
> @@ -405,6 +408,7 @@ static const struct hid_blacklist {
> { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
> { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
> { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
> + { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
>
> { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
> { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
A minor detail, but the CMEDIA entry should be sorted alphabetically,
as the comment says. See below.
Cheers,
Shaun
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 6b21a21..a435f5b 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -90,6 +90,9 @@
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CMEDIA_CM109 0x000e
+
#define USB_VENDOR_ID_CYPRESS 0x04b4
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
@@ -387,6 +390,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_CM109, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: USB: driver for CM109 chipset
2007-08-29 19:37 ` Shaun Jackman
@ 2007-08-29 23:07 ` Jiri Kosina
0 siblings, 0 replies; 11+ messages in thread
From: Jiri Kosina @ 2007-08-29 23:07 UTC (permalink / raw)
To: Shaun Jackman; +Cc: Alfred E. Heggestad, linux-input
On Wed, 29 Aug 2007, Shaun Jackman wrote:
> > @@ -405,6 +408,7 @@ static const struct hid_blacklist {
> > { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
> > { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
> > { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
> > + { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
> >
> > { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
> > { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
> A minor detail, but the CMEDIA entry should be sorted alphabetically,
> as the comment says. See below.
I have already fixed up the Alfred's patch when merging it into my tree,
but thanks anyway!
--
Jiri Kosina
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2007-08-29 23:07 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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
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).