diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-21 17:04:55 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 16:52:34 -0500 |
commit | 28397ffef14255ba45b99570d366fcd2b454c8f3 (patch) | |
tree | 919b6651cf9f4fb31fc436600a285c847b03c6cd /drivers | |
parent | 88a1e909da60cd3adf159bc337ede09d4ac93e3e (diff) |
Staging: add princeton instruments usb camera driver
Adds the driver for the Princeton Instruments USB camera.
Needs a lot of work...
TODO:
- make checkpatch.pl clean
- coding style fixups (typedefs, etc.)
- get it to build properly
- audit ioctls
- remove ioctls if possible
- assign proper minor number
- remove dbg() macro
- lots of general cleanups
- review locking
Cc: Judd Montgomery <judd@jpilot.org>
Cc: Jeff Frontz <jeff.frontz@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/rspiusb/Kconfig | 6 | ||||
-rw-r--r-- | drivers/staging/rspiusb/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/rspiusb/TODO | 22 | ||||
-rw-r--r-- | drivers/staging/rspiusb/rspiusb.c | 887 | ||||
-rw-r--r-- | drivers/staging/rspiusb/rspiusb.h | 25 |
7 files changed, 944 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 53404a4018fe..fe3b23e43567 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
@@ -83,5 +83,7 @@ source "drivers/staging/altpciechdma/Kconfig" | |||
83 | 83 | ||
84 | source "drivers/staging/rtl8187se/Kconfig" | 84 | source "drivers/staging/rtl8187se/Kconfig" |
85 | 85 | ||
86 | source "drivers/staging/rspiusb/Kconfig" | ||
87 | |||
86 | endif # !STAGING_EXCLUDE_BUILD | 88 | endif # !STAGING_EXCLUDE_BUILD |
87 | endif # STAGING | 89 | endif # STAGING |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 170789f3c4ca..bd4cb9285a2f 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
@@ -24,3 +24,4 @@ obj-$(CONFIG_ASUS_OLED) += asus_oled/ | |||
24 | obj-$(CONFIG_PANEL) += panel/ | 24 | obj-$(CONFIG_PANEL) += panel/ |
25 | obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/ | 25 | obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/ |
26 | obj-$(CONFIG_RTL8187SE) += rtl8187se/ | 26 | obj-$(CONFIG_RTL8187SE) += rtl8187se/ |
27 | obj-$(CONFIG_USB_RSPI) += rspiusb/ | ||
diff --git a/drivers/staging/rspiusb/Kconfig b/drivers/staging/rspiusb/Kconfig new file mode 100644 index 000000000000..d225f6794d02 --- /dev/null +++ b/drivers/staging/rspiusb/Kconfig | |||
@@ -0,0 +1,6 @@ | |||
1 | config USB_RSPI | ||
2 | tristate "Princeton Instruments USB camera support" | ||
3 | default n | ||
4 | depends on USB && BROKEN | ||
5 | help | ||
6 | This driver is for the Princeton Instruments USB camera device. | ||
diff --git a/drivers/staging/rspiusb/Makefile b/drivers/staging/rspiusb/Makefile new file mode 100644 index 000000000000..cc7aed92b0e3 --- /dev/null +++ b/drivers/staging/rspiusb/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_USB_RSPI) += rspiusb.o | |||
diff --git a/drivers/staging/rspiusb/TODO b/drivers/staging/rspiusb/TODO new file mode 100644 index 000000000000..cd6336a9254d --- /dev/null +++ b/drivers/staging/rspiusb/TODO | |||
@@ -0,0 +1,22 @@ | |||
1 | This driver is for the Princeton Instruments USB camera. | ||
2 | |||
3 | It needs lots of work to get it into the main drivers/usb/ subdirectory: | ||
4 | |||
5 | Any patches to do any of the following changes are greatly appreciated: | ||
6 | |||
7 | - make checkpatch.pl clean | ||
8 | - coding style fixups (typedefs, etc.) | ||
9 | - get it to build properly | ||
10 | - audit ioctls | ||
11 | - remove ioctls if possible | ||
12 | - assign proper minor number | ||
13 | - remove dbg() macro | ||
14 | - lots of general cleanups | ||
15 | - review locking | ||
16 | |||
17 | Please send patches to: | ||
18 | Greg Kroah-Hartman <gregkh@suse.de> | ||
19 | and CC: | ||
20 | Judd Montgomery <judd@jpilot.org> | ||
21 | Jeff Frontz <jeff.frontz@gmail.com> | ||
22 | as they have this device and can test any needed changes. | ||
diff --git a/drivers/staging/rspiusb/rspiusb.c b/drivers/staging/rspiusb/rspiusb.c new file mode 100644 index 000000000000..ca281d6cbd7a --- /dev/null +++ b/drivers/staging/rspiusb/rspiusb.c | |||
@@ -0,0 +1,887 @@ | |||
1 | /* | ||
2 | * rspiusb.c | ||
3 | * | ||
4 | * Copyright (C) 2005, 2006 Princeton Instruments | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation version 2 of the License | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/vmalloc.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/smp_lock.h> | ||
27 | #include <linux/completion.h> | ||
28 | #include <linux/scatterlist.h> | ||
29 | #include <linux/usb.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/pagemap.h> | ||
32 | #include <linux/ioctl.h> | ||
33 | #include "rspiusb.h" | ||
34 | |||
35 | #ifdef CONFIG_USB_DEBUG | ||
36 | static int debug = 1; | ||
37 | #else | ||
38 | static int debug; | ||
39 | #endif | ||
40 | /* Use our own dbg macro */ | ||
41 | #undef dbg | ||
42 | #define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) | ||
43 | |||
44 | /* Version Information */ | ||
45 | #define DRIVER_VERSION "V1.0.1" | ||
46 | #define DRIVER_AUTHOR "Princeton Instruments" | ||
47 | #define DRIVER_DESC "PI USB2.0 Device Driver for Linux" | ||
48 | |||
49 | /* Define these values to match your devices */ | ||
50 | #define VENDOR_ID 0x0BD7 | ||
51 | #define ST133_PID 0xA010 | ||
52 | #define PIXIS_PID 0xA026 | ||
53 | |||
54 | /* Get a minor range for your devices from the usb maintainer */ | ||
55 | #ifdef CONFIG_USB_DYNAMIC_MINORS | ||
56 | #define PIUSB_MINOR_BASE 0 | ||
57 | #else | ||
58 | #define PIUSB_MINOR_BASE 192 | ||
59 | #endif | ||
60 | |||
61 | /* prevent races between open() and disconnect() */ | ||
62 | static DECLARE_MUTEX(disconnect_sem); | ||
63 | |||
64 | /* Structure to hold all of our device specific stuff */ | ||
65 | struct device_extension { | ||
66 | struct usb_device *udev; /* save off the usb device pointer */ | ||
67 | struct usb_interface *interface; /* the interface for this device */ | ||
68 | unsigned char minor; /* the starting minor number for this device */ | ||
69 | size_t bulk_in_size_returned; | ||
70 | int bulk_in_byte_trk; | ||
71 | struct urb ***PixelUrb; | ||
72 | int frameIdx; | ||
73 | int urbIdx; | ||
74 | unsigned int *maplist_numPagesMapped; | ||
75 | int open; /* if the port is open or not */ | ||
76 | int present; /* if the device is not disconnected */ | ||
77 | int userBufMapped; /* has the user buffer been mapped? */ | ||
78 | struct scatterlist **sgl; /* scatter-gather list for user buffer */ | ||
79 | unsigned int *sgEntries; | ||
80 | struct kref kref; | ||
81 | int gotPixelData; | ||
82 | int pendingWrite; | ||
83 | char **pendedPixelUrbs; | ||
84 | int iama; /*PIXIS or ST133 */ | ||
85 | int num_frames; /* the number of frames that will fit in the user buffer */ | ||
86 | int active_frame; | ||
87 | unsigned long frameSize; | ||
88 | struct semaphore sem; | ||
89 | //FX2 specific endpoints | ||
90 | unsigned int hEP[8]; | ||
91 | }; | ||
92 | #define to_pi_dev(d) container_of( d, struct device_extension, kref ) | ||
93 | |||
94 | static int MapUserBuffer(struct ioctl_struct *, struct device_extension *); | ||
95 | static int UnMapUserBuffer(struct device_extension *); | ||
96 | static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
97 | unsigned long arg); | ||
98 | static int piusb_output(struct ioctl_struct *, unsigned char *, int, struct device_extension *); | ||
99 | static struct usb_driver piusb_driver; | ||
100 | |||
101 | /* table of devices that work with this driver */ | ||
102 | static struct usb_device_id pi_device_table[] = { | ||
103 | {USB_DEVICE(VENDOR_ID, ST133_PID)}, | ||
104 | {USB_DEVICE(VENDOR_ID, PIXIS_PID)}, | ||
105 | {0, } /* Terminating entry */ | ||
106 | }; | ||
107 | |||
108 | MODULE_DEVICE_TABLE(usb, pi_device_table); | ||
109 | |||
110 | static int lastErr = 0; | ||
111 | static int errCnt = 0; | ||
112 | |||
113 | static void piusb_delete(struct kref *kref) | ||
114 | { | ||
115 | struct device_extension *pdx = to_pi_dev(kref); | ||
116 | |||
117 | dev_dbg(&pdx->udev->dev, "%s\n", __func__); | ||
118 | usb_put_dev(pdx->udev); | ||
119 | kfree(pdx); | ||
120 | } | ||
121 | |||
122 | static int piusb_open(struct inode *inode, struct file *file) | ||
123 | { | ||
124 | struct device_extension *pdx = NULL; | ||
125 | struct usb_interface *interface; | ||
126 | int subminor; | ||
127 | int retval = 0; | ||
128 | |||
129 | dbg("Piusb_Open()"); | ||
130 | subminor = iminor(inode); | ||
131 | interface = usb_find_interface(&piusb_driver, subminor); | ||
132 | if (!interface) { | ||
133 | printk(KERN_ERR "%s - error, can't find device for minor %d\n", | ||
134 | __func__, subminor); | ||
135 | retval = -ENODEV; | ||
136 | goto exit_no_device; | ||
137 | } | ||
138 | |||
139 | pdx = usb_get_intfdata(interface); | ||
140 | if (!pdx) { | ||
141 | retval = -ENODEV; | ||
142 | goto exit_no_device; | ||
143 | } | ||
144 | dbg("Alternate Setting = %d", interface->num_altsetting); | ||
145 | |||
146 | pdx->frameIdx = pdx->urbIdx = 0; | ||
147 | pdx->gotPixelData = 0; | ||
148 | pdx->pendingWrite = 0; | ||
149 | pdx->frameSize = 0; | ||
150 | pdx->num_frames = 0; | ||
151 | pdx->active_frame = 0; | ||
152 | pdx->bulk_in_byte_trk = 0; | ||
153 | pdx->userBufMapped = 0; | ||
154 | pdx->pendedPixelUrbs = NULL; | ||
155 | pdx->sgEntries = NULL; | ||
156 | pdx->sgl = NULL; | ||
157 | pdx->maplist_numPagesMapped = NULL; | ||
158 | pdx->PixelUrb = NULL; | ||
159 | pdx->bulk_in_size_returned = 0; | ||
160 | /* increment our usage count for the device */ | ||
161 | kref_get(&pdx->kref); | ||
162 | /* save our object in the file's private structure */ | ||
163 | file->private_data = pdx; | ||
164 | exit_no_device: | ||
165 | return retval; | ||
166 | } | ||
167 | |||
168 | static int piusb_release(struct inode *inode, struct file *file) | ||
169 | { | ||
170 | struct device_extension *pdx; | ||
171 | int retval = 0; | ||
172 | |||
173 | dbg("Piusb_Release()"); | ||
174 | pdx = (struct device_extension *)file->private_data; | ||
175 | if (pdx == NULL) { | ||
176 | dbg("%s - object is NULL", __func__); | ||
177 | return -ENODEV; | ||
178 | } | ||
179 | /* decrement the count on our device */ | ||
180 | kref_put(&pdx->kref, piusb_delete); | ||
181 | return retval; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * piusb_ioctl | ||
186 | */ | ||
187 | static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
188 | unsigned long arg) | ||
189 | { | ||
190 | struct device_extension *pdx; | ||
191 | char dummyCtlBuf[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
192 | unsigned long devRB = 0; | ||
193 | int i = 0; | ||
194 | int err = 0; | ||
195 | int retval = 0; | ||
196 | struct ioctl_struct ctrl; | ||
197 | unsigned char *uBuf; | ||
198 | int numbytes = 0; | ||
199 | unsigned short controlData = 0; | ||
200 | |||
201 | pdx = (struct device_extension *)file->private_data; | ||
202 | /* verify that the device wasn't unplugged */ | ||
203 | if (!pdx->present) { | ||
204 | dbg("No Device Present\n"); | ||
205 | return -ENODEV; | ||
206 | } | ||
207 | /* fill in your device specific stuff here */ | ||
208 | if (_IOC_DIR(cmd) & _IOC_READ) | ||
209 | err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); | ||
210 | else if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
211 | err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); | ||
212 | if (err) { | ||
213 | dev_err(&pdx->udev->dev, "return with error = %d\n", err); | ||
214 | return -EFAULT; | ||
215 | } | ||
216 | switch (cmd) { | ||
217 | case PIUSB_GETVNDCMD: | ||
218 | if (copy_from_user | ||
219 | (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) | ||
220 | info("copy_from_user failed\n"); | ||
221 | dbg("%s %x\n", "Get Vendor Command = ", ctrl.cmd); | ||
222 | retval = | ||
223 | usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), | ||
224 | ctrl.cmd, USB_DIR_IN, 0, 0, &devRB, | ||
225 | ctrl.numbytes, HZ * 10); | ||
226 | if (ctrl.cmd == 0xF1) { | ||
227 | dbg("FW Version returned from HW = %ld.%ld", | ||
228 | (devRB >> 8), (devRB & 0xFF)); | ||
229 | } | ||
230 | return devRB; | ||
231 | case PIUSB_SETVNDCMD: | ||
232 | if (copy_from_user | ||
233 | (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) | ||
234 | info("copy_from_user failed\n"); | ||
235 | // dbg( "%s %x", "Set Vendor Command = ",ctrl.cmd ); | ||
236 | controlData = ctrl.pData[0]; | ||
237 | controlData |= (ctrl.pData[1] << 8); | ||
238 | // dbg( "%s %d", "Vendor Data =",controlData ); | ||
239 | retval = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), ctrl.cmd, (USB_DIR_OUT | USB_TYPE_VENDOR), /* | USB_RECIP_ENDPOINT), */ | ||
240 | controlData, | ||
241 | 0, | ||
242 | &dummyCtlBuf, ctrl.numbytes, HZ * 10); | ||
243 | return retval; | ||
244 | break; | ||
245 | case PIUSB_ISHIGHSPEED: | ||
246 | return ((pdx->udev->speed == USB_SPEED_HIGH) ? 1 : 0); | ||
247 | break; | ||
248 | case PIUSB_WRITEPIPE: | ||
249 | if (copy_from_user(&ctrl, (void __user *)arg, _IOC_SIZE(cmd))) | ||
250 | info("copy_from_user WRITE_DUMMY failed\n"); | ||
251 | if (!access_ok(VERIFY_READ, ctrl.pData, ctrl.numbytes)) { | ||
252 | dbg("can't access pData"); | ||
253 | return 0; | ||
254 | } | ||
255 | piusb_output(&ctrl, ctrl.pData /*uBuf */ , ctrl.numbytes, pdx); | ||
256 | return ctrl.numbytes; | ||
257 | break; | ||
258 | case PIUSB_USERBUFFER: | ||
259 | if (copy_from_user | ||
260 | (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) | ||
261 | info("copy_from_user failed\n"); | ||
262 | return MapUserBuffer((struct ioctl_struct *) & ctrl, pdx); | ||
263 | break; | ||
264 | case PIUSB_UNMAP_USERBUFFER: | ||
265 | UnMapUserBuffer(pdx); | ||
266 | return 0; | ||
267 | break; | ||
268 | case PIUSB_READPIPE: | ||
269 | if (copy_from_user | ||
270 | (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) | ||
271 | info("copy_from_user failed\n"); | ||
272 | switch (ctrl.endpoint) { | ||
273 | case 0: //ST133 Pixel Data or PIXIS IO | ||
274 | if (pdx->iama == PIXIS_PID) { | ||
275 | unsigned int numToRead = 0; | ||
276 | unsigned int totalRead = 0; | ||
277 | uBuf = kmalloc(ctrl.numbytes, GFP_KERNEL); | ||
278 | if (!uBuf) { | ||
279 | dbg("Alloc for uBuf failed"); | ||
280 | return 0; | ||
281 | } | ||
282 | numbytes = ctrl.numbytes; | ||
283 | numToRead = numbytes; | ||
284 | dbg("numbytes to read = %d", numbytes); | ||
285 | dbg("endpoint # %d", ctrl.endpoint); | ||
286 | if (copy_from_user(uBuf, ctrl.pData, numbytes)) | ||
287 | dbg("copying ctrl.pData to dummyBuf failed"); | ||
288 | do { | ||
289 | i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl.endpoint], (uBuf + totalRead), (numToRead > 64) ? 64 : numToRead, &numbytes, HZ * 10); //EP0 can only handle 64 bytes at a time | ||
290 | if (i) { | ||
291 | dbg("CMD = %s, Address = 0x%02X", ((uBuf[3] == 0x02) ? "WRITE" : "READ"), uBuf[1]); | ||
292 | dbg("Number of bytes Attempted to read = %d", (int)ctrl.numbytes); | ||
293 | dbg("Blocking ReadI/O Failed with status %d", i); | ||
294 | kfree(uBuf); | ||
295 | return -1; | ||
296 | } else { | ||
297 | dbg("Pixis EP0 Read %d bytes", | ||
298 | numbytes); | ||
299 | totalRead += numbytes; | ||
300 | numToRead -= numbytes; | ||
301 | } | ||
302 | } | ||
303 | while (numToRead); | ||
304 | memcpy(ctrl.pData, uBuf, totalRead); | ||
305 | dbg("Total Bytes Read from PIXIS EP0 = %d", | ||
306 | totalRead); | ||
307 | ctrl.numbytes = totalRead; | ||
308 | if (copy_to_user | ||
309 | ((struct ioctl_struct *) arg, &ctrl, | ||
310 | sizeof(struct ioctl_struct))) | ||
311 | dbg("copy_to_user failed in IORB"); | ||
312 | kfree(uBuf); | ||
313 | return ctrl.numbytes; | ||
314 | } else //ST133 Pixel Data | ||
315 | { | ||
316 | if (!pdx->gotPixelData) | ||
317 | return 0; | ||
318 | else { | ||
319 | pdx->gotPixelData = 0; | ||
320 | ctrl.numbytes = | ||
321 | pdx->bulk_in_size_returned; | ||
322 | pdx->bulk_in_size_returned -= | ||
323 | pdx->frameSize; | ||
324 | for (i = 0; i < pdx->maplist_numPagesMapped[pdx->active_frame]; i++) | ||
325 | SetPageDirty(pdx->sgl[pdx->active_frame][i].page_link); | ||
326 | pdx->active_frame = | ||
327 | ((pdx->active_frame + | ||
328 | 1) % pdx->num_frames); | ||
329 | return ctrl.numbytes; | ||
330 | } | ||
331 | } | ||
332 | break; | ||
333 | case 1: //ST133IO | ||
334 | case 4: //PIXIS IO | ||
335 | uBuf = kmalloc(ctrl.numbytes, GFP_KERNEL); | ||
336 | if (!uBuf) { | ||
337 | dbg("Alloc for uBuf failed"); | ||
338 | return 0; | ||
339 | } | ||
340 | numbytes = ctrl.numbytes; | ||
341 | // dbg( "numbytes to read = %d", numbytes ); | ||
342 | if (copy_from_user(uBuf, ctrl.pData, numbytes)) | ||
343 | dbg("copying ctrl.pData to dummyBuf failed"); | ||
344 | i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl.endpoint], | ||
345 | uBuf, numbytes, &numbytes, HZ * 10); | ||
346 | if (i) { | ||
347 | dbg("Blocking ReadI/O Failed with status %d", | ||
348 | i); | ||
349 | kfree(uBuf); | ||
350 | return -1; | ||
351 | } else { | ||
352 | ctrl.numbytes = numbytes; | ||
353 | memcpy(ctrl.pData, uBuf, numbytes); | ||
354 | if (copy_to_user | ||
355 | ((struct ioctl_struct *) arg, &ctrl, | ||
356 | sizeof(struct ioctl_struct))) | ||
357 | dbg("copy_to_user failed in IORB"); | ||
358 | kfree(uBuf); | ||
359 | return ctrl.numbytes; | ||
360 | } | ||
361 | break; | ||
362 | |||
363 | case 2: //PIXIS Ping | ||
364 | case 3: //PIXIS Pong | ||
365 | if (!pdx->gotPixelData) | ||
366 | return 0; | ||
367 | else { | ||
368 | pdx->gotPixelData = 0; | ||
369 | ctrl.numbytes = pdx->bulk_in_size_returned; | ||
370 | pdx->bulk_in_size_returned -= pdx->frameSize; | ||
371 | for (i = 0; | ||
372 | i < | ||
373 | pdx->maplist_numPagesMapped[pdx-> | ||
374 | active_frame]; | ||
375 | i++) | ||
376 | SetPageDirty(pdx->sgl[pdx->active_frame][i].page_link); | ||
377 | pdx->active_frame = | ||
378 | ((pdx->active_frame + 1) % pdx->num_frames); | ||
379 | return ctrl.numbytes; | ||
380 | } | ||
381 | break; | ||
382 | } | ||
383 | break; | ||
384 | case PIUSB_WHATCAMERA: | ||
385 | return pdx->iama; | ||
386 | case PIUSB_SETFRAMESIZE: | ||
387 | dbg("PIUSB_SETFRAMESIZE"); | ||
388 | if (copy_from_user | ||
389 | (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) | ||
390 | info("copy_from_user failed\n"); | ||
391 | pdx->frameSize = ctrl.numbytes; | ||
392 | pdx->num_frames = ctrl.numFrames; | ||
393 | if (!pdx->sgl) | ||
394 | pdx->sgl = | ||
395 | kmalloc(sizeof(struct scatterlist *) * | ||
396 | pdx->num_frames, GFP_KERNEL); | ||
397 | if (!pdx->sgEntries) | ||
398 | pdx->sgEntries = | ||
399 | kmalloc(sizeof(unsigned int) * pdx->num_frames, | ||
400 | GFP_KERNEL); | ||
401 | if (!pdx->PixelUrb) | ||
402 | pdx->PixelUrb = | ||
403 | kmalloc(sizeof(struct urb **) * pdx->num_frames, | ||
404 | GFP_KERNEL); | ||
405 | if (!pdx->maplist_numPagesMapped) | ||
406 | pdx->maplist_numPagesMapped = | ||
407 | vmalloc(sizeof(unsigned int) * pdx->num_frames); | ||
408 | if (!pdx->pendedPixelUrbs) | ||
409 | pdx->pendedPixelUrbs = | ||
410 | kmalloc(sizeof(char *) * pdx->num_frames, | ||
411 | GFP_KERNEL); | ||
412 | return 0; | ||
413 | default: | ||
414 | dbg("%s\n", "No IOCTL found"); | ||
415 | break; | ||
416 | |||
417 | } | ||
418 | /* return that we did not understand this ioctl call */ | ||
419 | dbg("Returning -ENOTTY"); | ||
420 | return -ENOTTY; | ||
421 | } | ||
422 | |||
423 | static void piusb_write_bulk_callback(struct urb *urb) | ||
424 | { | ||
425 | struct device_extension *pdx = urb->context; | ||
426 | int status = urb->status; | ||
427 | |||
428 | /* sync/async unlink faults aren't errors */ | ||
429 | if (status && !(status == -ENOENT || status == -ECONNRESET)) | ||
430 | dev_dbg(&urb->dev->dev, | ||
431 | "%s - nonzero write bulk status received: %d", | ||
432 | __func__, status); | ||
433 | |||
434 | pdx->pendingWrite = 0; | ||
435 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, | ||
436 | urb->transfer_buffer, urb->transfer_dma); | ||
437 | } | ||
438 | |||
439 | int piusb_output(struct ioctl_struct * io, unsigned char *uBuf, int len, | ||
440 | struct device_extension *pdx) | ||
441 | { | ||
442 | struct urb *urb = NULL; | ||
443 | int err = 0; | ||
444 | unsigned char *kbuf = NULL; | ||
445 | |||
446 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
447 | if (urb != NULL) { | ||
448 | kbuf = | ||
449 | usb_buffer_alloc(pdx->udev, len, GFP_KERNEL, | ||
450 | &urb->transfer_dma); | ||
451 | if (!kbuf) { | ||
452 | info("buffer_alloc failed\n"); | ||
453 | return -ENOMEM; | ||
454 | } | ||
455 | memcpy(kbuf, uBuf, len); | ||
456 | usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf, | ||
457 | len, piusb_write_bulk_callback, pdx); | ||
458 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
459 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
460 | if (err) { | ||
461 | dev_err(&pdx->udev->dev, | ||
462 | "WRITE ERROR:submit urb error = %d\n", err); | ||
463 | } | ||
464 | pdx->pendingWrite = 1; | ||
465 | usb_free_urb(urb); | ||
466 | } | ||
467 | return -EINPROGRESS; | ||
468 | } | ||
469 | |||
470 | static int UnMapUserBuffer(struct device_extension *pdx) | ||
471 | { | ||
472 | int i = 0; | ||
473 | int k = 0; | ||
474 | unsigned int epAddr; | ||
475 | for (k = 0; k < pdx->num_frames; k++) { | ||
476 | dbg("Killing Urbs for Frame %d", k); | ||
477 | for (i = 0; i < pdx->sgEntries[k]; i++) { | ||
478 | usb_kill_urb(pdx->PixelUrb[k][i]); | ||
479 | usb_free_urb(pdx->PixelUrb[k][i]); | ||
480 | pdx->pendedPixelUrbs[k][i] = 0; | ||
481 | } | ||
482 | dbg("Urb error count = %d", errCnt); | ||
483 | errCnt = 0; | ||
484 | dbg("Urbs free'd and Killed for Frame %d", k); | ||
485 | } | ||
486 | |||
487 | for (k = 0; k < pdx->num_frames; k++) { | ||
488 | if (pdx->iama == PIXIS_PID) //if so, which EP should we map this frame to | ||
489 | { | ||
490 | if (k % 2) //check to see if this should use EP4(PONG) | ||
491 | { | ||
492 | epAddr = pdx->hEP[3]; //PONG, odd frames | ||
493 | } else { | ||
494 | epAddr = pdx->hEP[2]; //PING, even frames and zero | ||
495 | } | ||
496 | } else //ST133 only has 1 endpoint for Pixel data transfer | ||
497 | { | ||
498 | epAddr = pdx->hEP[0]; | ||
499 | } | ||
500 | usb_buffer_unmap_sg(pdx->udev, epAddr, pdx->sgl[k], | ||
501 | pdx->maplist_numPagesMapped[k]); | ||
502 | for (i = 0; i < pdx->maplist_numPagesMapped[k]; i++) { | ||
503 | page_cache_release(pdx->sgl[k][i].page_link); | ||
504 | } | ||
505 | kfree(pdx->sgl[k]); | ||
506 | kfree(pdx->PixelUrb[k]); | ||
507 | kfree(pdx->pendedPixelUrbs[k]); | ||
508 | pdx->sgl[k] = NULL; | ||
509 | pdx->PixelUrb[k] = NULL; | ||
510 | pdx->pendedPixelUrbs[k] = NULL; | ||
511 | } | ||
512 | kfree(pdx->sgEntries); | ||
513 | vfree(pdx->maplist_numPagesMapped); | ||
514 | pdx->sgEntries = NULL; | ||
515 | pdx->maplist_numPagesMapped = NULL; | ||
516 | kfree(pdx->sgl); | ||
517 | kfree(pdx->pendedPixelUrbs); | ||
518 | kfree(pdx->PixelUrb); | ||
519 | pdx->sgl = NULL; | ||
520 | pdx->pendedPixelUrbs = NULL; | ||
521 | pdx->PixelUrb = NULL; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static void piusb_readPIXEL_callback(struct urb *urb) | ||
526 | { | ||
527 | int i = 0; | ||
528 | struct device_extension *pdx = urb->context; | ||
529 | int status = urb->status; | ||
530 | |||
531 | if (status && !(status == -ENOENT || status == -ECONNRESET)) { | ||
532 | dbg("%s - nonzero read bulk status received: %d", __func__, | ||
533 | status); | ||
534 | dbg("Error in read EP2 callback"); | ||
535 | dbg("FrameIndex = %d", pdx->frameIdx); | ||
536 | dbg("Bytes received before problem occurred = %d", | ||
537 | pdx->bulk_in_byte_trk); | ||
538 | dbg("Urb Idx = %d", pdx->urbIdx); | ||
539 | pdx->pendedPixelUrbs[pdx->frameIdx][pdx->urbIdx] = 0; | ||
540 | } else { | ||
541 | pdx->bulk_in_byte_trk += urb->actual_length; | ||
542 | { | ||
543 | i = usb_submit_urb(urb, GFP_ATOMIC); //resubmit the URB | ||
544 | if (i) { | ||
545 | errCnt++; | ||
546 | if (i != lastErr) { | ||
547 | dbg("submit urb in callback failed with error code %d", i); | ||
548 | lastErr = i; | ||
549 | } | ||
550 | } else { | ||
551 | pdx->urbIdx++; //point to next URB when we callback | ||
552 | if (pdx->bulk_in_byte_trk >= pdx->frameSize) { | ||
553 | pdx->bulk_in_size_returned = | ||
554 | pdx->bulk_in_byte_trk; | ||
555 | pdx->bulk_in_byte_trk = 0; | ||
556 | pdx->gotPixelData = 1; | ||
557 | pdx->frameIdx = | ||
558 | ((pdx->frameIdx + | ||
559 | 1) % pdx->num_frames); | ||
560 | pdx->urbIdx = 0; | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | } | ||
566 | |||
567 | /* MapUserBuffer( | ||
568 | inputs: | ||
569 | struct ioctl_struct *io - structure containing user address, frame #, and size | ||
570 | struct device_extension *pdx - the PIUSB device extension | ||
571 | returns: | ||
572 | int - status of the task | ||
573 | Notes: | ||
574 | MapUserBuffer maps a buffer passed down through an ioctl. The user buffer is Page Aligned by the app | ||
575 | and then passed down. The function get_free_pages(...) does the actual mapping of the buffer from user space to | ||
576 | kernel space. From there a scatterlist is created from all the pages. The next function called is to usb_buffer_map_sg | ||
577 | which allocated DMA addresses for each page, even coalescing them if possible. The DMA address is placed in the scatterlist | ||
578 | structure. The function returns the number of DMA addresses. This may or may not be equal to the number of pages that | ||
579 | the user buffer uses. We then build an URB for each DMA address and then submit them. | ||
580 | */ | ||
581 | //int MapUserBuffer( unsigned long uaddr, unsigned long numbytes, unsigned long frameInfo, struct device_extension *pdx ) | ||
582 | static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) | ||
583 | { | ||
584 | unsigned long uaddr; | ||
585 | unsigned long numbytes; | ||
586 | int frameInfo; //which frame we're mapping | ||
587 | unsigned int epAddr = 0; | ||
588 | unsigned long count = 0; | ||
589 | int i = 0; | ||
590 | int k = 0; | ||
591 | int err = 0; | ||
592 | struct page **maplist_p; | ||
593 | int numPagesRequired; | ||
594 | frameInfo = io->numFrames; | ||
595 | uaddr = (unsigned long)io->pData; | ||
596 | numbytes = io->numbytes; | ||
597 | |||
598 | if (pdx->iama == PIXIS_PID) //if so, which EP should we map this frame to | ||
599 | { | ||
600 | if (frameInfo % 2) //check to see if this should use EP4(PONG) | ||
601 | { | ||
602 | epAddr = pdx->hEP[3]; //PONG, odd frames | ||
603 | } else { | ||
604 | epAddr = pdx->hEP[2]; //PING, even frames and zero | ||
605 | } | ||
606 | dbg("Pixis Frame #%d: EP=%d", frameInfo, | ||
607 | (epAddr == pdx->hEP[2]) ? 2 : 4); | ||
608 | } else //ST133 only has 1 endpoint for Pixel data transfer | ||
609 | { | ||
610 | epAddr = pdx->hEP[0]; | ||
611 | dbg("ST133 Frame #%d: EP=2", frameInfo); | ||
612 | } | ||
613 | count = numbytes; | ||
614 | dbg("UserAddress = 0x%08lX", uaddr); | ||
615 | dbg("numbytes = %d", (int)numbytes); | ||
616 | //number of pages to map the entire user space DMA buffer | ||
617 | numPagesRequired = | ||
618 | ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; | ||
619 | dbg("Number of pages needed = %d", numPagesRequired); | ||
620 | maplist_p = vmalloc(numPagesRequired * sizeof(struct page)); //, GFP_ATOMIC); | ||
621 | if (!maplist_p) { | ||
622 | dbg("Can't Allocate Memory for maplist_p"); | ||
623 | return -ENOMEM; | ||
624 | } | ||
625 | //map the user buffer to kernel memory | ||
626 | down_write(¤t->mm->mmap_sem); | ||
627 | pdx->maplist_numPagesMapped[frameInfo] = get_user_pages(current, current->mm, (uaddr & PAGE_MASK), numPagesRequired, WRITE, 0, //Don't Force | ||
628 | maplist_p, | ||
629 | NULL); | ||
630 | up_write(¤t->mm->mmap_sem); | ||
631 | dbg("Number of pages mapped = %d", | ||
632 | pdx->maplist_numPagesMapped[frameInfo]); | ||
633 | for (i = 0; i < pdx->maplist_numPagesMapped[frameInfo]; i++) | ||
634 | flush_dcache_page(maplist_p[i]); | ||
635 | if (!pdx->maplist_numPagesMapped[frameInfo]) { | ||
636 | dbg("get_user_pages() failed"); | ||
637 | vfree(maplist_p); | ||
638 | return -ENOMEM; | ||
639 | } | ||
640 | //need to create a scatterlist that spans each frame that can fit into the mapped buffer | ||
641 | pdx->sgl[frameInfo] = | ||
642 | kmalloc((pdx->maplist_numPagesMapped[frameInfo] * | ||
643 | sizeof(struct scatterlist)), GFP_ATOMIC); | ||
644 | if (!pdx->sgl[frameInfo]) { | ||
645 | vfree(maplist_p); | ||
646 | dbg("can't allocate mem for sgl"); | ||
647 | return -ENOMEM; | ||
648 | } | ||
649 | pdx->sgl[frameInfo][0].page_link = maplist_p[0]; | ||
650 | pdx->sgl[frameInfo][0].offset = uaddr & ~PAGE_MASK; | ||
651 | if (pdx->maplist_numPagesMapped[frameInfo] > 1) { | ||
652 | pdx->sgl[frameInfo][0].length = | ||
653 | PAGE_SIZE - pdx->sgl[frameInfo][0].offset; | ||
654 | count -= pdx->sgl[frameInfo][0].length; | ||
655 | for (k = 1; k < pdx->maplist_numPagesMapped[frameInfo]; k++) { | ||
656 | pdx->sgl[frameInfo][k].offset = 0; | ||
657 | pdx->sgl[frameInfo][k].page_link = maplist_p[k]; | ||
658 | pdx->sgl[frameInfo][k].length = | ||
659 | (count < PAGE_SIZE) ? count : PAGE_SIZE; | ||
660 | count -= PAGE_SIZE; //example had PAGE_SIZE here; | ||
661 | } | ||
662 | } else { | ||
663 | pdx->sgl[frameInfo][0].length = count; | ||
664 | } | ||
665 | pdx->sgEntries[frameInfo] = | ||
666 | usb_buffer_map_sg(pdx->udev, epAddr, pdx->sgl[frameInfo], | ||
667 | pdx->maplist_numPagesMapped[frameInfo]); | ||
668 | dbg("number of sgEntries = %d", pdx->sgEntries[frameInfo]); | ||
669 | pdx->userBufMapped = 1; | ||
670 | vfree(maplist_p); | ||
671 | //Create and Send the URB's for each s/g entry | ||
672 | pdx->PixelUrb[frameInfo] = | ||
673 | kmalloc(pdx->sgEntries[frameInfo] * sizeof(struct urb *), | ||
674 | GFP_KERNEL); | ||
675 | if (!pdx->PixelUrb[frameInfo]) { | ||
676 | dbg("Can't Allocate Memory for Urb"); | ||
677 | return -ENOMEM; | ||
678 | } | ||
679 | for (i = 0; i < pdx->sgEntries[frameInfo]; i++) { | ||
680 | pdx->PixelUrb[frameInfo][i] = usb_alloc_urb(0, GFP_KERNEL); //0 because we're using BULK transfers | ||
681 | usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i], | ||
682 | pdx->udev, | ||
683 | epAddr, | ||
684 | (dma_addr_t *) sg_dma_address(&pdx-> | ||
685 | sgl[frameInfo] | ||
686 | [i]), | ||
687 | sg_dma_len(&pdx->sgl[frameInfo][i]), | ||
688 | piusb_readPIXEL_callback, (void *)pdx); | ||
689 | pdx->PixelUrb[frameInfo][i]->transfer_dma = | ||
690 | sg_dma_address(&pdx->sgl[frameInfo][i]); | ||
691 | pdx->PixelUrb[frameInfo][i]->transfer_flags = | ||
692 | URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; | ||
693 | } | ||
694 | pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT; //only interrupt when last URB completes | ||
695 | pdx->pendedPixelUrbs[frameInfo] = | ||
696 | kmalloc((pdx->sgEntries[frameInfo] * sizeof(char)), GFP_KERNEL); | ||
697 | if (!pdx->pendedPixelUrbs[frameInfo]) | ||
698 | dbg("Can't allocate Memory for pendedPixelUrbs"); | ||
699 | for (i = 0; i < pdx->sgEntries[frameInfo]; i++) { | ||
700 | err = usb_submit_urb(pdx->PixelUrb[frameInfo][i], GFP_ATOMIC); | ||
701 | if (err) { | ||
702 | dbg("%s %d\n", "submit urb error =", err); | ||
703 | pdx->pendedPixelUrbs[frameInfo][i] = 0; | ||
704 | return err; | ||
705 | } else | ||
706 | pdx->pendedPixelUrbs[frameInfo][i] = 1;; | ||
707 | } | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | static struct file_operations piusb_fops = { | ||
712 | .owner = THIS_MODULE, | ||
713 | .ioctl = piusb_ioctl, | ||
714 | .open = piusb_open, | ||
715 | .release = piusb_release, | ||
716 | }; | ||
717 | |||
718 | static struct usb_class_driver piusb_class = { | ||
719 | .name = "usb/rspiusb%d", | ||
720 | .fops = &piusb_fops, | ||
721 | .minor_base = PIUSB_MINOR_BASE, | ||
722 | }; | ||
723 | |||
724 | /** | ||
725 | * piusb_probe | ||
726 | * | ||
727 | * Called by the usb core when a new device is connected that it thinks | ||
728 | * this driver might be interested in. | ||
729 | */ | ||
730 | static int piusb_probe(struct usb_interface *interface, | ||
731 | const struct usb_device_id *id) | ||
732 | { | ||
733 | struct device_extension *pdx = NULL; | ||
734 | struct usb_host_interface *iface_desc; | ||
735 | struct usb_endpoint_descriptor *endpoint; | ||
736 | int i; | ||
737 | int retval = -ENOMEM; | ||
738 | |||
739 | dev_dbg(&interface->dev, "%s - Looking for PI USB Hardware", __func__); | ||
740 | |||
741 | pdx = kzalloc(sizeof(struct device_extension), GFP_KERNEL); | ||
742 | if (pdx == NULL) { | ||
743 | dev_err(&interface->dev, "Out of memory\n"); | ||
744 | goto error; | ||
745 | } | ||
746 | kref_init(&pdx->kref); | ||
747 | pdx->udev = usb_get_dev(interface_to_usbdev(interface)); | ||
748 | pdx->interface = interface; | ||
749 | iface_desc = interface->cur_altsetting; | ||
750 | |||
751 | /* See if the device offered us matches what we can accept */ | ||
752 | if ((pdx->udev->descriptor.idVendor != VENDOR_ID) | ||
753 | || ((pdx->udev->descriptor.idProduct != PIXIS_PID) | ||
754 | && (pdx->udev->descriptor.idProduct != ST133_PID))) { | ||
755 | return -ENODEV; | ||
756 | } | ||
757 | pdx->iama = pdx->udev->descriptor.idProduct; | ||
758 | |||
759 | if (debug) { | ||
760 | if (pdx->udev->descriptor.idProduct == PIXIS_PID) | ||
761 | dbg("PIUSB:Pixis Camera Found"); | ||
762 | else | ||
763 | dbg("PIUSB:ST133 USB Controller Found"); | ||
764 | if (pdx->udev->speed == USB_SPEED_HIGH) | ||
765 | dbg("Highspeed(USB2.0) Device Attached"); | ||
766 | else | ||
767 | dbg("Lowspeed (USB1.1) Device Attached"); | ||
768 | |||
769 | dbg("NumEndpoints in Configuration: %d", | ||
770 | iface_desc->desc.bNumEndpoints); | ||
771 | } | ||
772 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | ||
773 | endpoint = &iface_desc->endpoint[i].desc; | ||
774 | if (debug) { | ||
775 | dbg("Endpoint[%d]->bDescriptorType = %d", i, | ||
776 | endpoint->bDescriptorType); | ||
777 | dbg("Endpoint[%d]->bEndpointAddress = 0x%02X", i, | ||
778 | endpoint->bEndpointAddress); | ||
779 | dbg("Endpoint[%d]->bbmAttributes = %d", i, | ||
780 | endpoint->bmAttributes); | ||
781 | dbg("Endpoint[%d]->MaxPacketSize = %d\n", i, | ||
782 | endpoint->wMaxPacketSize); | ||
783 | } | ||
784 | if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
785 | USB_ENDPOINT_XFER_BULK) { | ||
786 | if (endpoint->bEndpointAddress & USB_DIR_IN) | ||
787 | pdx->hEP[i] = | ||
788 | usb_rcvbulkpipe(pdx->udev, | ||
789 | endpoint->bEndpointAddress); | ||
790 | else | ||
791 | pdx->hEP[i] = | ||
792 | usb_sndbulkpipe(pdx->udev, | ||
793 | endpoint->bEndpointAddress); | ||
794 | } | ||
795 | } | ||
796 | usb_set_intfdata(interface, pdx); | ||
797 | retval = usb_register_dev(interface, &piusb_class); | ||
798 | if (retval) { | ||
799 | err("Not able to get a minor for this device."); | ||
800 | usb_set_intfdata(interface, NULL); | ||
801 | goto error; | ||
802 | } | ||
803 | pdx->present = 1; | ||
804 | |||
805 | /* we can register the device now, as it is ready */ | ||
806 | pdx->minor = interface->minor; | ||
807 | /* let the user know what node this device is now attached to */ | ||
808 | dbg("PI USB2.0 device now attached to piusb-%d", pdx->minor); | ||
809 | return 0; | ||
810 | |||
811 | error: | ||
812 | if (pdx) | ||
813 | kref_put(&pdx->kref, piusb_delete); | ||
814 | return retval; | ||
815 | } | ||
816 | |||
817 | /** | ||
818 | * piusb_disconnect | ||
819 | * | ||
820 | * Called by the usb core when the device is removed from the system. | ||
821 | * | ||
822 | * This routine guarantees that the driver will not submit any more urbs | ||
823 | * by clearing pdx->udev. It is also supposed to terminate any currently | ||
824 | * active urbs. Unfortunately, usb_bulk_msg(), used in piusb_read(), does | ||
825 | * not provide any way to do this. But at least we can cancel an active | ||
826 | * write. | ||
827 | */ | ||
828 | static void piusb_disconnect(struct usb_interface *interface) | ||
829 | { | ||
830 | struct device_extension *pdx; | ||
831 | int minor = interface->minor; | ||
832 | lock_kernel(); | ||
833 | pdx = usb_get_intfdata(interface); | ||
834 | usb_set_intfdata(interface, NULL); | ||
835 | /* give back our minor */ | ||
836 | usb_deregister_dev(interface, &piusb_class); | ||
837 | unlock_kernel(); | ||
838 | /* prevent device read, write and ioctl */ | ||
839 | pdx->present = 0; | ||
840 | kref_put(&pdx->kref, piusb_delete); | ||
841 | dbg("PI USB2.0 device #%d now disconnected\n", minor); | ||
842 | } | ||
843 | |||
844 | static struct usb_driver piusb_driver = { | ||
845 | .name = "sub", | ||
846 | .probe = piusb_probe, | ||
847 | .disconnect = piusb_disconnect, | ||
848 | .id_table = pi_device_table, | ||
849 | }; | ||
850 | |||
851 | /** | ||
852 | * piusb_init | ||
853 | */ | ||
854 | static int __init piusb_init(void) | ||
855 | { | ||
856 | int result; | ||
857 | /* register this driver with the USB subsystem */ | ||
858 | result = usb_register(&piusb_driver); | ||
859 | if (result) { | ||
860 | printk(KERN_ERR KBUILD_MODNAME | ||
861 | ": usb_register failed. Error number %d\n", result); | ||
862 | return result; | ||
863 | } | ||
864 | printk(KERN_INFO KBUILD_MODNAME ":%s: %s\n", DRIVER_DESC, | ||
865 | DRIVER_VERSION); | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | /** | ||
870 | * piusb_exit | ||
871 | */ | ||
872 | static void __exit piusb_exit(void) | ||
873 | { | ||
874 | /* deregister this driver with the USB subsystem */ | ||
875 | usb_deregister(&piusb_driver); | ||
876 | } | ||
877 | |||
878 | module_init(piusb_init); | ||
879 | module_exit(piusb_exit); | ||
880 | |||
881 | /* Module parameters */ | ||
882 | module_param(debug, int, 0); | ||
883 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
884 | |||
885 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
886 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
887 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/rspiusb/rspiusb.h b/drivers/staging/rspiusb/rspiusb.h new file mode 100644 index 000000000000..965cd2d8c194 --- /dev/null +++ b/drivers/staging/rspiusb/rspiusb.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef __RSPIUSB_H | ||
2 | #define __RSPIUSB_H | ||
3 | |||
4 | #define PIUSB_MAGIC 'm' | ||
5 | #define PIUSB_IOCTL_BASE 192 | ||
6 | #define PIUSB_GETVNDCMD _IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 1, struct ioctl_struct) | ||
7 | #define PIUSB_SETVNDCMD _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 2, struct ioctl_struct) | ||
8 | #define PIUSB_WRITEPIPE _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 3, struct ioctl_struct) | ||
9 | #define PIUSB_READPIPE _IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 4, struct ioctl_struct) | ||
10 | #define PIUSB_SETFRAMESIZE _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 5, struct ioctl_struct) | ||
11 | #define PIUSB_WHATCAMERA _IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 6) | ||
12 | #define PIUSB_USERBUFFER _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 7, struct ioctl_struct) | ||
13 | #define PIUSB_ISHIGHSPEED _IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 8) | ||
14 | #define PIUSB_UNMAP_USERBUFFER _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 9, struct ioctl_struct) | ||
15 | |||
16 | struct ioctl_struct { | ||
17 | unsigned char cmd; | ||
18 | unsigned long numbytes; | ||
19 | unsigned char dir; //1=out;0=in | ||
20 | int endpoint; | ||
21 | int numFrames; | ||
22 | unsigned char *pData; | ||
23 | }; | ||
24 | |||
25 | #endif | ||