/* -*- linux-c -*- * USB Anchor chips dev board driver * * * (C) Copyright 1999 Rob Melby */ #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 struct usb_device * ez_dev = NULL; 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); printk(KERN_DEBUG "anchor.c: get config returned %i\n", (int) byte); 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) 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"); /* register stuff */ if ((register_chrdev(180, "EZUSB", &usb_anchor_fops)) < 0) { printk(KERN_WARNING "anchor.c: Cannot register device\n"); return -1; } 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; } 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 struct file_operations usb_anchor_fops = { NULL, NULL, write_anchor, NULL, NULL, NULL, NULL, open_anchor, NULL, close_anchor, NULL, NULL }; */ static struct file_operations usb_anchor_fops = { write: write_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