]> err.no Git - linux-2.6/blob - drivers/media/mdtv/smsusb.c
V4L/DVB (8266): sms1xxx: merge modules
[linux-2.6] / drivers / media / mdtv / smsusb.c
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <linux/usb.h>
5 #include <linux/firmware.h>
6
7 #include "smscoreapi.h"
8
9 #define USB_VID_SIANO   0x187f
10 #define USB_PID_0010    0x0010
11 #define USB_PID_0100    0x0100
12 #define USB_PID_0200    0x0200
13
14 #define USB1_BUFFER_SIZE                0x1000
15 #define USB2_BUFFER_SIZE                0x4000
16
17 #define MAX_BUFFERS             50
18 #define MAX_URBS                10
19
20 typedef struct _smsusb_device smsusb_device_t;
21
22 typedef struct _smsusb_urb
23 {
24         smscore_buffer_t *cb;
25         smsusb_device_t *dev;
26
27         struct urb              urb;
28 } smsusb_urb_t;
29
30 typedef struct _smsusb_device
31 {
32         struct usb_device* udev;
33         smscore_device_t *coredev;
34
35         smsusb_urb_t    surbs[MAX_URBS];
36
37         int                             response_alignment;
38         int                             buffer_size;
39 } *psmsusb_device_t;
40
41 static struct usb_device_id smsusb_id_table [] = {
42         { USB_DEVICE(USB_VID_SIANO, USB_PID_0010) },
43         { USB_DEVICE(USB_VID_SIANO, USB_PID_0100) },
44         { USB_DEVICE(USB_VID_SIANO, USB_PID_0200) },
45         { }             /* Terminating entry */
46 };
47 MODULE_DEVICE_TABLE (usb, smsusb_id_table);
48
49 int smsusb_submit_urb(smsusb_device_t* dev, smsusb_urb_t* surb);
50
51 void smsusb_onresponse(struct urb *urb)
52 {
53         smsusb_urb_t *surb = (smsusb_urb_t *) urb->context;
54         smsusb_device_t *dev = surb->dev;
55
56         if (urb->status < 0)
57         {
58                 printk(KERN_INFO "%s error, urb status %d, %d bytes\n", __FUNCTION__, urb->status, urb->actual_length);
59                 return;
60         }
61
62         if (urb->actual_length > 0)
63         {
64                 SmsMsgHdr_ST *phdr = (SmsMsgHdr_ST *) surb->cb->p;
65
66                 if (urb->actual_length >= phdr->msgLength)
67                 {
68                         surb->cb->size = phdr->msgLength;
69
70                         if (dev->response_alignment && (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG))
71                         {
72                                 surb->cb->offset = dev->response_alignment + ((phdr->msgFlags >> 8) & 3);
73
74                                 // sanity check
75                                 if (((int) phdr->msgLength + surb->cb->offset) > urb->actual_length)
76                                 {
77                                         printk("%s: invalid response msglen %d offset %d size %d\n", __FUNCTION__, phdr->msgLength, surb->cb->offset, urb->actual_length);
78                                         goto exit_and_resubmit;
79                                 }
80
81                                 // move buffer pointer and copy header to its new location
82                                 memcpy((char*) phdr + surb->cb->offset, phdr, sizeof(SmsMsgHdr_ST));
83                         }
84                         else
85                                 surb->cb->offset = 0;
86
87                         smscore_onresponse(dev->coredev, surb->cb);
88                         surb->cb = NULL;
89                 }
90                 else
91                 {
92                         printk("%s invalid response msglen %d actual %d\n", __FUNCTION__, phdr->msgLength, urb->actual_length);
93                 }
94         }
95
96 exit_and_resubmit:
97         smsusb_submit_urb(dev, surb);
98 }
99
100 int smsusb_submit_urb(smsusb_device_t* dev, smsusb_urb_t* surb)
101 {
102         if (!surb->cb)
103         {
104                 surb->cb = smscore_getbuffer(dev->coredev);
105                 if (!surb->cb)
106                 {
107                         printk(KERN_INFO "%s smscore_getbuffer(...) returned NULL\n", __FUNCTION__);
108                         return -ENOMEM;
109                 }
110         }
111
112         usb_fill_bulk_urb(
113                 &surb->urb,
114                 dev->udev,
115                 usb_rcvbulkpipe(dev->udev, 0x81),
116                 surb->cb->p,
117                 dev->buffer_size,
118                 smsusb_onresponse,
119                 surb
120         );
121         surb->urb.transfer_dma = surb->cb->phys;
122         surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
123
124         return usb_submit_urb(&surb->urb, GFP_ATOMIC);
125 }
126
127 void smsusb_stop_streaming(smsusb_device_t* dev)
128 {
129         int i;
130
131         for (i = 0; i < MAX_URBS; i ++)
132         {
133                 usb_kill_urb(&dev->surbs[i].urb);
134
135                 if (dev->surbs[i].cb)
136                 {
137                         smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
138                         dev->surbs[i].cb = NULL;
139                 }
140         }
141 }
142
143 int smsusb_start_streaming(smsusb_device_t* dev)
144 {
145         int i, rc;
146
147         for (i = 0; i < MAX_URBS; i ++)
148         {
149                 rc = smsusb_submit_urb(dev, &dev->surbs[i]);
150                 if (rc < 0)
151                 {
152                         printk(KERN_INFO "%s smsusb_submit_urb(...) failed\n", __FUNCTION__);
153                         smsusb_stop_streaming(dev);
154                         break;
155                 }
156         }
157
158         return rc;
159 }
160
161 int smsusb_sendrequest(void *context, void *buffer, size_t size)
162 {
163         smsusb_device_t* dev = (smsusb_device_t*) context;
164         int dummy;
165
166         return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000);
167 }
168
169 char *smsusb1_fw_lkup[] =
170 {
171         "dvbt_stellar_usb.inp",
172         "dvbh_stellar_usb.inp",
173         "tdmb_stellar_usb.inp",
174         "none",
175         "dvbt_bda_stellar_usb.inp",
176 };
177
178 int smsusb1_load_firmware(struct usb_device *udev, int id)
179 {
180         const struct firmware *fw;
181         u8* fw_buffer;
182         int rc, dummy;
183
184         if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA)
185         {
186                 printk(KERN_INFO "%s invalid firmware id specified %d\n", __FUNCTION__, id);
187                 return -EINVAL;
188         }
189
190         rc = request_firmware(&fw, smsusb1_fw_lkup[id], &udev->dev);
191         if (rc < 0)
192         {
193                 printk(KERN_INFO "%s failed to open \"%s\" mode %d\n", __FUNCTION__, smsusb1_fw_lkup[id], id);
194                 return rc;
195         }
196
197         fw_buffer = kmalloc(fw->size, GFP_KERNEL);
198         if (fw_buffer)
199         {
200                 memcpy(fw_buffer, fw->data, fw->size);
201
202                 rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000);
203
204                 printk(KERN_INFO "%s: sent %d(%d) bytes, rc %d\n", __FUNCTION__, fw->size, dummy, rc);
205
206                 kfree(fw_buffer);
207         }
208         else
209         {
210                 printk(KERN_INFO "failed to allocate firmware buffer\n");
211                 rc = -ENOMEM;
212         }
213
214         release_firmware(fw);
215
216         return rc;
217 }
218
219 void smsusb1_detectmode(void *context, int *mode)
220 {
221         char *product_string = ((smsusb_device_t *) context)->udev->product;
222
223         *mode = DEVICE_MODE_NONE;
224
225         if (!product_string)
226         {
227                 product_string = "none";
228                 printk("%s product string not found\n", __FUNCTION__);
229         }
230         else
231         {
232                 if (strstr(product_string, "DVBH"))
233                         *mode = 1;
234                 else if (strstr(product_string, "BDA"))
235                         *mode = 4;
236                 else if (strstr(product_string, "DVBT"))
237                         *mode = 0;
238                 else if (strstr(product_string, "TDMB"))
239                         *mode = 2;
240         }
241
242         printk("%s: %d \"%s\"\n", __FUNCTION__, *mode, product_string);
243 }
244
245 int smsusb1_setmode(void *context, int mode)
246 {
247         SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, sizeof(SmsMsgHdr_ST), 0 };
248
249         if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA)
250         {
251                 printk(KERN_INFO "%s invalid firmware id specified %d\n", __FUNCTION__, mode);
252                 return -EINVAL;
253         }
254
255         return smsusb_sendrequest(context, &Msg, sizeof(Msg));
256 }
257
258 void smsusb_term_device(struct usb_interface *intf)
259 {
260         smsusb_device_t *dev = (smsusb_device_t*) usb_get_intfdata(intf);
261
262         if (dev)
263         {
264                 smsusb_stop_streaming(dev);
265
266                 // unregister from smscore
267                 if (dev->coredev)
268                         smscore_unregister_device(dev->coredev);
269
270                 kfree(dev);
271
272                 printk(KERN_INFO "%s device %p destroyed\n", __FUNCTION__, dev);
273         }
274
275         usb_set_intfdata(intf, NULL);
276 }
277
278 int smsusb_init_device(struct usb_interface *intf)
279 {
280         smsdevice_params_t params;
281         smsusb_device_t* dev;
282         int i, rc;
283
284         // create device object
285         dev = kzalloc(sizeof(smsusb_device_t), GFP_KERNEL);
286         if (!dev)
287         {
288                 printk(KERN_INFO "%s kzalloc(sizeof(smsusb_device_t) failed\n", __FUNCTION__);
289                 return -ENOMEM;
290         }
291
292         memset(&params, 0, sizeof(params));
293         usb_set_intfdata(intf, dev);
294         dev->udev = interface_to_usbdev(intf);
295
296         switch (dev->udev->descriptor.idProduct)
297         {
298                 case USB_PID_0100:
299                         dev->buffer_size = USB1_BUFFER_SIZE;
300
301                         params.setmode_handler = smsusb1_setmode;
302                         params.detectmode_handler = smsusb1_detectmode;
303                         break;
304
305                 default:
306                         dev->buffer_size = USB2_BUFFER_SIZE;
307                         dev->response_alignment = dev->udev->ep_in[1]->desc.wMaxPacketSize - sizeof(SmsMsgHdr_ST);
308
309                         params.flags |= SMS_DEVICE_FAMILY2;
310                         break;
311         }
312
313         params.device = &dev->udev->dev;
314         params.buffer_size = dev->buffer_size;
315         params.num_buffers = MAX_BUFFERS;
316         params.sendrequest_handler = smsusb_sendrequest;
317         params.context = dev;
318         snprintf(params.devpath, sizeof(params.devpath), "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
319
320         // register in smscore
321         rc = smscore_register_device(&params, &dev->coredev);
322         if (rc < 0)
323         {
324                 printk(KERN_INFO "%s smscore_register_device(...) failed, rc %d\n", __FUNCTION__, rc);
325                 smsusb_term_device(intf);
326                 return rc;
327         }
328
329         // initialize urbs
330         for (i = 0; i < MAX_URBS; i ++)
331         {
332                 dev->surbs[i].dev = dev;
333                 usb_init_urb(&dev->surbs[i].urb);
334         }
335
336         rc = smsusb_start_streaming(dev);
337         if (rc < 0)
338         {
339                 printk(KERN_INFO "%s smsusb_start_streaming(...) failed\n", __FUNCTION__);
340                 smsusb_term_device(intf);
341                 return rc;
342         }
343
344         rc = smscore_start_device(dev->coredev);
345         if (rc < 0)
346         {
347                 printk(KERN_INFO "%s smscore_start_device(...) failed\n", __FUNCTION__);
348                 smsusb_term_device(intf);
349                 return rc;
350         }
351
352         printk(KERN_INFO "%s device %p created\n", __FUNCTION__, dev);
353
354         return rc;
355 }
356
357 int smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
358 {
359         struct usb_device *udev = interface_to_usbdev(intf);
360         char devpath[32];
361         int i, rc;
362
363         if (intf->num_altsetting > 0)
364         {
365                 rc = usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
366                 if (rc < 0)
367                 {
368                         printk(KERN_INFO "%s usb_set_interface failed, rc %d\n", __FUNCTION__, rc);
369                         return rc;
370                 }
371         }
372
373         printk(KERN_INFO "smsusb_probe %d\n", intf->cur_altsetting->desc.bInterfaceNumber);
374         for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i ++)
375                 printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, intf->cur_altsetting->endpoint[i].desc.bmAttributes, intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
376
377         if (udev->actconfig->desc.bNumInterfaces == 2 && intf->cur_altsetting->desc.bInterfaceNumber == 0)
378         {
379                 printk(KERN_INFO "rom interface 0 is not used\n");
380                 return -ENODEV;
381         }
382
383         if (intf->cur_altsetting->desc.bInterfaceNumber == 1)
384         {
385                 snprintf(devpath, 32, "%d:%s", udev->bus->busnum, udev->devpath);
386                 return smsusb1_load_firmware(udev, smscore_registry_getmode(devpath));
387         }
388
389         return smsusb_init_device(intf);
390 }
391
392 void smsusb_disconnect(struct usb_interface *intf)
393 {
394         smsusb_term_device(intf);
395 }
396
397 static struct usb_driver smsusb_driver = {
398         .name                   = "smsusb",
399         .probe                  = smsusb_probe,
400         .disconnect     = smsusb_disconnect,
401         .id_table               = smsusb_id_table,
402 };
403
404 extern struct list_head g_smsdvb_clients;
405 kmutex_t g_smsdvb_clientslock;
406
407 int smsusb_module_init(void)
408 {
409         int rc = usb_register(&smsusb_driver);
410         if (rc)
411                 printk(KERN_INFO "usb_register failed. Error number %d\n", rc);
412
413         /* Bring up the dvb componenets */
414         INIT_LIST_HEAD(&g_smsdvb_clients);
415         kmutex_init(&g_smsdvb_clientslock);
416
417         rc = smscore_register_hotplug(smsdvb_hotplug);
418
419         printk(KERN_INFO "%s\n", __FUNCTION__);
420
421         return rc;
422 }
423
424 void smsusb_module_exit(void)
425 {
426         /* Tear down the DVB components */
427         smscore_unregister_hotplug(smsdvb_hotplug);
428
429         kmutex_lock(&g_smsdvb_clientslock);
430
431         while (!list_empty(&g_smsdvb_clients))
432                 smsdvb_unregister_client((smsdvb_client_t*) g_smsdvb_clients.next);
433
434         kmutex_unlock(&g_smsdvb_clientslock);
435
436         /* Regular USB Cleanup */
437         usb_deregister(&smsusb_driver);
438         printk(KERN_INFO "%s\n", __FUNCTION__);
439 }
440
441 module_init(smsusb_module_init);
442 module_exit(smsusb_module_exit);
443
444 MODULE_DESCRIPTION("smsusb");
445 MODULE_AUTHOR("Anatoly Greenblatt,,, (anatolyg@siano-ms.com)");
446 MODULE_LICENSE("GPL");