diff --git a/README.md b/README.md index 6142aad..47b87b7 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC) ## TODO - [ ] A name +- [ ] A (VID and) PID, and maybe better subclass & protocol IDs for the vnd cfg itf - [x] CMSIS-DAP JTAG implementation - [x] Flashrom/SPI support using Serprog - Parallel ROM flashing support, too, by having the device switch into a @@ -254,7 +255,7 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC) it'll be used for other stuff anyway, etc.). Means a custom Linux driver but oh well, I2C-Tiny-USB needs patching either way. - [ ] 1-wire using ↑ -- [ ] A proper interface for sending commands etc. instead of shoehorning it +- [x] A proper interface for sending commands etc. instead of shoehorning it into Serprog. - Can probably be included in the "Better USB interface stuff". - [ ] JTAG pinout detector diff --git a/host/modules/dmj.c b/host/modules/dmj.c index 4e144ca..c20f01c 100644 --- a/host/modules/dmj.c +++ b/host/modules/dmj.c @@ -287,10 +287,14 @@ static int dmj_check_hw(struct dmj_dev *dmj) ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_VERSION, DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, &protover, &len); - if (ret < 0) { /* TODO: positive error codes from respstat */ + if (ret < 0) { dev_err(dev, "USB fail: %d\n", ret); return ret; } + if (ret) { + dev_err(dev, "USB protocol fail: %s (%d)\n", dmj_get_protoerr(ret), ret); + return -EIO; + } if (len < sizeof(protover)) { dev_err(dev, "USB fail remoteio: %d\n", len); return -EREMOTEIO; @@ -321,7 +325,11 @@ static int dmj_print_info(struct dmj_dev *dmj) len = sizeof(strinfo)-1; ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_INFOSTR, DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, strinfo, &len); - if (ret < 0) return ret; /* TODO: positive error codes from respstat */ + if (ret < 0) return ret; + if (ret) { + dev_err(dev, "USB protocol fail: %s (%d)\n", dmj_get_protoerr(ret), ret); + return -EIO; + } if (len >= sizeof(strinfo)) return -EMSGSIZE; strinfo[len] = 0; /*strinfo[64] = 0;*/ dev_info(dev, HARDWARE_NAME " '%s'\n", strinfo); @@ -418,32 +426,35 @@ static const struct mfd_cell dmj_mfd_i2c[] = { static int dmj_probe(struct usb_interface *itf, const struct usb_device_id *usb_id) { struct usb_host_interface *hostitf = itf->cur_altsetting; - struct usb_endpoint_descriptor *epin, *epout; + struct usb_endpoint_descriptor *epin = NULL, *epout = NULL, *curep; struct device *dev = &itf->dev; struct dmj_dev *dmj; - int ret; + int ret, i; - /*dev_dbg(dev, "dmj probe itfn=%d nendp=%d\n", - hostitf->desc.bInterfaceNumber, hostitf->desc.bNumEndpoints);*/ - - if (hostitf->desc.bInterfaceNumber != 0 || hostitf->desc.bNumEndpoints < 2) + if (hostitf->desc.bNumEndpoints < 2) return -ENODEV; - /* TODO: query endpoints in a better way */ - epout = &hostitf->endpoint[DMJ_VND_CFG_EP_OUT].desc; - epin = &hostitf->endpoint[DMJ_VND_CFG_EP_IN].desc; + for (i = 0; i < hostitf->desc.bNumEndpoints; ++i) { + curep = &hostitf->endpoint[i].desc; - /*dev_dbg(dev, "epout addr=0x%02x, epin addr=0x%02x\n", - epout->bEndpointAddress, epin->bEndpointAddress);*/ + if (!epin && usb_endpoint_is_bulk_in (curep)) epin = curep; + if (!epout && usb_endpoint_is_bulk_out(curep)) epout = curep; - if (!usb_endpoint_is_bulk_out(epout)) { dev_warn(dev, "aaa1\n"); return -ENODEV; } - if (!usb_endpoint_is_bulk_in(epin)) { dev_warn(dev, "aaa1\n"); return -ENODEV; } + if (epin && epout) break; + } + + if (!epin) { + dev_warn(dev, "found suitable device but no ep in\n"); + return -ENODEV; + } + if (!epout) { + dev_warn(dev, "found suitable device but no ep out\n"); + return -ENODEV; + } dmj = kzalloc(sizeof(*dmj), GFP_KERNEL); if (!dmj) return -ENOMEM; - /*dev_dbg(dev, "hi there!\n");*/ - dmj->ep_out = epout->bEndpointAddress; dmj->ep_in = epin->bEndpointAddress; dmj->usb_dev = usb_get_dev(interface_to_usbdev(itf)); @@ -525,7 +536,7 @@ static int dmj_resume(struct usb_interface *itf) } static const struct usb_device_id dmj_table[] = { - { USB_DEVICE(0xcafe, 0x1312) }, + { USB_DEVICE_AND_INTERFACE_INFO(0xcafe, 0x1312, USB_CLASS_VENDOR_SPEC, 42, 69) }, { } }; MODULE_DEVICE_TABLE(usb, dmj_table); diff --git a/src/m_default/_default.c b/src/m_default/_default.c index f29ea2d..166ab84 100644 --- a/src/m_default/_default.c +++ b/src/m_default/_default.c @@ -164,7 +164,6 @@ static void handle_cmd_cb(uint8_t cmd) { #define TUD_I2CTINYUSB_DESCRIPTOR(_itfnum, _stridx) \ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, 0, 0, 0, _stridx \ - enum { STRID_LANGID = 0, STRID_MANUFACTURER, @@ -264,8 +263,8 @@ static const uint8_t desc_configuration[] = { TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), #if CFG_TUD_VENDOR > 0 - TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT, - EPNUM_VND_CFG_IN, CFG_TUD_VENDOR_RX_BUFSIZE), + TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT, + EPNUM_VND_CFG_IN, CFG_TUD_VENDOR_RX_BUFSIZE, VND_CFG_SUBCLASS, VND_CFG_PROTOCOL), #endif #if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) diff --git a/src/vnd_cfg.h b/src/vnd_cfg.h index f139ab9..57fa591 100644 --- a/src/vnd_cfg.h +++ b/src/vnd_cfg.h @@ -5,8 +5,18 @@ #include -/* the configuration vendor interface must always be the first vendor itf, and - * have endpoint number 1. */ +/* the configuration vendor interface has a specific subclass and protocol + * number that can be useful for identification */ +#define VND_CFG_SUBCLASS 42 +#define VND_CFG_PROTOCOL 69 +#define TUD_VENDOR_DESCRIPTOR_EX(_itfnum, _stridx, _epout, _epin, _epsize, _subclass, _protocol) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, _subclass, _protocol, _stridx,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0 + #define VND_CFG_PROTO_VER 0x0010