/* This file is part of s10sh * * Copyright (C) 2000 by Salvatore Sanfilippo * Copyright (C) 2001 by Salvatore Sanfilippo * * S10sh IS FREE SOFTWARE, UNDER THE TERMS OF THE GPL VERSION 2 * don't forget what free software means, even if today is so diffused. * * USB driver implementation * * ALL THIRD PARTY BRAND, PRODUCT AND SERVICE NAMES MENTIONED ARE * THE TRADEMARK OR REGISTERED TRADEMARK OF THEIR RESPECTIVE OWNERS */ #ifdef HAVE_USB_SUPPORT #include #include #include #include #include #include #include #ifdef __linux__ #include #endif /* __linux__ */ #ifndef PAGE_SIZE /* This should be ok in most archs: what matter is that the real * page size is equal or minor than 0x1000, not that it matches */ #define PAGE_SIZE 0x1000 #endif #include "s10sh.h" /************************** * USB API * **************************/ /* WARNING: functions with "USB" prefix are s10sh USB api functions, * functions with "usb" perfix are libusb functions */ /* USB settings */ usb_dev_handle *cameraudh; int usb_timeout = 1000; int input_ep = 0x81; int output_ep = 0x02; int configuration = 1; int interface = 0; int alternate = 0; int USB_camera_init(struct usb_device **camera_dev) { struct usb_bus *bus; struct usb_device *dev; usb_init(); usb_find_busses(); usb_find_devices(); if (!usb_busses) { if (opt_debug) fprintf(stderr, "USB initialization failed\n"); return USB_INIT_FAILED; } for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (opt_debug) printf("Found device %04X/%04X\n", dev->descriptor.idVendor, dev->descriptor.idProduct); switch(dev->descriptor.idVendor) { case VENDOR_ID_CANON: switch(dev->descriptor.idProduct) { case PRODUCT_ID_S10: *camera_dev = dev; if (opt_debug) printf("Canon S10 found\n"); return USB_INIT_S10; break; case PRODUCT_ID_S20: *camera_dev = dev; if (opt_debug) printf("Canon S20 found\n"); return USB_INIT_S20; break; case PRODUCT_ID_A20: *camera_dev = dev; if (opt_debug) printf("Canon A20 found\n"); return USB_INIT_A20; break; /* "Artem 'Zazoobr' Ignatjev" */ case PRODUCT_ID_A60: *camera_dev = dev; if (opt_debug) printf("Canon A60 found\n"); return USB_INIT_A60; break; /* Stephan Weitz */ case PRODUCT_ID_S30: *camera_dev = dev; if (opt_debug) printf("Canon S30 found\n"); return USB_INIT_S30; break; case PRODUCT_ID_S100_EU: case PRODUCT_ID_S100_US: *camera_dev = dev; if (opt_debug) printf("Canon S100 found\n"); return USB_INIT_S100; break; /* Sean_Welch@alum.wofford.org */ case PRODUCT_ID_S400: *camera_dev = dev; if (opt_debug) printf("Canon S400 found\n"); return USB_INIT_S400; break; /* David Jones */ case PRODUCT_ID_DIGITAL_IXUS_V3: *camera_dev = dev; if (opt_debug) printf("Canon Digital IXUS V3 found\n"); return USB_INIT_IXUS_V3; break; case PRODUCT_ID_G1: *camera_dev = dev; if (opt_debug) printf("Canon G1 found\n"); return USB_INIT_G1; break; case PRODUCT_ID_G3: *camera_dev = dev; if (opt_debug) printf("Canon G3 found\n"); return USB_INIT_G3; break; /* Matthew Dillon */ case PRODUCT_ID_10D: *camera_dev = dev; if (opt_debug) printf("Canon EOS-10D found\n"); /* This camera believes the flash in drive "C:" instead of drive "D:" ... whatever */ setdcimpath("C:\\DCIM"); return USB_INIT_10D; break; case PRODUCT_ID_DIG_V2: *camera_dev = dev; if (opt_debug) printf("Canon Digital V2\n"); return USB_INIT_DIG_V2; break; case PRODUCT_ID_NEXTDIGICAM1: case PRODUCT_ID_NEXTDIGICAM2: case PRODUCT_ID_NEXTDIGICAM3: case PRODUCT_ID_NEXTDIGICAM4: case PRODUCT_ID_NEXTDIGICAM5: case PRODUCT_ID_NEXTDIGICAM6: *camera_dev = dev; printf("Unsupported Canon digicam " "found, S10sh will try to use " "The s10, s20, s100, G1 " "protocol. Cross your " "fingers!\n"); return USB_INIT_NEW; break; default: if (opt_debug) printf("Unknown Canon product" " ID: %04X\n", dev->descriptor.idProduct); break; } break; default: if (opt_debug) printf("Unknown vendor ID: %04X\n", dev->descriptor.idVendor); } } } return USB_INIT_NOCAMERA; } /* The following two functions are based on gpio library */ int USB_write_control_msg(int value, char *buffer, int size) { int retval; retval = usb_control_msg(cameraudh, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_OUT, size > 1 ? 0x04 : 0x0c, value, 0, buffer, size, usb_timeout); if (opt_debug) { printf("WRITE CONTROL MSG, value %X, size %d: %s\n", value, size, retval == -1 ? "FAILED" : "OK"); if (retval != -1) dump_hex("DATA", buffer, size); } return retval; } int USB_read_control_msg(int value, char *buffer, int size) { int retval; retval = usb_control_msg(cameraudh, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, size > 1 ? 0x04 : 0x0c, value, 0, buffer, size, usb_timeout); if (opt_debug) { printf("READ CONTROL MSG, value %X, size %d: %s\n", value, size, retval == -1 ? "FAILED" : "OK"); if (retval != -1) dump_hex("DATA", buffer, size); } return retval; } int USB_read(void *buffer, int size) { int retval; retval = usb_bulk_read(cameraudh, input_ep, buffer, size, usb_timeout); if (opt_debug) { printf("USB READ: %s (%X)\n", retval == -1 ? "FAILED" : "OK", retval); if (retval != -1) dump_hex("DATA", buffer, size); } return retval; } int USB_write(void *buffer, int size) { int retval; retval = usb_bulk_write(cameraudh, output_ep, buffer, size, usb_timeout); if (opt_debug) { printf("USB WRITE: %s (%X)\n", retval == -1? "FAILED" : "OK", retval); if (retval != -1) dump_hex("DATA", buffer, size); } return retval; } int USB_cmd(unsigned char cmd1, unsigned char cmd2, unsigned int cmd3, unsigned int serial, unsigned char *payload, int size) { unsigned char buffer[4096]; unsigned int aux; aux = size+0x10; memset(buffer, 0, 4096); *(unsigned int*)buffer = byteswap32(aux); *(unsigned int*)(buffer+4) = byteswap32(cmd3); buffer[0x40] = 0x02; buffer[0x44] = cmd1; buffer[0x47] = cmd2; *(unsigned int*)(buffer+0x48) = byteswap32(aux); *(unsigned int*)(buffer+0x4c) = byteswap32(serial); if (payload != NULL) memcpy(buffer+0x50, payload, size); return USB_write_control_msg(0x10, buffer, 0x50+size); } int USB_initial_sync(void) { struct usb_device *camera_dev; int retval; unsigned char buffer[4096]; usb_timeout = 500; retval = USB_camera_init(&camera_dev); if (retval == USB_INIT_NOCAMERA) { printf("Camera not found, please press the shot button and\n" "check that the camera is in PC mode, then retry\n"); exit(1); } else if (retval == USB_INIT_FAILED) { printf("Fatal error initializing USB\n"); exit(1); } cameraudh = usb_open(camera_dev); if (!cameraudh) { printf("usb_open() error, can't open the camera\n"); exit(1); } retval = usb_set_configuration(cameraudh, configuration); if (retval == USB_ERROR) { printf("usb_set_configuration() error\n"); exit(1); } retval = usb_claim_interface(cameraudh, interface); if (retval == USB_ERROR) { printf("usb_claim_interface() error\n"); exit(1); } retval = usb_set_altinterface(cameraudh, alternate); if (retval == USB_ERROR) { printf("usb_set_altinterface() error\n"); exit(1); } if (opt_debug) printf("USB: Camera successful open\n"); while (USB_read_control_msg(0x55, buffer, 1) == -1); USB_read_control_msg(0x1, buffer, 0x58); USB_write_control_msg(0x11, buffer+0x48, 0x10); USB_read(buffer, 0x44); usb_timeout = 3000; return 0; } char *USB_get_id(void) { int retval; static char buffer[0x50+0x4c]; USB_cmd(0x01, 0x12, 0x201, 0x01, NULL, 0); retval = USB_read(buffer, 0x50+0x4c); if (retval == -1) return NULL; firmware[1] = firmware[3] = firmware[5] = '.'; firmware[0] = buffer[0x5b]+'0'; firmware[2] = buffer[0x5a]+'0'; firmware[4] = buffer[0x59]+'0'; firmware[6] = buffer[0x58]+'0'; firmware[7] = '\0'; return buffer+0x5c; } char *USB_get_disk(void) { int retval; static char buffer[4096]; USB_cmd(0x0a, 0x11, 0x202, 0x01, NULL, 0); USB_read(buffer, 0x40); memcpy(&retval, buffer+6, 4); USB_read(buffer, retval); return buffer; } #define BULK_TR_SIZE 0x1000 /* PAGE_SIZE */ unsigned char *USB_get_data(char *pathname, int reqtype, int *retlen) { unsigned char buffer[4096*2]; unsigned char *image; int aux = BULK_TR_SIZE; int size; int totalsize; int n_read = 0; memset(buffer, 0, 4); buffer[0] = reqtype; /* select image or thumbnail */ *(unsigned int*)(buffer+4) = byteswap32(aux); memcpy(buffer+8, pathname, strlen(pathname)+1); USB_cmd(0x01, 0x11, 0x202, 0x01, buffer, strlen(pathname)+9); USB_read(buffer, 0x40); totalsize = byteswap32(*(unsigned int*)(buffer+6)); if (totalsize == 0) return NULL; *retlen = totalsize; image = malloc(totalsize); if (!image) { perror("malloc"); exit(1); } printf("Getting %s, %d bytes\n", pathname, totalsize); progressbar(PROGRESS_RESET, 0, 0); while(1) { size = (totalsize > BULK_TR_SIZE) ? BULK_TR_SIZE : totalsize; USB_read(image+n_read, size); totalsize -= size; n_read += size; progressbar(PROGRESS_PRINT, *retlen, n_read); if (totalsize == 0) break; } return image; } time_t USB_get_date(void) { time_t curtime; unsigned char buffer[1024]; USB_cmd(0x03, 0x12, 0x201, 0x01, NULL, 0); USB_read(buffer, 0x60); curtime = byteswap32(*(time_t*)(buffer+0x54)); return curtime; } int USB_get_disk_info(char *disk, int *size, int *free) { unsigned char buffer[1024]; char diskstr[] = "X:\\"; diskstr[0] = disk[0]; USB_cmd(0x09, 0x11, 0x201, 0x01, diskstr, 4); USB_read(buffer, 0x5c); if (buffer[0x50] != 0) return -1; *size = byteswap32(*(unsigned int*)(buffer+0x54)); *free = byteswap32(*(unsigned int*)(buffer+0x58)); return 0; } int USB_get_power_status(int *good, int *ac) { unsigned char buffer[1024]; USB_cmd(0x0a, 0x12, 0x201, 0x01, NULL, 0); USB_read(buffer, 0x58); if (*(buffer+0x54) == 0x06) *good = 1; else *good = 0; if (*(buffer+0x57) == 0x10) *ac = 1; else *ac = 0; return 0; } int USB_mkdir(char *pathname) { unsigned char buffer[1024]; unsigned char arg[1024]; if (pathname[1] != ':') { snprintf(arg, 1024, "%s\\%s", lastpath, pathname); pathname = arg; } USB_cmd(0x5, 0x11, 0x201, 0x01, pathname, strlen(pathname)+1); USB_read(buffer, 0x54); if (buffer[0x50] == 0) return 0; else return -1; } int USB_rmdir(char *pathname) { unsigned char buffer[1024]; unsigned char arg[1024]; if (pathname[1] != ':') { snprintf(arg, 1024, "%s\\%s", lastpath, pathname); pathname = arg; } USB_cmd(0x6, 0x11, 0x201, 0x01, pathname, strlen(pathname)+1); USB_read(buffer, 0x54); if (buffer[0x50] == 0) return 0; else return -1; } int USB_delete(char *pathname) { unsigned char buffer[1024]; memcpy(buffer, lastpath, strlen(lastpath)+1); memcpy(buffer+strlen(lastpath)+1, pathname, strlen(pathname)+1); buffer[strlen(lastpath)] = '\\'; USB_cmd(0x0d, 0x11, 0x201, 0x01, buffer, strlen(lastpath)+1+ strlen(pathname)+1); USB_read(buffer, 0x54); if (buffer[0x50] == 0x86) return 0; else return -1; } int USB_set_file_attrib(char *pathname, unsigned char newattrib) { unsigned char buffer[1024]; buffer[0] = newattrib; buffer[1] = buffer[2] = buffer[3] = 0x00; memcpy(buffer+4, lastpath, strlen(lastpath)+1); buffer[4+strlen(lastpath)] = '\\'; memcpy(buffer+4+strlen(lastpath)+1, pathname, strlen(pathname)+1); USB_cmd(0x0e, 0x11, 0x201, 0x01, buffer, 4+strlen(lastpath)+1+ strlen(pathname)+1); USB_read(buffer, 0x54); if (buffer[0x50] == 0x86) return 0; else return -1; } int USB_upload(char *source, char *target) { struct stat buf; unsigned char buffer[4096*2]; char read_buffer[0x1400]; unsigned int serial, datalen, offset; unsigned int len1, lenaux, aux; unsigned short saux; int fd, progress_bar = 0; char arg[1024]; if (target == NULL) { char *p; p = strrchr(source, '/'); if (p != NULL) target = p++; else target = source; p = strchr(target, '.'); if (p != NULL && strchr(p+1, '.') != NULL) { printf("sorry, only one dot allowed in target filename\n"); return -1; } } if (strlen(target) <= 2 || target[1] != ':') { snprintf(arg, 1024, "%s\\%s", lastpath, target); target = arg; } serial = 0x12345678; offset = 0; fd = open(source, O_RDONLY); if (fd == -1) { perror("open"); return -1; } if (fstat(fd, &buf) == -1) { perror("stat"); printf("WARING: s10sh will not show the progress bar\n\n"); } else { progress_bar = 1; progressbar(PROGRESS_RESET, 0, 0); } while(1) { datalen = read(fd, read_buffer, 0x300); if (datalen == 0) { break; } else if (datalen == -1) { perror("read"); return -1; } len1 = 0x1c+strlen(target)+1+datalen; memset(buffer, 0, 4); buffer[4] = 0x03; buffer[5] = 0x02; lenaux = len1+0x40; memcpy(buffer+6, &lenaux, 4); memset(buffer+10, 0, 0x36); USB_write_control_msg(0x10, buffer, 0x40); USB_read(buffer, 0x40); memcpy(buffer, &len1, 4); aux = 0x0403; memcpy(buffer+4, &aux, 4); memset(buffer+8, 0, 0x38); aux = 0x02; memcpy(buffer+0x40, &aux, 4); saux = 0x03; memcpy(buffer+0x44, &saux, 2); buffer[0x46] = 0x00; buffer[0x47] = 0x11; memcpy(buffer+0x48, &len1, 4); memcpy(buffer+0x4c, &serial, 4); aux = 0x02; memcpy(buffer+0x50, &aux, 4); memcpy(buffer+0x54, &offset, 4); memcpy(buffer+0x58, &datalen, 4); memcpy(buffer+0x5c, target, strlen(target)+1); memcpy(buffer+0x5c+strlen(target)+1, read_buffer, datalen); USB_write(buffer, len1+0x40); USB_read(buffer, 0x5c); offset += datalen; progressbar(PROGRESS_PRINT, buf.st_size, offset); } close(fd); printf("\n"); return 0; } void USB_close(void) { int retval; retval = usb_release_interface(cameraudh, interface); if (retval == USB_ERROR) { printf("usb_claim_interface() error\n"); exit(1); } usb_close(cameraudh); } #endif /* HAVE_USB_SUPPORT */