Commit | Line | Data |
---|---|---|
b11869db PE |
1 | /* |
2 | * Copyright (C) 2008 Sensoray Company Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License (Version 2) as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software Foundation, | |
15 | * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/init.h> | |
1d03d2bd | 20 | #include <linux/smp_lock.h> |
b11869db PE |
21 | #include <linux/usb.h> |
22 | #include <dvb-usb.h> | |
23 | ||
24 | #define S2250_LOADER_FIRMWARE "s2250_loader.fw" | |
25 | #define S2250_FIRMWARE "s2250.fw" | |
26 | ||
27 | typedef struct device_extension_s { | |
28 | struct kref kref; | |
29 | int minor; | |
30 | struct usb_device *usbdev; | |
31 | } device_extension_t, *pdevice_extension_t; | |
32 | ||
33 | #define USB_s2250loader_MAJOR 240 | |
34 | #define USB_s2250loader_MINOR_BASE 0 | |
35 | #define MAX_DEVICES 256 | |
36 | ||
37 | static pdevice_extension_t s2250_dev_table[MAX_DEVICES]; | |
fd9a40da | 38 | static DEFINE_MUTEX(s2250_dev_table_mutex); |
b11869db PE |
39 | |
40 | #define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref) | |
41 | static void s2250loader_delete(struct kref *kref) | |
42 | { | |
43 | pdevice_extension_t s = to_s2250loader_dev_common(kref); | |
44 | s2250_dev_table[s->minor] = NULL; | |
45 | kfree(s); | |
46 | } | |
47 | ||
48 | static int s2250loader_probe(struct usb_interface *interface, | |
49 | const struct usb_device_id *id) | |
50 | { | |
51 | struct usb_device *usbdev; | |
52 | int minor, ret; | |
53 | pdevice_extension_t s = NULL; | |
54 | const struct firmware *fw; | |
55 | ||
56 | usbdev = usb_get_dev(interface_to_usbdev(interface)); | |
57 | if (!usbdev) { | |
58 | printk(KERN_ERR "Enter s2250loader_probe failed\n"); | |
59 | return -1; | |
60 | } | |
61 | printk(KERN_INFO "Enter s2250loader_probe 2.6 kernel\n"); | |
62 | printk(KERN_INFO "vendor id 0x%x, device id 0x%x devnum:%d\n", | |
63 | usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, | |
64 | usbdev->devnum); | |
65 | ||
66 | if (usbdev->descriptor.bNumConfigurations != 1) { | |
67 | printk(KERN_ERR "can't handle multiple config\n"); | |
68 | return -1; | |
69 | } | |
fd9a40da | 70 | mutex_lock(&s2250_dev_table_mutex); |
b11869db PE |
71 | |
72 | for (minor = 0; minor < MAX_DEVICES; minor++) { | |
73 | if (s2250_dev_table[minor] == NULL) | |
74 | break; | |
75 | } | |
76 | ||
77 | if (minor < 0 || minor >= MAX_DEVICES) { | |
78 | printk(KERN_ERR "Invalid minor: %d\n", minor); | |
79 | goto failed; | |
80 | } | |
81 | ||
82 | /* Allocate dev data structure */ | |
83 | s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); | |
84 | if (s == NULL) { | |
85 | printk(KERN_ERR "Out of memory\n"); | |
86 | goto failed; | |
87 | } | |
88 | s2250_dev_table[minor] = s; | |
89 | ||
90 | printk(KERN_INFO "s2250loader_probe: Device %d on Bus %d Minor %d\n", | |
91 | usbdev->devnum, usbdev->bus->busnum, minor); | |
92 | ||
93 | memset(s, 0, sizeof(device_extension_t)); | |
94 | s->usbdev = usbdev; | |
95 | printk(KERN_INFO "loading 2250 loader\n"); | |
96 | ||
97 | kref_init(&(s->kref)); | |
98 | ||
fd9a40da | 99 | mutex_unlock(&s2250_dev_table_mutex); |
b11869db PE |
100 | |
101 | if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { | |
102 | printk(KERN_ERR | |
103 | "s2250: unable to load firmware from file \"%s\"\n", | |
104 | S2250_LOADER_FIRMWARE); | |
105 | goto failed2; | |
106 | } | |
107 | ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); | |
108 | release_firmware(fw); | |
109 | if (0 != ret) { | |
110 | printk(KERN_ERR "loader download failed\n"); | |
111 | goto failed2; | |
112 | } | |
113 | ||
114 | if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { | |
115 | printk(KERN_ERR | |
116 | "s2250: unable to load firmware from file \"%s\"\n", | |
117 | S2250_FIRMWARE); | |
118 | goto failed2; | |
119 | } | |
120 | ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); | |
121 | release_firmware(fw); | |
122 | if (0 != ret) { | |
123 | printk(KERN_ERR "firmware_s2250 download failed\n"); | |
124 | goto failed2; | |
125 | } | |
126 | ||
127 | usb_set_intfdata(interface, s); | |
128 | return 0; | |
129 | ||
130 | failed: | |
fd9a40da | 131 | mutex_unlock(&s2250_dev_table_mutex); |
b11869db PE |
132 | failed2: |
133 | if (s) | |
134 | kref_put(&(s->kref), s2250loader_delete); | |
135 | ||
136 | printk(KERN_ERR "probe failed\n"); | |
137 | return -1; | |
138 | } | |
139 | ||
140 | static void s2250loader_disconnect(struct usb_interface *interface) | |
141 | { | |
142 | pdevice_extension_t s = usb_get_intfdata(interface); | |
143 | printk(KERN_INFO "s2250: disconnect\n"); | |
144 | lock_kernel(); | |
145 | s = usb_get_intfdata(interface); | |
146 | usb_set_intfdata(interface, NULL); | |
147 | kref_put(&(s->kref), s2250loader_delete); | |
148 | unlock_kernel(); | |
149 | } | |
150 | ||
151 | static struct usb_device_id s2250loader_ids[] = { | |
152 | {USB_DEVICE(0x1943, 0xa250)}, | |
153 | {} /* Terminating entry */ | |
154 | }; | |
155 | ||
156 | MODULE_DEVICE_TABLE(usb, s2250loader_ids); | |
157 | ||
158 | static struct usb_driver s2250loader_driver = { | |
159 | .name = "s2250-loader", | |
160 | .probe = s2250loader_probe, | |
161 | .disconnect = s2250loader_disconnect, | |
162 | .id_table = s2250loader_ids, | |
163 | }; | |
164 | ||
165 | int s2250loader_init(void) | |
166 | { | |
167 | int r; | |
168 | unsigned i = 0; | |
169 | ||
170 | for (i = 0; i < MAX_DEVICES; i++) | |
171 | s2250_dev_table[i] = NULL; | |
172 | ||
173 | r = usb_register(&s2250loader_driver); | |
174 | if (r) { | |
175 | printk(KERN_ERR "usb_register failed. Error number %d\n", r); | |
176 | return -1; | |
177 | } | |
178 | ||
179 | printk(KERN_INFO "s2250loader_init: driver registered\n"); | |
180 | return 0; | |
181 | } | |
182 | EXPORT_SYMBOL(s2250loader_init); | |
183 | ||
184 | void s2250loader_cleanup(void) | |
185 | { | |
186 | printk(KERN_INFO "s2250loader_cleanup\n"); | |
187 | usb_deregister(&s2250loader_driver); | |
188 | } | |
189 | EXPORT_SYMBOL(s2250loader_cleanup); |