This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / media / dvb / dibusb / dvb-dibusb-firmware.c
1 /*
2  * dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices 
3  * based on reference design made by DiBcom (http://www.dibcom.fr/)
4  *
5  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
6  *
7  * see dvb-dibusb-core.c for more copyright details.
8  *
9  * This file contains functions for downloading the firmware to the device.
10  */
11 #include "dvb-dibusb.h"
12
13 #include <linux/firmware.h>
14 #include <linux/usb.h>
15
16 /*
17  * load a firmware packet to the device 
18  */
19 static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
20 {
21         return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
22                         0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
23 }
24
25 int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
26 {
27         const struct firmware *fw = NULL;
28         u16 addr;
29         u8 *b,*p;
30         int ret = 0,i;
31         
32         if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
33                 err("did not find a valid firmware file. (%s) "
34                         "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
35                         dibdev->dev_cl->firmware);
36                 return ret;
37         }
38         
39         p = kmalloc(fw->size,GFP_KERNEL);       
40         if (p != NULL) {
41                 u8 reset;
42                 /*
43                  * you cannot use the fw->data as buffer for 
44                  * usb_control_msg, a new buffer has to be
45                  * created
46                  */
47                 memcpy(p,fw->data,fw->size);
48
49                 /* stop the CPU */
50                 reset = 1;
51                 if ((ret = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1)) != 1) 
52                         err("could not stop the USB controller CPU.");
53                 for(i = 0; p[i+3] == 0 && i < fw->size; ) { 
54                         b = (u8 *) &p[i];
55                         addr = *((u16 *) &b[1]);
56
57                         ret = dibusb_writemem(udev,addr,&b[4],b[0]);
58                 
59                         if (ret != b[0]) {
60                                 err("error while transferring firmware "
61                                         "(transferred size: %d, block size: %d)",
62                                         ret,b[0]);
63                                 ret = -EINVAL;
64                                 break;
65                         }
66                         i += 5 + b[0];
67                 }
68                 /* length in ret */
69                 if (ret > 0)
70                         ret = 0;
71                 /* restart the CPU */
72                 reset = 0;
73                 if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) {
74                         err("could not restart the USB controller CPU.");
75                         ret = -EINVAL;
76                 }
77
78                 kfree(p);
79         } else { 
80                 ret = -ENOMEM;
81         }
82         release_firmware(fw);
83
84         return ret;
85 }