enigma2 20150309 -> 20150316
[opendreambox.git] / meta-bsp / common / recipes / linux / linux-dreambox-3.2 / 0001-add-memory-mapping-support-to-usbfs-used-by-sundtek-.patch
1 From 6c704e2d8d084e51680d0984c58b06f04cb828b2 Mon Sep 17 00:00:00 2001
2 From: Andreas Monzner <andreas.monzner@dream-property.net>
3 Date: Fri, 27 Sep 2013 23:20:20 +0200
4 Subject: [PATCH] add memory mapping support to usbfs (used by sundtek usb
5  tuners)
6
7 ---
8  drivers/usb/core/devio.c     | 220 ++++++++++++++++++++++++++++++++++++++++---
9  include/linux/usbdevice_fs.h |   8 ++
10  2 files changed, 216 insertions(+), 12 deletions(-)
11
12 diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
13 index 22f770a..1e890cb 100644
14 --- a/drivers/usb/core/devio.c
15 +++ b/drivers/usb/core/devio.c
16 @@ -66,6 +66,7 @@ struct dev_state {
17         spinlock_t lock;            /* protects the async urb lists */
18         struct list_head async_pending;
19         struct list_head async_completed;
20 +       struct list_head memory_list;
21         wait_queue_head_t wait;     /* wake up if a request completed */
22         unsigned int discsignr;
23         struct pid *disc_pid;
24 @@ -92,6 +93,16 @@ struct async {
25         u8 bulk_status;
26  };
27  
28 +struct usb_memory {
29 +       struct list_head memlist;
30 +       int vma_use_count;
31 +       int usb_use_count;
32 +       u32 offset;
33 +       u32 size;
34 +       void *mem;
35 +       unsigned long vm_start;
36 +};
37 +
38  static int usbfs_snoop;
39  module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
40  MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
41 @@ -248,10 +259,28 @@ static struct async *alloc_async(unsigned int numisoframes)
42  
43  static void free_async(struct async *as)
44  {
45 +       struct usb_memory *usbm = NULL, *usbm_iter;
46 +       unsigned long flags;
47 +       struct dev_state *ps = as->ps;
48 +
49         put_pid(as->pid);
50         if (as->cred)
51                 put_cred(as->cred);
52 -       kfree(as->urb->transfer_buffer);
53 +
54 +       spin_lock_irqsave(&ps->lock, flags);
55 +       list_for_each_entry(usbm_iter, &ps->memory_list, memlist) {
56 +               if (usbm_iter->mem == as->urb->transfer_buffer) {
57 +                       usbm = usbm_iter;
58 +                       break;
59 +               }
60 +       }
61 +       spin_unlock_irqrestore(&ps->lock, flags);
62 +
63 +       if (usbm == NULL)
64 +               kfree(as->urb->transfer_buffer);
65 +       else
66 +               usbm->usb_use_count--;
67 +
68         kfree(as->urb->setup_packet);
69         usb_free_urb(as->urb);
70         kfree(as);
71 @@ -726,6 +755,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
72         INIT_LIST_HEAD(&ps->list);
73         INIT_LIST_HEAD(&ps->async_pending);
74         INIT_LIST_HEAD(&ps->async_completed);
75 +       INIT_LIST_HEAD(&ps->memory_list);
76         init_waitqueue_head(&ps->wait);
77         ps->discsignr = 0;
78         ps->disc_pid = get_pid(task_pid(current));
79 @@ -754,6 +784,8 @@ static int usbdev_release(struct inode *inode, struct file *file)
80         struct dev_state *ps = file->private_data;
81         struct usb_device *dev = ps->dev;
82         unsigned int ifnum;
83 +       struct list_head *p, *q;
84 +       struct usb_memory *tmp;
85         struct async *as;
86  
87         usb_lock_device(dev);
88 @@ -778,6 +810,14 @@ static int usbdev_release(struct inode *inode, struct file *file)
89                 free_async(as);
90                 as = async_getcompleted(ps);
91         }
92 +
93 +       list_for_each_safe(p, q, &ps->memory_list) {
94 +               tmp = list_entry(p, struct usb_memory, memlist);
95 +               list_del(p);
96 +               if (tmp->mem)
97 +                       free_pages_exact(tmp->mem, tmp->size);
98 +               kfree(tmp);
99 +       }
100         kfree(ps);
101         return 0;
102  }
103 @@ -1064,6 +1104,64 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
104         return status;
105  }
106  
107 +static int proc_release_memory(struct dev_state *ps, void __user *arg)
108 +{
109 +       struct usbdevfs_memory m;
110 +       struct usb_memory *usbm;
111 +       unsigned long flags;
112 +
113 +       if (copy_from_user(&m, arg, sizeof(m)))
114 +               return -EFAULT;
115 +
116 +       spin_lock_irqsave(&ps->lock, flags);
117 +       list_for_each_entry(usbm, &ps->memory_list, memlist) {
118 +               if (((void*)usbm->vm_start == m.buffer || usbm->offset == m.offset) &&
119 +                       usbm->usb_use_count == 0 && usbm->vma_use_count == 0) {
120 +
121 +                       list_del_init(&usbm->memlist);
122 +                       spin_unlock_irqrestore(&ps->lock, flags);
123 +                       free_pages_exact(usbm->mem, usbm->size);
124 +                       kfree(usbm);
125 +                       return 0;
126 +               }
127 +       }
128 +       spin_unlock_irqrestore(&ps->lock, flags);
129 +       return -EBUSY;
130 +}
131 +
132 +static int proc_alloc_memory(struct dev_state *ps, void __user *arg)
133 +{
134 +       struct usbdevfs_memory m;
135 +       struct usb_memory *usbmem;
136 +       void *mem;
137 +       unsigned long flags;
138 +
139 +       if (copy_from_user(&m, arg, sizeof(m)))
140 +               return -EFAULT;
141 +
142 +       mem = alloc_pages_exact(m.size, GFP_KERNEL | GFP_DMA32);
143 +       if (!mem)
144 +               return -ENOMEM;
145 +       
146 +       usbmem = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
147 +       if (!usbmem) {
148 +               free_pages_exact(mem, m.size);
149 +               return -ENOMEM;
150 +       }
151 +       memset(mem, 0x0, (PAGE_SIZE<<get_order(m.size)));
152 +       usbmem->mem = mem;
153 +       m.offset = usbmem->offset = virt_to_phys(mem);
154 +       usbmem->size = m.size;
155 +       spin_lock_irqsave(&ps->lock, flags);
156 +       list_add_tail(&usbmem->memlist, &ps->memory_list);
157 +       spin_unlock_irqrestore(&ps->lock, flags);
158 +
159 +       if (copy_to_user(arg, &m, sizeof(m)))
160 +               return -EFAULT;
161 +
162 +       return 0;
163 +}
164 +
165  static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
166                         struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
167                         void __user *arg)
168 @@ -1072,6 +1170,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
169         struct usb_host_endpoint *ep;
170         struct async *as;
171         struct usb_ctrlrequest *dr = NULL;
172 +       struct usb_memory *usbm = NULL, *iter = NULL;
173         unsigned int u, totlen, isofrmlen;
174         int ret, ifnum = -1;
175         int is_in;
176 @@ -1203,7 +1302,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
177                 }
178                 uurb->buffer_length = totlen;
179                 break;
180 -
181         default:
182                 return -EINVAL;
183         }
184 @@ -1220,20 +1318,51 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
185                 kfree(dr);
186                 return -ENOMEM;
187         }
188 +       as->ps = ps;
189         if (uurb->buffer_length > 0) {
190 -               as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
191 -                               GFP_KERNEL);
192 -               if (!as->urb->transfer_buffer) {
193 -                       kfree(isopkt);
194 -                       kfree(dr);
195 -                       free_async(as);
196 -                       return -ENOMEM;
197 +               if (!list_empty(&ps->memory_list)) {
198 +                       unsigned long flags;
199 +                       usbm=NULL;
200 +                       as->urb->transfer_buffer = NULL;
201 +                       spin_lock_irqsave(&ps->lock, flags);
202 +                       list_for_each_entry(iter, &ps->memory_list, memlist) {
203 +                               if ((void*)iter->vm_start == uurb->buffer && iter->usb_use_count == 0 && 
204 +                                               (PAGE_SIZE<<get_order(iter->size)) >= uurb->buffer_length) {
205 +                                       usbm = iter;
206 +                                       usbm->usb_use_count++;
207 +                                       break;
208 +                               }
209 +                       }
210 +                       spin_unlock_irqrestore(&ps->lock, flags);
211 +                       if (usbm) {
212 +                               as->urb->transfer_buffer = usbm->mem;
213 +                       } else {
214 +                               kfree(isopkt);
215 +                               kfree(dr);
216 +                               free_async(as);
217 +                               return -ENOMEM;
218 +                       }
219 +                       if (as->urb->transfer_buffer == NULL) {
220 +                               kfree(isopkt);
221 +                               kfree(dr);
222 +                               free_async(as);
223 +                               return -ENOMEM;
224 +                       }
225 +               } else {
226 +                       as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
227 +                                       GFP_KERNEL);
228 +                       if (!as->urb->transfer_buffer) {
229 +                               kfree(isopkt);
230 +                               kfree(dr);
231 +                               free_async(as);
232 +                               return -ENOMEM;
233 +                       }       
234                 }
235                 /* Isochronous input data may end up being discontiguous
236                  * if some of the packets are short.  Clear the buffer so
237                  * that the gaps don't leak kernel data to userspace.
238                  */
239 -               if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
240 +               if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO && usbm == NULL)
241                         memset(as->urb->transfer_buffer, 0,
242                                         uurb->buffer_length);
243         }
244 @@ -1276,7 +1405,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
245                 totlen += isopkt[u].length;
246         }
247         kfree(isopkt);
248 -       as->ps = ps;
249         as->userurb = arg;
250         if (is_in && uurb->buffer_length > 0)
251                 as->userbuffer = uurb->buffer;
252 @@ -1287,10 +1415,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
253         as->pid = get_pid(task_pid(current));
254         as->cred = get_current_cred();
255         security_task_getsecid(current, &as->secid);
256 -       if (!is_in && uurb->buffer_length > 0) {
257 +       if (!is_in && uurb->buffer_length > 0 && usbm == NULL) {
258                 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
259                                 uurb->buffer_length)) {
260                         free_async(as);
261 +                       if (usbm)
262 +                               usbm->usb_use_count--;
263                         return -EFAULT;
264                 }
265         }
266 @@ -1338,6 +1468,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
267                                 0, ret, COMPLETE, NULL, 0);
268                 async_removepending(as);
269                 free_async(as);
270 +               if (usbm)
271 +                       usbm->usb_use_count--;
272                 return ret;
273         }
274         return 0;
275 @@ -1947,6 +2079,16 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
276                 snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
277                 ret = proc_release_port(ps, p);
278                 break;
279 +
280 +       case USBDEVFS_ALLOC_MEMORY:
281 +               snoop(&dev->dev, "%s: ALLOC_MEMORY\n", __func__);
282 +               ret = proc_alloc_memory(ps, p);
283 +               break;
284 +
285 +       case USBDEVFS_RELEASE_MEMORY:
286 +               snoop(&dev->dev, "%s: RELEASE_MEMORY\n", __func__);
287 +               ret = proc_release_memory(ps, p);
288 +               break;
289         }
290         usb_unlock_device(dev);
291         if (ret >= 0)
292 @@ -1991,6 +2133,59 @@ static unsigned int usbdev_poll(struct file *file,
293         return mask;
294  }
295  
296 +static void usbdev_vm_open(struct vm_area_struct *vma)
297 +{
298 +       struct usb_memory *usbm = vma->vm_private_data;
299 +       usbm->vma_use_count++;
300 +}
301 +
302 +static void usbdev_vm_close(struct vm_area_struct *vma)
303 +{
304 +       struct usb_memory *usbm = vma->vm_private_data;
305 +       usbm->vma_use_count--;
306 +}
307 +
308 +
309 +struct vm_operations_struct usbdev_vm_ops = {
310 +       .open = usbdev_vm_open,
311 +       .close = usbdev_vm_close
312 +};
313 +
314 +static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) 
315 +{
316 +       struct usb_memory *usbm = NULL, *usbm_iter = NULL;
317 +       struct dev_state *ps = file->private_data;
318 +       int size = vma->vm_end - vma->vm_start;
319 +       unsigned long flags;
320 +       spin_lock_irqsave(&ps->lock, flags);
321 +       list_for_each_entry(usbm_iter, &ps->memory_list, memlist) {
322 +
323 +               if (usbm_iter->offset == (vma->vm_pgoff<<PAGE_SHIFT) && 
324 +                       size <= (PAGE_SIZE<<get_order(usbm_iter->size))) {
325 +                       usbm = usbm_iter;
326 +                       usbm->vm_start = vma->vm_start;
327 +                       break;
328 +               }
329 +       }
330 +       spin_unlock_irqrestore(&ps->lock, flags);
331 +
332 +       if (usbm == NULL)
333 +               return -EINVAL;
334 +
335 +       if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(usbm->mem) >> PAGE_SHIFT,
336 +               size,
337 +               vma->vm_page_prot) < 0)
338 +               return -EAGAIN;
339 +       
340 +       vma->vm_flags |= VM_IO;
341 +       vma->vm_flags |= VM_RESERVED; //(VM_DONTEXPAND | VM_DONTDUMP); newer kernels use don't expand/don't dump
342 +       vma->vm_ops = &usbdev_vm_ops;
343 +       vma->vm_private_data = usbm;
344 +       usbdev_vm_open(vma);
345 +       return 0;
346 +}
347 +
348 +
349  const struct file_operations usbdev_file_operations = {
350         .owner =          THIS_MODULE,
351         .llseek =         usbdev_lseek,
352 @@ -2000,6 +2195,7 @@ const struct file_operations usbdev_file_operations = {
353  #ifdef CONFIG_COMPAT
354         .compat_ioctl =   usbdev_compat_ioctl,
355  #endif
356 +       .mmap =           usbdev_mmap,
357         .open =           usbdev_open,
358         .release =        usbdev_release,
359  };
360 diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
361 index 15591d2..4261efd 100644
362 --- a/include/linux/usbdevice_fs.h
363 +++ b/include/linux/usbdevice_fs.h
364 @@ -70,6 +70,12 @@ struct usbdevfs_getdriver {
365         char driver[USBDEVFS_MAXDRIVERNAME + 1];
366  };
367  
368 +struct usbdevfs_memory {
369 +       u32 size;
370 +       u32 offset;
371 +       void __user *buffer;
372 +};
373 +
374  struct usbdevfs_connectinfo {
375         unsigned int devnum;
376         unsigned char slow;
377 @@ -204,4 +210,6 @@ struct usbdevfs_ioctl32 {
378  #define USBDEVFS_CONNECT           _IO('U', 23)
379  #define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
380  #define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
381 +#define USBDEVFS_ALLOC_MEMORY      _IOWR('U', 28, struct usbdevfs_memory)
382 +#define USBDEVFS_RELEASE_MEMORY       _IOW('U', 29, struct usbdevfs_memory)
383  #endif /* _LINUX_USBDEVICE_FS_H */
384 -- 
385 1.8.4.rc3
386