1 /*****************************************************************************/
4 * ezusb.c -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
7 * Thomas Sailer (sailer@ife.ee.ethz.ch)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * 0.1 26.05.99 Created
28 /*****************************************************************************/
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/socket.h>
33 #include <asm/uaccess.h>
34 #include <linux/miscdevice.h>
39 /* --------------------------------------------------------------------- */
44 struct semaphore mutex
;
45 struct usb_device
*usbdev
;
48 unsigned char intdata
[64];
51 /* --------------------------------------------------------------------- */
53 static int ezusb_irq(int state
, void *__buffer
, int len
, void *dev_id
)
55 struct ezusb
*ez
= (struct ezusb
*)dev_id
;
57 if (len
> sizeof(ez
->intdata
))
58 len
= sizeof(ez
->intdata
);
60 memcpy(ez
->intdata
, __buffer
, len
);
64 /* --------------------------------------------------------------------- */
66 static loff_t
ezusb_llseek(struct file
*file
, loff_t offset
, int origin
)
68 struct ezusb
*ez
= (struct ezusb
*)file
->private_data
;
72 offset
+= file
->f_pos
;
78 if (offset
< 0 || offset
>= 0x10000)
80 return (file
->f_pos
= offset
);
83 static ssize_t
ezusb_read(struct file
*file
, char *buf
, size_t sz
, loff_t
*ppos
)
85 struct ezusb
*ez
= (struct ezusb
*)file
->private_data
;
93 if (*ppos
< 0 || *ppos
>= 0x10000)
100 while (sz
> 0 && pos
< 0x10000) {
104 if (pos
+ len
> 0x10000)
106 dr
.requesttype
= 0xc0;
111 i
= ez
->usbdev
->bus
->op
->control_msg(ez
->usbdev
, usb_rcvctrlpipe(ez
->usbdev
, 0), &dr
, b
, len
);
114 printk(KERN_WARNING
"ezusb: upload failed pos %u len %u ret %d\n", dr
.value
, dr
.length
, i
);
120 if (copy_to_user(buf
, b
, len
)) {
137 static ssize_t
ezusb_write(struct file
*file
, const char *buf
, size_t sz
, loff_t
*ppos
)
139 struct ezusb
*ez
= (struct ezusb
*)file
->private_data
;
140 unsigned pos
= *ppos
;
147 if (*ppos
< 0 || *ppos
>= 0x10000)
154 while (sz
> 0 && pos
< 0x10000) {
158 if (pos
+ len
> 0x10000)
160 if (copy_from_user(b
, buf
, len
)) {
167 dr
.requesttype
= 0x40;
172 i
= ez
->usbdev
->bus
->op
->control_msg(ez
->usbdev
, usb_sndctrlpipe(ez
->usbdev
, 0), &dr
, b
, len
);
175 printk(KERN_WARNING
"ezusb: download failed pos %u len %u ret %d\n", dr
.value
, dr
.length
, i
);
191 static int ezusb_open(struct inode
*inode
, struct file
*file
)
193 struct ezusb
*ez
= &ezusb
[0];
196 while (!ez
->usbdev
) {
198 if (!(file
->f_flags
& O_NONBLOCK
)) {
201 schedule_timeout(HZ
/2);
202 if (signal_pending(current
))
208 file
->private_data
= ez
;
212 static int ezusb_release(struct inode
*inode
, struct file
*file
)
214 struct ezusb
*ez
= (struct ezusb
*)file
->private_data
;
218 static int ezusb_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
220 struct ezusb
*ez
= (struct ezusb
*)file
->private_data
;
221 struct ezusb_ctrltransfer ctrl
;
222 struct ezusb_bulktransfer bulk
;
223 unsigned int len1
, ep
;
226 unsigned char tbuf
[1024];
231 copy_from_user_ret(&ctrl
, (void *)arg
, sizeof(ctrl
), -EFAULT
);
232 if (ctrl
.dlen
> sizeof(tbuf
) || ctrl
.dlen
> 1024)
234 if (ctrl
.requesttype
& 0x80) {
235 if (ctrl
.dlen
&& !access_ok(VERIFY_WRITE
, ctrl
.data
, ctrl
.dlen
))
242 i
= ez
->usbdev
->bus
->op
->control_msg(ez
->usbdev
, usb_rcvctrlpipe(ez
->usbdev
, 0),
243 (devrequest
*)&ctrl
, tbuf
, ctrl
.dlen
);
245 if (!i
&& ctrl
.dlen
) {
246 copy_to_user_ret(ctrl
.data
, tbuf
, ctrl
.dlen
, -EFAULT
);
250 copy_from_user_ret(tbuf
, ctrl
.data
, ctrl
.dlen
, -EFAULT
);
257 i
= ez
->usbdev
->bus
->op
->control_msg(ez
->usbdev
, usb_sndctrlpipe(ez
->usbdev
, 0),
258 (devrequest
*)&ctrl
, tbuf
, ctrl
.dlen
);
262 printk(KERN_WARNING
"ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n",
263 ctrl
.requesttype
, ctrl
.request
, ctrl
.length
, i
);
268 case EZUSB_INTERRUPT
:
269 get_user_ret(irqep
, (unsigned int *)arg
, -EFAULT
);
270 if (irqep
!= ez
->irqep
) {
274 usb_request_irq(ez
->usbdev
, usb_rcvctrlpipe(ez
->usbdev
, ez
->irqep
),
275 ezusb_irq
, 2 /* interval */, ez
);
279 copy_to_user_ret((&((struct ezusb_interrupttransfer
*)0)->data
) + arg
,
280 ez
->intdata
, 64, -EFAULT
);
284 copy_from_user_ret(&bulk
, (void *)arg
, sizeof(bulk
), -EFAULT
);
286 if (len1
> sizeof(tbuf
))
288 if (bulk
.ep
& 0x80) {
289 if (len1
&& !access_ok(VERIFY_WRITE
, bulk
.data
, len1
))
296 i
= ez
->usbdev
->bus
->op
->bulk_msg(ez
->usbdev
, usb_rcvbulkpipe(ez
->usbdev
, bulk
.ep
& 0x7f),
300 copy_to_user_ret(bulk
.data
, tbuf
, len2
, -EFAULT
);
304 copy_from_user_ret(tbuf
, bulk
.data
, len1
, -EFAULT
);
311 i
= ez
->usbdev
->bus
->op
->bulk_msg(ez
->usbdev
, usb_sndbulkpipe(ez
->usbdev
, bulk
.ep
& 0x7f),
316 printk(KERN_WARNING
"ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n",
317 bulk
.ep
, bulk
.len
, i
);
323 get_user_ret(ep
, (unsigned int *)arg
, -EFAULT
);
324 if ((ep
& ~0x80) >= 16)
326 usb_settoggle(ez
->usbdev
, ep
& 0xf, !(ep
& 0x80), 0);
332 static struct file_operations ezusb_fops
= {
345 NULL
, /* check_media_change */
346 NULL
, /* revalidate */
350 static struct miscdevice ezusb_misc
= {
351 192, "ezusb", &ezusb_fops
354 /* --------------------------------------------------------------------- */
356 static int ezusb_probe(struct usb_device
*usbdev
)
358 struct ezusb
*ez
= &ezusb
[0];
359 struct usb_interface_descriptor
*interface
;
360 struct usb_endpoint_descriptor
*endpoint
;
363 #define KERN_DEBUG ""
364 printk(KERN_DEBUG
"ezusb: probe: vendor id 0x%x, device id 0x%x\n",
365 usbdev
->descriptor
.idVendor
, usbdev
->descriptor
.idProduct
);
367 /* the 1234:5678 is just a self assigned test ID */
368 if ((usbdev
->descriptor
.idVendor
!= 0x0547 || usbdev
->descriptor
.idProduct
!= 0x2131) &&
369 (usbdev
->descriptor
.idVendor
!= 0x1234 || usbdev
->descriptor
.idProduct
!= 0x5678))
372 /* We don't handle multiple configurations */
373 if (usbdev
->descriptor
.bNumConfigurations
!= 1)
376 /* We don't handle multiple interfaces */
377 if (usbdev
->config
[0].bNumInterfaces
!= 1)
383 printk(KERN_INFO
"ezusb: device already used\n");
387 usbdev
->private = ez
;
388 if (usb_set_configuration(usbdev
, usbdev
->config
[0].bConfigurationValue
)) {
389 printk(KERN_ERR
"ezusb: set_configuration failed\n");
392 interface
= &usbdev
->config
[0].altsetting
[1].interface
[0];
393 if (usb_set_interface(usbdev
, 0, 1)) {
394 printk(KERN_ERR
"ezusb: set_interface failed\n");
404 usbdev
->private = NULL
;
408 static void ezusb_disconnect(struct usb_device
*usbdev
)
410 struct ezusb
*ez
= (struct ezusb
*)usbdev
->private;
415 usbdev
->private = NULL
;
419 static struct usb_driver ezusb_driver
= {
426 /* --------------------------------------------------------------------- */
432 /* initialize struct */
433 for (u
= 0; u
< NREZUSB
; u
++) {
434 init_MUTEX(&ezusb
[u
].mutex
);
435 ezusb
[u
].usbdev
= NULL
;
438 /* register misc device */
439 if (misc_register(&ezusb_misc
)) {
440 printk(KERN_WARNING
"ezusb: cannot register minor %d\n", ezusb_misc
.minor
);
443 usb_register(&ezusb_driver
);
444 printk(KERN_INFO
"ezusb: Anchorchip firmware download driver registered\n");
448 void ezusb_cleanup(void)
450 usb_deregister(&ezusb_driver
);
451 misc_deregister(&ezusb_misc
);
454 /* --------------------------------------------------------------------- */
460 int init_module(void)
462 ezusb_misc
.minor
= minor
;
466 void cleanup_module(void)
473 /* --------------------------------------------------------------------- */