From patchwork Thu Jul 21 09:56:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaac Lozano <109lozanoi@gmail.com> X-Patchwork-Id: 9241347 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 21A8D602F0 for ; Thu, 21 Jul 2016 10:01:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0F88D268AE for ; Thu, 21 Jul 2016 10:01:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 03878279E0; Thu, 21 Jul 2016 10:01:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.0 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,FROM_STARTS_WITH_NUMS,RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 55EF0268AE for ; Thu, 21 Jul 2016 10:01:02 +0000 (UTC) Received: from localhost ([::1]:39506 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bQAmr-00007k-Lq for patchwork-qemu-devel@patchwork.kernel.org; Thu, 21 Jul 2016 06:01:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57782) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from <109lozanoi@gmail.com>) id 1bQAj8-0005du-5U for qemu-devel@nongnu.org; Thu, 21 Jul 2016 05:57:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <109lozanoi@gmail.com>) id 1bQAj5-0003eP-Nd for qemu-devel@nongnu.org; Thu, 21 Jul 2016 05:57:09 -0400 Received: from mail-pf0-x241.google.com ([2607:f8b0:400e:c00::241]:35606) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from <109lozanoi@gmail.com>) id 1bQAj5-0003eE-Cl for qemu-devel@nongnu.org; Thu, 21 Jul 2016 05:57:07 -0400 Received: by mail-pf0-x241.google.com with SMTP id h186so5193447pfg.2 for ; Thu, 21 Jul 2016 02:57:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=UxjO9myJWHTSh4TWwl74WzcYkfSKBPwsJtI8mGDzJr8=; b=Bleb2jh3/Gw5y2y9BhZvM032cX7e/6qGJ0FucpECYogVfklUSY2BG2bkgXjX8G4E+3 Qs8pQceKJMql4fgJmVsiKtQpcb57fTdceKr0+87PuwUEjHUlYnegIAwsg1mZXqBRZwiq uuYuXUnLGc1YnL9sLFij+Zzvpkr9Amnq2vz0YiXYc+SxCbgSuOM38YYGlIYBfDllJx8F YSY2Sq7n3Q16n6fOUGtL5CoEEjSxiAWxXeNLHuKmLRYwanIxEsHvlJhQABgswOPGmtcd KiQw40owxQb0H7FqKjRqB2lYfewG6EqtOyzRcyslcXvjhWroh6VayIjtIi6oJYOITdQF MDJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=UxjO9myJWHTSh4TWwl74WzcYkfSKBPwsJtI8mGDzJr8=; b=bRbTV7hoGDGd3Zx3dGz9rrQ3dt5S2bi5aQCCgu0dHWLPry75pa8d+CBh/qdfgmhNce 53OJmr7oYltNs/OsMJakwegQ+hYsgEYkam1XUyRVJXtRsgMzkT5ve42cAx1cmUdx8/qs l2u/bsRv2JoTnM7AYJIMYkPu+u6rnGE1h4MNBAGDorE7WtIcx3hSyCfKb/H91GICnAuU Flef/em+iHzUJx7dmockjeZkzd6xbjJxM2jeK0PFprGD3NLLUwfURIm4YQ/nMHVCITve zhdsmPJhY5fGrGOZFV28P0rQlN6zg042wOVgEs7qrHsGjqDkofYinf0kfxA+x9ruB3EN 4SDA== X-Gm-Message-State: ALyK8tKfgp+paURoerUqejfpxLwg0Unu+EANDryEH9mqTS29P1jjq3kSvJin60dZ9xWOvg== X-Received: by 10.98.85.5 with SMTP id j5mr71093985pfb.81.1469095026434; Thu, 21 Jul 2016 02:57:06 -0700 (PDT) Received: from localhost.localdomain (23-114-218-5.lightspeed.frokca.sbcglobal.net. [23.114.218.5]) by smtp.gmail.com with ESMTPSA id d3sm10831355pfk.37.2016.07.21.02.57.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Jul 2016 02:57:05 -0700 (PDT) From: Isaac Lozano <109lozanoi@gmail.com> To: qemu-devel@nongnu.org Date: Thu, 21 Jul 2016 02:56:34 -0700 Message-Id: <1b3ed86694a85165388a5efcd351cfaa19b59ad4.1468876280.git.109lozanoi@gmail.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c00::241 Subject: [Qemu-devel] [PATCH v2 2/2] usb-mtp: added object properties X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Isaac Lozano <109lozanoi@gmail.com>, bsd@redhat.com, kraxel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Windows uses object properties to determine the size of a file, so to add object properties, we must also add a minimum set of new commands and object properties. Most object properties are data that we already have, except for the unique persistant object identifier. Windows doesn't use this property, it seems, so we can cheat a bit and just use the object handle for it. Signed-off-by: Isaac Lozano <109lozanoi@gmail.com> --- hw/usb/dev-mtp.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 5 deletions(-) diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 6f6a270..fa0c81e 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -48,6 +48,9 @@ enum mtp_code { CMD_GET_OBJECT_INFO = 0x1008, CMD_GET_OBJECT = 0x1009, CMD_GET_PARTIAL_OBJECT = 0x101b, + CMD_GET_OBJECT_PROPS_SUPPORTED = 0x9801, + CMD_GET_OBJECT_PROP_DESC = 0x9802, + CMD_GET_OBJECT_PROP_VALUE = 0x9803, /* response codes */ RES_OK = 0x2001, @@ -59,10 +62,12 @@ enum mtp_code { RES_INCOMPLETE_TRANSFER = 0x2007, RES_INVALID_STORAGE_ID = 0x2008, RES_INVALID_OBJECT_HANDLE = 0x2009, + RES_INVALID_OBJECT_FORMAT_CODE = 0x200b, RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014, RES_INVALID_PARENT_OBJECT = 0x201a, RES_INVALID_PARAMETER = 0x201d, RES_SESSION_ALREADY_OPEN = 0x201e, + RES_INVALID_OBJECT_PROP_CODE = 0xA801, /* format codes */ FMT_UNDEFINED_OBJECT = 0x3000, @@ -72,6 +77,22 @@ enum mtp_code { EVT_OBJ_ADDED = 0x4002, EVT_OBJ_REMOVED = 0x4003, EVT_OBJ_INFO_CHANGED = 0x4007, + + /* object properties */ + PROP_STORAGE_ID = 0xDC01, + PROP_OBJECT_FORMAT = 0xDC02, + PROP_OBJECT_COMPRESSED_SIZE = 0xDC04, + PROP_PARENT_OBJECT = 0xDC0B, + PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER = 0xDC41, + PROP_NAME = 0xDC44, +}; + +enum mtp_data_type { + DATA_TYPE_UINT16 = 0x0004, + DATA_TYPE_UINT32 = 0x0006, + DATA_TYPE_UINT64 = 0x0008, + DATA_TYPE_UINT128 = 0x000a, + DATA_TYPE_STRING = 0xffff, }; typedef struct { @@ -778,6 +799,9 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) CMD_GET_OBJECT_INFO, CMD_GET_OBJECT, CMD_GET_PARTIAL_OBJECT, + CMD_GET_OBJECT_PROPS_SUPPORTED, + CMD_GET_OBJECT_PROP_DESC, + CMD_GET_OBJECT_PROP_VALUE, }; static const uint16_t fmt[] = { FMT_UNDEFINED_OBJECT, @@ -886,8 +910,7 @@ static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c, if (o->stat.st_size > 0xFFFFFFFF) { usb_mtp_add_u32(d, 0xFFFFFFFF); - } - else { + } else { usb_mtp_add_u32(d, o->stat.st_size); } @@ -972,6 +995,122 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, return d; } +static MTPData *usb_mtp_get_object_props_supported(MTPState *s, MTPControl *c) +{ + static const uint16_t props[] = { + PROP_STORAGE_ID, + PROP_OBJECT_FORMAT, + PROP_OBJECT_COMPRESSED_SIZE, + PROP_PARENT_OBJECT, + PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER, + PROP_NAME, + }; + MTPData *d = usb_mtp_data_alloc(c); + usb_mtp_add_u16_array(d, ARRAY_SIZE(props), props); + + return d; +} + +static MTPData *usb_mtp_get_object_prop_desc(MTPState *s, MTPControl *c) +{ + MTPData *d = usb_mtp_data_alloc(c); + switch (c->argv[0]) { + case PROP_STORAGE_ID: + usb_mtp_add_u16(d, PROP_STORAGE_ID); + usb_mtp_add_u16(d, DATA_TYPE_UINT32); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + case PROP_OBJECT_FORMAT: + usb_mtp_add_u16(d, PROP_OBJECT_FORMAT); + usb_mtp_add_u16(d, DATA_TYPE_UINT16); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u16(d, 0x0000); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + case PROP_OBJECT_COMPRESSED_SIZE: + usb_mtp_add_u16(d, PROP_OBJECT_COMPRESSED_SIZE); + usb_mtp_add_u16(d, DATA_TYPE_UINT64); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u64(d, 0x0000000000000000); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + case PROP_PARENT_OBJECT: + usb_mtp_add_u16(d, PROP_PARENT_OBJECT); + usb_mtp_add_u16(d, DATA_TYPE_UINT32); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER: + usb_mtp_add_u16(d, PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER); + usb_mtp_add_u16(d, DATA_TYPE_UINT128); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u64(d, 0x0000000000000000); + usb_mtp_add_u64(d, 0x0000000000000000); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + case PROP_NAME: + usb_mtp_add_u16(d, PROP_NAME); + usb_mtp_add_u16(d, DATA_TYPE_STRING); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u8(d, 0x00); + usb_mtp_add_u32(d, 0x00000000); + usb_mtp_add_u8(d, 0x00); + break; + default: + usb_mtp_data_free(d); + return NULL; + } + + return d; +} + +static MTPData *usb_mtp_get_object_prop_value(MTPState *s, MTPControl *c, + MTPObject *o) +{ + MTPData *d = usb_mtp_data_alloc(c); + switch (c->argv[1]) { + case PROP_STORAGE_ID: + usb_mtp_add_u32(d, QEMU_STORAGE_ID); + break; + case PROP_OBJECT_FORMAT: + usb_mtp_add_u16(d, o->format); + break; + case PROP_OBJECT_COMPRESSED_SIZE: + usb_mtp_add_u64(d, o->stat.st_size); + break; + case PROP_PARENT_OBJECT: + if (o->parent == NULL) { + usb_mtp_add_u32(d, 0x00000000); + } else { + usb_mtp_add_u32(d, o->parent->handle); + } + break; + case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER: + /* Should be persistant between sessions, + * but using our objedt ID is "good enough" + * for now */ + usb_mtp_add_u64(d, 0x0000000000000000); + usb_mtp_add_u64(d, o->handle); + break; + case PROP_NAME: + usb_mtp_add_str(d, o->name); + break; + default: + usb_mtp_data_free(d); + return NULL; + } + + return d; +} + static void usb_mtp_command(MTPState *s, MTPControl *c) { MTPData *data_in = NULL; @@ -1119,6 +1258,43 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) nres = 1; res0 = data_in->length; break; + case CMD_GET_OBJECT_PROPS_SUPPORTED: + if (c->argv[0] != FMT_UNDEFINED_OBJECT && + c->argv[0] != FMT_ASSOCIATION) { + usb_mtp_queue_result(s, RES_INVALID_OBJECT_FORMAT_CODE, + c->trans, 0, 0, 0); + return; + } + data_in = usb_mtp_get_object_props_supported(s, c); + break; + case CMD_GET_OBJECT_PROP_DESC: + if (c->argv[1] != FMT_UNDEFINED_OBJECT && + c->argv[1] != FMT_ASSOCIATION) { + usb_mtp_queue_result(s, RES_INVALID_OBJECT_FORMAT_CODE, + c->trans, 0, 0, 0); + return; + } + data_in = usb_mtp_get_object_prop_desc(s, c); + if (data_in == NULL) { + usb_mtp_queue_result(s, RES_INVALID_OBJECT_PROP_CODE, + c->trans, 0, 0, 0); + return; + } + break; + case CMD_GET_OBJECT_PROP_VALUE: + o = usb_mtp_object_lookup(s, c->argv[0]); + if (o == NULL) { + usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE, + c->trans, 0, 0, 0); + return; + } + data_in = usb_mtp_get_object_prop_value(s, c, o); + if (data_in == NULL) { + usb_mtp_queue_result(s, RES_INVALID_OBJECT_PROP_CODE, + c->trans, 0, 0, 0); + return; + } + break; default: trace_usb_mtp_op_unknown(s->dev.addr, c->code); usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED, @@ -1204,9 +1380,9 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length); if (d->length + sizeof(container) > 0xFFFFFFFF) { container.length = cpu_to_le32(0xFFFFFFFF); - } - else { - container.length = cpu_to_le32(d->length + sizeof(container)); + } else { + container.length = cpu_to_le32(d->length + + sizeof(container)); } container.type = cpu_to_le16(TYPE_DATA); container.code = cpu_to_le16(d->code);