File: usbcompat.c

package info (click to toggle)
alsa-driver 1.0.13-5etch1
  • links: PTS
  • area: main
  • in suites: etch
  • size: 20,108 kB
  • ctags: 50,477
  • sloc: ansic: 319,881; sh: 32,930; makefile: 2,015; python: 1,527; perl: 1,316; xml: 896; awk: 66
file content (145 lines) | stat: -rw-r--r-- 4,323 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/version.h>

#include <linux/module.h>
#include <linux/usb.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)

struct snd_compat_usb_device_id {
	__u16		match_flags;
	__u16		idVendor;
	__u16		idProduct;
	__u16		bcdDevice_lo, bcdDevice_hi;
	__u8		bDeviceClass;
	__u8		bDeviceSubClass;
	__u8		bDeviceProtocol;
	__u8		bInterfaceClass;
	__u8		bInterfaceSubClass;
	__u8		bInterfaceProtocol;
	unsigned long	driver_info;
};

struct usb_device;
struct usb_interface;

struct snd_compat_usb_driver {
	const char *name;
	void *(*probe)(struct usb_device *dev, unsigned intf, const struct snd_compat_usb_device_id *id);
	void (*disconnect)(struct usb_device *, void *);
	struct list_head driver_list;
	const struct snd_compat_usb_device_id *id_table;
};

int snd_compat_usb_register(struct snd_compat_usb_driver *);
void snd_compat_usb_deregister(struct snd_compat_usb_driver *);
void snd_compat_usb_driver_claim_interface(struct snd_compat_usb_driver *, struct usb_interface *iface, void *ptr);

#define USB_DEVICE_ID_MATCH_VENDOR		0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT		0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO		0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI		0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS		0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS	0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL	0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS		0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS	0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL	0x0200

#define MAX_USB_DRIVERS	5
struct snd_usb_reg_table {
	struct usb_driver driver;
	struct snd_compat_usb_driver *orig;
};

static struct snd_usb_reg_table my_usb_drivers[MAX_USB_DRIVERS];

static void *snd_usb_compat_probe(struct usb_device *dev, unsigned int ifnum)
{
	struct snd_compat_usb_driver *p;
	struct usb_interface_descriptor *alts = usb_ifnum_to_if(dev, ifnum)->altsetting;
	const struct snd_compat_usb_device_id *tbl;
	struct snd_compat_usb_device_id id;
	int i;

	for (i = 0; i < MAX_USB_DRIVERS; i++) {
		if (! (p = my_usb_drivers[i].orig))
			continue;
		for (tbl = p->id_table; tbl->match_flags; tbl++) {
			/* we are too lazy to check all entries... */
			if ((tbl->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
			    tbl->idVendor != dev->descriptor.idVendor)
				continue;
			if ((tbl->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
			    tbl->idProduct != dev->descriptor.idProduct)
				continue;
			if ((tbl->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
			    tbl->bInterfaceClass != alts->bInterfaceClass)
				continue;
			if ((tbl->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
			    tbl->bInterfaceSubClass != alts->bInterfaceSubClass)
				continue;
			id = *tbl;
			id.idVendor = dev->descriptor.idVendor;
			id.idProduct = dev->descriptor.idProduct;
			id.bInterfaceClass = alts->bInterfaceClass;
			id.bInterfaceSubClass = alts->bInterfaceSubClass;
			return p->probe(dev, ifnum, &id);
		}
	}
	return NULL;
}

int snd_compat_usb_register(struct snd_compat_usb_driver *driver)
{
	int i;
	struct usb_driver *drv;

	for (i = 0; i < MAX_USB_DRIVERS; i++) {
		if (! my_usb_drivers[i].orig)
			break;
	}
	if (i >= MAX_USB_DRIVERS)
		return -ENOMEM;
	my_usb_drivers[i].orig = driver;
	drv = &my_usb_drivers[i].driver;
	drv->name = driver->name;
	drv->probe = snd_usb_compat_probe;
	drv->disconnect = driver->disconnect;
	INIT_LIST_HEAD(&drv->driver_list);
	usb_register(drv);
	return 0;
}

static struct snd_usb_reg_table *find_matching_usb_driver(struct snd_compat_usb_driver *driver)
{
	int i;
	for (i = 0; i < MAX_USB_DRIVERS; i++) {
		if (my_usb_drivers[i].orig == driver)
			return &my_usb_drivers[i];
	}
	return NULL;
}

void snd_compat_usb_deregister(struct snd_compat_usb_driver *driver)
{
	struct snd_usb_reg_table *tbl;	
	if ((tbl = find_matching_usb_driver(driver)) != NULL) {
		usb_deregister(&tbl->driver);
		tbl->orig = NULL;
	}
}

void snd_compat_usb_driver_claim_interface(struct snd_compat_usb_driver *driver, struct usb_interface *iface, void *ptr)
{
	struct snd_usb_reg_table *tbl;
	if ((tbl = find_matching_usb_driver(driver)) != NULL)
		usb_driver_claim_interface(&tbl->driver, iface, ptr);
}

EXPORT_SYMBOL(snd_compat_usb_register);
EXPORT_SYMBOL(snd_compat_usb_deregister);
EXPORT_SYMBOL(snd_compat_usb_driver_claim_interface);

#endif /* LINUX_VERSION < 2.3.0 */