libptouch を複数ソースに分割し src/lib に配置
- core / usb / print / status / png と libptouch_internal.h に分割 - 旧単一ファイル src/libptouch.c を削除 - CMake のソース一覧と include パスを更新 - README・libptouch.h の参照パスを追随 Made-with: Cursor
This commit is contained in:
196
src/lib/libptouch_usb.c
Normal file
196
src/lib/libptouch_usb.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* libptouch — USB (libusb): open/close, bulk transfers
|
||||
*
|
||||
* Author: knb
|
||||
* Email: knb@artif.org
|
||||
*/
|
||||
|
||||
#include "libptouch_internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* バルク IN/OUT を両方持つインタフェースを探して claim する。
|
||||
* USB Printer クラス (bInterfaceClass==7) を優先する。
|
||||
*/
|
||||
static int claim_interface_with_bulk(libusb_device_handle *h, int *out_iface,
|
||||
uint8_t *out_ep, uint8_t *in_ep)
|
||||
{
|
||||
libusb_device *dev = libusb_get_device(h);
|
||||
struct libusb_config_descriptor *cfg = NULL;
|
||||
int r = libusb_get_active_config_descriptor(dev, &cfg);
|
||||
if (r != 0 || !cfg)
|
||||
return -1;
|
||||
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (int i = 0; i < cfg->bNumInterfaces; i++) {
|
||||
const struct libusb_interface_descriptor *alt =
|
||||
&cfg->interface[i].altsetting[0];
|
||||
if (pass == 0 &&
|
||||
alt->bInterfaceClass != LIBUSB_CLASS_PRINTER)
|
||||
continue;
|
||||
|
||||
uint8_t ep_out = 0, ep_in = 0;
|
||||
for (uint8_t k = 0; k < alt->bNumEndpoints; k++) {
|
||||
const struct libusb_endpoint_descriptor *ep =
|
||||
&alt->endpoint[k];
|
||||
if ((ep->bmAttributes &
|
||||
LIBUSB_TRANSFER_TYPE_MASK) ==
|
||||
LIBUSB_TRANSFER_TYPE_BULK) {
|
||||
if (ep->bEndpointAddress &
|
||||
LIBUSB_ENDPOINT_IN)
|
||||
ep_in = ep->bEndpointAddress;
|
||||
else
|
||||
ep_out = ep->bEndpointAddress;
|
||||
}
|
||||
}
|
||||
if (!ep_out || !ep_in)
|
||||
continue;
|
||||
r = libusb_claim_interface(h, i);
|
||||
if (r == 0) {
|
||||
*out_iface = i;
|
||||
*out_ep = ep_out;
|
||||
*in_ep = ep_in;
|
||||
libusb_free_config_descriptor(cfg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
libusb_free_config_descriptor(cfg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libptouch_err_t libptouch_open_usb_vid_pid(libptouch_ctx *ctx, uint16_t vid,
|
||||
uint16_t pid)
|
||||
{
|
||||
if (!ctx) {
|
||||
return LIBPTOUCH_ERR_ARG;
|
||||
}
|
||||
if (ctx->usb_handle) {
|
||||
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "USB already open");
|
||||
return LIBPTOUCH_ERR_ARG;
|
||||
}
|
||||
|
||||
int r = libusb_init(&ctx->usb_ctx);
|
||||
if (r != LIBUSB_SUCCESS) {
|
||||
ptouch_set_error_usb(ctx, r, "libusb_init");
|
||||
ctx->usb_ctx = NULL;
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
|
||||
libusb_device_handle *h =
|
||||
libusb_open_device_with_vid_pid(ctx->usb_ctx, vid, pid);
|
||||
if (!h) {
|
||||
libusb_exit(ctx->usb_ctx);
|
||||
ctx->usb_ctx = NULL;
|
||||
char buf[160];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"no USB device 0x%04x:0x%04x (check cable, power, udev)",
|
||||
(unsigned)vid, (unsigned)pid);
|
||||
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOT_FOUND, buf);
|
||||
return LIBPTOUCH_ERR_NOT_FOUND;
|
||||
}
|
||||
ctx->usb_handle = h;
|
||||
|
||||
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106)
|
||||
(void)libusb_set_auto_detach_kernel_driver(h, 1);
|
||||
#endif
|
||||
|
||||
if (claim_interface_with_bulk(h, &ctx->claimed_interface,
|
||||
&ctx->bulk_out_ep, &ctx->bulk_in_ep) != 0) {
|
||||
ptouch_set_error(ctx, LIBPTOUCH_ERR_USB,
|
||||
"no bulk IN/OUT interface (permissions or driver?)");
|
||||
libusb_close(h);
|
||||
ctx->usb_handle = NULL;
|
||||
libusb_exit(ctx->usb_ctx);
|
||||
ctx->usb_ctx = NULL;
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
|
||||
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||
|
||||
ctx->usb_open = 1;
|
||||
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||
return LIBPTOUCH_OK;
|
||||
}
|
||||
|
||||
libptouch_err_t libptouch_open_usb(libptouch_ctx *ctx)
|
||||
{
|
||||
return libptouch_open_usb_vid_pid(ctx, LIBPTOUCH_USB_VID_BROTHER,
|
||||
LIBPTOUCH_USB_PID_PTP900W);
|
||||
}
|
||||
|
||||
void libptouch_close(libptouch_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
if (ctx->usb_handle) {
|
||||
if (ctx->claimed_interface >= 0) {
|
||||
(void)libusb_release_interface(ctx->usb_handle,
|
||||
ctx->claimed_interface);
|
||||
ctx->claimed_interface = -1;
|
||||
}
|
||||
libusb_close(ctx->usb_handle);
|
||||
ctx->usb_handle = NULL;
|
||||
}
|
||||
if (ctx->usb_ctx) {
|
||||
libusb_exit(ctx->usb_ctx);
|
||||
ctx->usb_ctx = NULL;
|
||||
}
|
||||
ctx->bulk_out_ep = 0;
|
||||
ctx->bulk_in_ep = 0;
|
||||
ctx->usb_open = 0;
|
||||
}
|
||||
|
||||
int ptouch_bulk_out(libusb_device_handle *h, uint8_t ep, const uint8_t *data,
|
||||
int len, unsigned int timeout_ms)
|
||||
{
|
||||
int tr = 0;
|
||||
int r = libusb_bulk_transfer(h, ep, (unsigned char *)data, len, &tr,
|
||||
(int)timeout_ms);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (tr != len)
|
||||
return LIBUSB_ERROR_IO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ptouch_bulk_in_exact(libusb_device_handle *h, uint8_t ep, uint8_t *buf,
|
||||
int len, unsigned int timeout_ms)
|
||||
{
|
||||
int got = 0;
|
||||
while (got < len) {
|
||||
int tr = 0;
|
||||
int r = libusb_bulk_transfer(h, ep, buf + got, len - got, &tr,
|
||||
(int)timeout_ms);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (tr == 0)
|
||||
return LIBUSB_ERROR_IO;
|
||||
got += tr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
libptouch_err_t ptouch_bulk_send_job(libptouch_ctx *ctx, const uint8_t *buf,
|
||||
size_t len, const char *what)
|
||||
{
|
||||
int tr = 0;
|
||||
int r = libusb_bulk_transfer(ctx->usb_handle, ctx->bulk_out_ep,
|
||||
(unsigned char *)buf, (int)len, &tr,
|
||||
120000);
|
||||
if (r != 0) {
|
||||
ptouch_set_error_usb(ctx, r, what);
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
if ((size_t)tr != len) {
|
||||
char msg[96];
|
||||
snprintf(msg, sizeof(msg), "%s: short write %d/%zu", what, tr,
|
||||
len);
|
||||
ptouch_set_error(ctx, LIBPTOUCH_ERR_USB, msg);
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
return LIBPTOUCH_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user