This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / media / dvb / dibusb / dvb-dibusb-usb.c
1 /*
2  * dvb-dibusb-usb.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 initializing and handling the 
10  * usb specific stuff.
11  */
12 #include "dvb-dibusb.h"
13
14 #include <linux/version.h>
15 #include <linux/pci.h>
16
17 int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
18                 u16 rlen)
19 {
20         int actlen,ret = -ENOMEM;
21
22         if (wbuf == NULL || wlen == 0)
23                 return -EINVAL;
24
25         if ((ret = down_interruptible(&dib->usb_sem)))
26                 return ret;
27
28         if (dib->feedcount && 
29                 wbuf[0] == DIBUSB_REQ_I2C_WRITE && 
30                 dib->dibdev->dev_cl->id == DIBUSB1_1)
31                 deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
32                                 "(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
33                         
34         debug_dump(wbuf,wlen);
35
36         ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
37                         dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
38                         DIBUSB_I2C_TIMEOUT);
39                 
40         if (ret)
41                 err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
42         else
43                 ret = actlen != wlen ? -1 : 0;
44
45         /* an answer is expected, and no error before */
46         if (!ret && rbuf && rlen) {
47                 ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
48                                 dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen,
49                                 DIBUSB_I2C_TIMEOUT);
50
51                 if (ret)
52                         err("recv bulk message failed: %d",ret);
53                 else {
54                         deb_alot("rlen: %d\n",rlen);
55                         debug_dump(rbuf,actlen);
56                 }
57         }
58         
59         up(&dib->usb_sem);
60         return ret;
61 }
62
63 /*
64  * Cypress controls
65  */
66
67 #if 0
68 /* 
69  * #if 0'ing the following functions as they are not in use _now_, 
70  * but probably will be sometime.
71  */
72
73 /*
74  * do not use this, just a workaround for a bug, 
75  * which will hopefully never occur :).
76  */
77 int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
78 {
79         u8 b[1] = { DIBUSB_REQ_INTR_READ };
80         return dibusb_write_usb(dib,b,1);
81 }
82
83 #endif 
84 static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
85 {
86         return dibusb_readwrite_usb(dib,buf,len,NULL,0);
87 }
88
89 /*
90  * ioctl for the firmware 
91  */
92 static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
93 {
94         u8 b[34];
95         int size = plen > 32 ? 32 : plen;
96         memset(b,0,34);
97         b[0] = DIBUSB_REQ_SET_IOCTL;
98         b[1] = cmd;
99
100         if (size > 0)
101                 memcpy(&b[2],param,size);
102
103         return dibusb_write_usb(dib,b,34); //2+size);
104 }
105
106 /*
107  * ioctl for power control
108  */
109 int dibusb_hw_wakeup(struct dvb_frontend *fe)
110 {
111         struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
112         u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
113         deb_info("dibusb-device is getting up.\n");
114         dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
115         
116         if (dib->fe_init)
117                 return dib->fe_init(fe);
118         
119         return 0;
120 }
121
122 int dibusb_hw_sleep(struct dvb_frontend *fe)
123 {
124         struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
125         u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
126         deb_info("dibusb-device is going to bed.\n");
127         dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
128
129         if (dib->fe_sleep)
130                 return dib->fe_sleep(fe);
131         
132         return 0;
133 }
134
135 int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
136 {
137         u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
138         return dibusb_readwrite_usb(dib,b,2,NULL,0);
139 }
140
141 int dibusb_streaming(struct usb_dibusb *dib,int onoff)
142 {
143         switch (dib->dibdev->dev_cl->id) {
144                 case DIBUSB2_0:
145                         if (onoff)
146                                 return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
147                         else
148                                 return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
149                         break;
150                 case UMT2_0: 
151                         return dibusb_set_streaming_mode(dib,onoff);
152                         break;
153                 default:
154                         break;
155         }
156         return 0;
157 }
158
159 int dibusb_urb_init(struct usb_dibusb *dib)
160 {
161         int ret,i,bufsize,def_pid_parse = 1;
162         
163         /*
164          * when reloading the driver w/o replugging the device 
165          * a timeout occures, this helps
166          */
167         usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
168         usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
169         usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
170
171         /* allocate the array for the data transfer URBs */
172         dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
173         if (dib->urb_list == NULL)
174                 return -ENOMEM;
175         memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
176
177         dib->init_state |= DIBUSB_STATE_URB_LIST;
178         
179         bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
180         deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
181         /* allocate the actual buffer for the URBs */
182         if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
183                 deb_info("not enough memory.\n");
184                 return -ENOMEM;
185         }
186         deb_info("allocation complete\n");
187         memset(dib->buffer,0,bufsize);
188         
189         dib->init_state |= DIBUSB_STATE_URB_BUF;
190
191         /* allocate and submit the URBs */
192         for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
193                 if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
194                         return -ENOMEM;
195                 }
196                 deb_info("submitting URB no. %d\n",i);
197                 
198                 usb_fill_bulk_urb( dib->urb_list[i], dib->udev, 
199                                 usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
200                                 &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], 
201                                 dib->dibdev->dev_cl->urb_buffer_size, 
202                                 dibusb_urb_complete, dib);
203                 
204                 dib->urb_list[i]->transfer_flags = 0;
205
206                 if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
207                         err("could not submit buffer urb no. %d\n",i);
208                         return ret;
209                 }
210                 dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
211         }
212
213         /* dib->pid_parse here contains the value of the module parameter */
214         /* decide if pid parsing can be deactivated:
215          * is possible (by speed) and wanted (by user)
216          */
217         switch (dib->dibdev->dev_cl->id) {
218                 case DIBUSB2_0:
219                         if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
220                                 def_pid_parse = 0;
221                                 info("running at HIGH speed, will deliver the complete TS.");
222                         } else
223                                 info("will use pid_parsing.");
224                         break;
225                 default: 
226                         break;
227         }
228         /* from here on it contains the device and user decision */
229         dib->pid_parse = def_pid_parse;
230         
231         return 0;
232 }
233
234 int dibusb_urb_exit(struct usb_dibusb *dib)
235 {
236         int i;
237         if (dib->init_state & DIBUSB_STATE_URB_LIST) {
238                 for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
239                         if (dib->urb_list[i] != NULL) {
240                                 deb_info("killing URB no. %d.\n",i);
241
242                                 /* stop the URBs */
243                                 usb_kill_urb(dib->urb_list[i]);
244                                 
245                                 deb_info("freeing URB no. %d.\n",i);
246                                 /* free the URBs */
247                                 usb_free_urb(dib->urb_list[i]);
248                         }
249                 }
250                 /* free the urb array */
251                 kfree(dib->urb_list);
252                 dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
253                 dib->init_state &= ~DIBUSB_STATE_URB_LIST;
254         }
255
256         if (dib->init_state & DIBUSB_STATE_URB_BUF)
257                 pci_free_consistent(NULL,
258                         dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
259                         dib->buffer,dib->dma_handle);
260
261         dib->init_state &= ~DIBUSB_STATE_URB_BUF;
262         return 0;
263 }