/* -*- linux-c -*- * USB Anchor chips dev board driver * * * (C) Copyright 1999 Rob Melby * (C) Copyright 2000 William Rachelson */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uhci.h" /* #include "test_program.h" */ #define GET_LINE_RESET -10000 #define PARSE_OK 0 #define PARSE_EOF 1 #define PARSE_ERROR -1 #define GET_TIMEOUT 3 #define ANCHOR_MINOR 101 #define DEBUG 1 /* we need more packaging.. like a ez_dev struct that contains the device plus * anything else.. like the wait queue * we can then shove that in file->private for read/write in order to make * this code less crappy */ struct usb_device * ez_dev = NULL; wait_queue_head_t wait; static struct file_operations usb_anchor_fops; static int usb_anchor_download(struct usb_device * dev, unsigned short int address, unsigned char * buf, int length); static int usb_anchor_verify(struct usb_device * dev, unsigned short int address, unsigned char byte); static int usb_anchor_get_config(struct usb_device *dev) { int result; unsigned char byte; devrequest dr; dr.requesttype = 0x80; //(USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80; dr.request = 0x08; dr.value = 0; dr.index = 0; dr.length = 1; /* result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &byte, 1); */ result = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), dr.request, dr.requesttype, 0, 0, &byte, 1, HZ * GET_TIMEOUT); #ifdef DEBUG printk(KERN_DEBUG "anchor.c: get config returned %i\n", (int) byte); #endif return result; } static int convert_char(char c) { if (c < 58) { return c - 48; } else { return c - 55; } } static int read_byte(char ** line) { int b; b = convert_char(**line); (*line)++; b = b*16 + convert_char(**line); (*line)++; return b; } static int program_code_byte(int address, unsigned char byte) { if (!ez_dev) { return -1; } // printk("[%x]: %x\n", address, byte); usb_anchor_download(ez_dev, (short int)address, &byte, 1); usb_anchor_verify(ez_dev, address, byte); return 0; } static int parse_line(char * line) { int i; int checksum = 0; int length, address, type, temp; if (*(line++) != ':') { printk(KERN_DEBUG "anchor.c: line didn't start with ':', started with %c\n", *(--line)); return PARSE_ERROR; } checksum += length = read_byte(&line); checksum += address = read_byte(&line); address = (address*256) + (temp = read_byte(&line)); // printk("Address: %i\n", address); checksum += temp; checksum += type = read_byte(&line); if (type == 1) { return PARSE_EOF; } for (i = 0; i < length; i++) { int byte; checksum += byte = read_byte(&line); //printk("[%x]: %x\n", address, byte); program_code_byte(address++, (unsigned char)byte); } // read the final checksum checksum += read_byte(&line); if ((checksum & 0xF) != 0) { printk(KERN_DEBUG "anchor.c: checksum returned %i should have been 0\n", checksum&0xf); return PARSE_ERROR; } return PARSE_OK; } static int usb_anchor_download(struct usb_device * dev, unsigned short int address, unsigned char * buf, int length) { int result; unsigned char buffer[64]; devrequest dr; dr.requesttype = 0x40; dr.request = 0xa0; dr.value = address; dr.index = 0; dr.length = length; memcpy(buffer, buf, (length < 64)?length:64); /* result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buffer, length); */ result = usb_control_msg(dev, usb_sndctrlpipe(dev,0), dr.request, dr.requesttype, dr.value, dr.index, buffer, length, HZ * GET_TIMEOUT); // printk("RESULT %i\n", result); return -result; } static int usb_anchor_reset_8051(struct usb_device * dev) { unsigned char enable = 0x01; int result; devrequest dr; dr.requesttype = 0x40; dr.request = 0xA0; dr.value = 0x7f92; dr.index = 0; dr.length = 1; /* result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, &enable, 1); */ result = usb_control_msg(dev, usb_sndctrlpipe(dev,0), dr.request, dr.requesttype, dr.value, dr.index, &enable, 1, HZ * GET_TIMEOUT); return result; } static int usb_anchor_run_8051(struct usb_device * dev) { unsigned char enable = 0x00; int result; devrequest dr; dr.requesttype = 0x40; dr.request = 0xA0; dr.value = 0x7F92; dr.index = 0; dr.length = 1; /* result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, &enable, 1); */ result = usb_control_msg(dev, usb_sndctrlpipe(dev,0), dr.request, dr.requesttype, dr.value, dr.index, &enable, 1, HZ * GET_TIMEOUT); return result; } static int usb_anchor_verify(struct usb_device * dev, unsigned short int address, unsigned char byte) { unsigned char buffer; devrequest dr; int result; dr.requesttype = 0xc0; dr.request = 0xa0; dr.value = address; dr.index = 0; dr.length = 1; /* result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &buffer, 1); */ result = usb_control_msg(dev, usb_sndctrlpipe(dev,0), dr.request, dr.requesttype, dr.value, dr.index, &buffer, 1, HZ * GET_TIMEOUT); if (buffer != byte) { printk(KERN_DEBUG "anchor.c: %x, was %x should be %x\n", address, buffer, byte); } return -result; } static void * anchor_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; /* struct usb_endpoint_descriptor *endpoint; */ printk(KERN_DEBUG "anchor.c: in anchor_probe\n"); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return -1; /* interface = &dev->config[0].interface[0];*/ interface = dev->config->interface->altsetting; /* 6:46 fearlessleader kernel: Vendor: 0547 Sep 11 01:56:46 fearlessleader kernel: Product: 0080 Sep 11 01:56:46 fearlessleader kernel: Configurations: 1 Sep 11 01:56:46 fearlessleader kernel: Device Class: 255 Sep 11 01:56:46 fearlessleader kernel: Vendor class */ printk(KERN_DEBUG "anchor.c: Vendor: %x\n", dev->descriptor.idVendor); printk(KERN_DEBUG "anchor.c: Product: %x\n", dev->descriptor.idProduct); if (dev->descriptor.idVendor != 0x547) return -1; if(dev->descriptor.idProduct != 0x80) { if(dev->descriptor.idProduct != 0x2131) { printk(KERN_DEBUG "anchor.c: Invalid product ID for anchor. !(80 || 2131)\n"); return -1; } } if (interface->bInterfaceClass != 0xFF) return -1; if (interface->bInterfaceSubClass != 0xff) return -1; printk(KERN_DEBUG "anchor.c: USB anchor dev kit found\n"); usb_set_configuration(dev, dev->config[0].bConfigurationValue); usb_set_interface(dev, 0, 1); usb_anchor_get_config(dev); ez_dev = dev; printk(KERN_DEBUG "anchor.c: attempting device registration...\n"); /* I think this is done by the usb subsystem? if ((register_chrdev(180, "EZUSB", &usb_anchor_fops)) < 0) { printk(KERN_DEBUG "anchor.c: Cannot register device\n"); return -1; } /* /* ok this is stupid... we need a ez_usb struct */ if (!(wait = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL))) { printk(KERN_DEBUG "anchor.c: error out of memory\n"); return NULL; } init_waitqueue_head(&wait); printk(KERN_DEBUG "anchor.c: setting device to alt setting 1\n"); if (usb_set_configuration(ez_dev, 1) < 0) { printk(KERN_DEBUG "anchor.c: error, could not set config #: 1\n"); } printk(KERN_DEBUG "anchor.c: registered ezusb device\n"); return 0; } static int open_anchor(struct inode * inode, struct file * file) { return 0; } static int close_anchor(struct inode * inode, struct file * file) { return 0; } static int get_line(unsigned char * buffer, unsigned char * line, int c) { static int count = -100; static int len; static unsigned char * buf = NULL; int index = 0; if (c == GET_LINE_RESET) { printk(KERN_DEBUG "anchor.c: get line reset\n"); count = -100; buf = NULL; return -1; } if (count == -100) { len = c; count = 0; } if (buf == NULL) { buf = buffer; } while ((count < len) && (buf[count] != '\n')) { // seek until we find a carriage return or run out of buffer line[index] = buf[count]; //printk("%c", line[index]); count++; index++; } //printk("\n%i %i\n", count, len); //printk("\nlast char was %c\n", buf[count]); count++; // this should be the carriage return if (count > len) { //printk("count was greater than len\n"); count = -100; buf = NULL; return -1; } return 1; } /* Writing to the ezusb device has the following behavior: * - performs reset * - parses input in intel hex format (IHX) * - sends input to ezusb * - begins execution of ihx instructions on the 8051 */ static ssize_t write_anchor(struct file *file, const char *buffer, size_t count, loff_t *ppos) { unsigned char * buf = NULL; unsigned char line[200]; buf = (unsigned char *)vmalloc(count); if (!buf) { return -EIO; } if (copy_from_user(buf, buffer, count)) return -EFAULT; usb_anchor_reset_8051(ez_dev); while ((get_line(buf, line, count) > 0) && !signal_pending(current)) { switch (parse_line(line)) { case PARSE_OK: break; case PARSE_EOF: break; default: printk(KERN_DEBUG "anchor.c: Error while parsing input\n"); // reset get_line kludge!! get_line(NULL, NULL, GET_LINE_RESET); return -EFAULT; } } if (signal_pending(current)) { return -EAGAIN; } usb_anchor_run_8051(ez_dev); return count; } static void anchor_wake_up(struct urb *urb) { printk(KERN_DEBUG "anchor.c: anchor_wake_up called\n"); wake_up_interruptible(&wait); } static ssize_t read_anchor(struct file *file, char *buffer, size_t count, loff_t *ppos) { purb_t purb; unsigned char *buf = NULL; int error; buf = (unsigned char *)vmalloc(count); if (!buf) { return -EIO; } printk(KERN_DEBUG "anchor.c: User requested read of %d bytes\n", count); /* allocate a urb */ purb = usb_alloc_urb(0); printk(KERN_DEBUG "anchor.c: allocated URB\n"); FILL_BULK_URB(purb, ez_dev, usb_rcvbulkpipe(ez_dev,2), buf, count, anchor_wake_up, ez_dev); error = usb_submit_urb(purb); if(error) { /* failure */ /* shrug */ printk(KERN_DEBUG "anchor.c: error submitting URB: %d\n", error); usb_free_urb(purb); return -EFAULT; } if(purb->status == -EINPROGRESS) { /* wait for completion */ printk(KERN_DEBUG "anchor.c: sleeping until complete\n"); interruptible_sleep_on(&wait); /* we're back, that was fast! */ printk(KERN_DEBUG "anchor.c: woke up\n"); } if(purb->status) { if(purb->status == -EINPROGRESS) { usb_unlink_urb(purb); } printk(KERN_DEBUG "anchor.c: couldn't get data from ezusb: error: %d\n", purb->status); usb_free_urb(purb); return -EFAULT; } if (copy_to_user(buffer, buf, purb->actual_length)) { usb_free_urb(purb); return -EFAULT; } printk(KERN_DEBUG "anchor.c: gave %d bytes to user\n", purb->actual_length); usb_free_urb(purb); return purb->actual_length; } static struct file_operations usb_anchor_fops = { write: write_anchor, read: read_anchor, open: open_anchor, release: close_anchor }; static void anchor_disconnect(struct usb_device *dev, void *ptr) { printk(KERN_DEBUG "anchor.c anchor dev kit disconnected\n"); unregister_chrdev(180, "EZUSB"); } static struct usb_driver anchor_driver = { "Anchor", anchor_probe, anchor_disconnect, { NULL, NULL }, &usb_anchor_fops, ANCHOR_MINOR }; int usb_anchor_init(void) { usb_register(&anchor_driver); return 0; } #ifdef MODULE int init_module(void) { printk(KERN_DEBUG "anchor.c: init_module: usb_anchor\n"); return usb_anchor_init(); } void cleanup_module(void) { usb_deregister(&anchor_driver); } #endif