From b287cd3ed141a83095bf513bf6d979a3093d0c0c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Dec 2022 13:30:36 +0100 Subject: [PATCH] 4.14-stable patches added patches: udf-discard-preallocation-before-extending-file-with-a-hole.patch udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch udf-fix-extending-file-within-last-block.patch udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch usb-serial-option-add-quectel-em05-g-modem.patch --- queue-4.14/series | 7 + ...on-before-extending-file-with-a-hole.patch | 131 ++++++++++++++++++ ...tents-if-i_lenextents-matches-i_size.patch | 34 +++++ ...fix-extending-file-within-last-block.patch | 99 +++++++++++++ ...scarding-at-indirect-extent-boundary.patch | 96 +++++++++++++ ...ent-buffer-overflow-in-setup-handler.patch | 40 ++++++ ...-cp210x-add-kamstrup-rf-sniffer-pids.patch | 37 +++++ ...rial-option-add-quectel-em05-g-modem.patch | 104 ++++++++++++++ 8 files changed, 548 insertions(+) create mode 100644 queue-4.14/udf-discard-preallocation-before-extending-file-with-a-hole.patch create mode 100644 queue-4.14/udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch create mode 100644 queue-4.14/udf-fix-extending-file-within-last-block.patch create mode 100644 queue-4.14/udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch create mode 100644 queue-4.14/usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch create mode 100644 queue-4.14/usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch create mode 100644 queue-4.14/usb-serial-option-add-quectel-em05-g-modem.patch diff --git a/queue-4.14/series b/queue-4.14/series index c83ae0dff81..0b989e3215c 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -9,3 +9,10 @@ can-sja1000-fix-size-of-ocr_mode_mask-define.patch can-mcba_usb-fix-termination-command-argument.patch asoc-ops-correct-bounds-check-for-second-channel-on-sx-controls.patch perf-script-python-remove-explicit-shebang-from-tests-attr.c.patch +udf-discard-preallocation-before-extending-file-with-a-hole.patch +udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch +udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch +udf-fix-extending-file-within-last-block.patch +usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch +usb-serial-option-add-quectel-em05-g-modem.patch +usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch diff --git a/queue-4.14/udf-discard-preallocation-before-extending-file-with-a-hole.patch b/queue-4.14/udf-discard-preallocation-before-extending-file-with-a-hole.patch new file mode 100644 index 00000000000..ab7f245ae7c --- /dev/null +++ b/queue-4.14/udf-discard-preallocation-before-extending-file-with-a-hole.patch @@ -0,0 +1,131 @@ +From 16d0556568148bdcaa45d077cac9f8f7077cf70a Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 7 Dec 2022 18:17:34 +0100 +Subject: udf: Discard preallocation before extending file with a hole + +From: Jan Kara + +commit 16d0556568148bdcaa45d077cac9f8f7077cf70a upstream. + +When extending file with a hole, we tried to preserve existing +preallocation for the file. However that is not very useful and +complicates code because the previous extent may need to be rounded to +block boundary as well (which we forgot to do thus causing data +corruption for sequence like: + +xfs_io -f -c "pwrite 0x75e63 11008" -c "truncate 0x7b24b" \ + -c "truncate 0xabaa3" -c "pwrite 0xac70b 22954" \ + -c "pwrite 0x93a43 11358" -c "pwrite 0xb8e65 52211" file + +with 512-byte block size. Just discard preallocation before extending +file to simplify things and also fix this data corruption. + +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/inode.c | 46 ++++++++++++++++++---------------------------- + 1 file changed, 18 insertions(+), 28 deletions(-) + +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -434,6 +434,12 @@ static int udf_get_block(struct inode *i + iinfo->i_next_alloc_goal++; + } + ++ /* ++ * Block beyond EOF and prealloc extents? Just discard preallocation ++ * as it is not useful and complicates things. ++ */ ++ if (((loff_t)block) << inode->i_blkbits > iinfo->i_lenExtents) ++ udf_discard_prealloc(inode); + udf_clear_extent_cache(inode); + phys = inode_getblk(inode, block, &err, &new); + if (!phys) +@@ -483,8 +489,6 @@ static int udf_do_extend_file(struct ino + uint32_t add; + int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); + struct super_block *sb = inode->i_sb; +- struct kernel_lb_addr prealloc_loc = {}; +- int prealloc_len = 0; + struct udf_inode_info *iinfo; + int err; + +@@ -505,19 +509,6 @@ static int udf_do_extend_file(struct ino + ~(sb->s_blocksize - 1); + } + +- /* Last extent are just preallocated blocks? */ +- if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == +- EXT_NOT_RECORDED_ALLOCATED) { +- /* Save the extent so that we can reattach it to the end */ +- prealloc_loc = last_ext->extLocation; +- prealloc_len = last_ext->extLength; +- /* Mark the extent as a hole */ +- last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +- (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); +- last_ext->extLocation.logicalBlockNum = 0; +- last_ext->extLocation.partitionReferenceNum = 0; +- } +- + /* Can we merge with the previous extent? */ + if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == + EXT_NOT_RECORDED_NOT_ALLOCATED) { +@@ -545,7 +536,7 @@ static int udf_do_extend_file(struct ino + * more extents, we may need to enter possible following + * empty indirect extent. + */ +- if (new_block_bytes || prealloc_len) ++ if (new_block_bytes) + udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); + } + +@@ -579,17 +570,6 @@ static int udf_do_extend_file(struct ino + } + + out: +- /* Do we have some preallocated blocks saved? */ +- if (prealloc_len) { +- err = udf_add_aext(inode, last_pos, &prealloc_loc, +- prealloc_len, 1); +- if (err) +- return err; +- last_ext->extLocation = prealloc_loc; +- last_ext->extLength = prealloc_len; +- count++; +- } +- + /* last_pos should point to the last written extent... */ + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) + last_pos->offset -= sizeof(struct short_ad); +@@ -642,8 +622,17 @@ static int udf_extend_file(struct inode + else + BUG(); + ++ /* ++ * When creating hole in file, just don't bother with preserving ++ * preallocation. It likely won't be very useful anyway. ++ */ ++ udf_discard_prealloc(inode); ++ + etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); + within_final_block = (etype != -1); ++ /* We don't expect extents past EOF... */ ++ WARN_ON_ONCE(etype != -1 && ++ elen > ((loff_t)offset + 1) << inode->i_blkbits); + + if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || + (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { +@@ -772,10 +761,11 @@ static sector_t inode_getblk(struct inod + goto out_free; + } + +- /* Are we beyond EOF? */ ++ /* Are we beyond EOF and preallocated extent? */ + if (etype == -1) { + int ret; + loff_t hole_len; ++ + isBeyondEOF = true; + if (count) { + if (c) diff --git a/queue-4.14/udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch b/queue-4.14/udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch new file mode 100644 index 00000000000..552b7bf733f --- /dev/null +++ b/queue-4.14/udf-do-not-bother-looking-for-prealloc-extents-if-i_lenextents-matches-i_size.patch @@ -0,0 +1,34 @@ +From 6ad53f0f71c52871202a7bf096feb2c59db33fc5 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 7 Dec 2022 17:34:33 +0100 +Subject: udf: Do not bother looking for prealloc extents if i_lenExtents matches i_size + +From: Jan Kara + +commit 6ad53f0f71c52871202a7bf096feb2c59db33fc5 upstream. + +If rounded block-rounded i_lenExtents matches block rounded i_size, +there are no preallocation extents. Do not bother walking extent linked +list. + +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/truncate.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/udf/truncate.c ++++ b/fs/udf/truncate.c +@@ -127,9 +127,10 @@ void udf_discard_prealloc(struct inode * + uint64_t lbcount = 0; + int8_t etype = -1, netype; + struct udf_inode_info *iinfo = UDF_I(inode); ++ int bsize = 1 << inode->i_blkbits; + + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || +- inode->i_size == iinfo->i_lenExtents) ++ ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize)) + return; + + epos.block = iinfo->i_location; diff --git a/queue-4.14/udf-fix-extending-file-within-last-block.patch b/queue-4.14/udf-fix-extending-file-within-last-block.patch new file mode 100644 index 00000000000..398367d14ca --- /dev/null +++ b/queue-4.14/udf-fix-extending-file-within-last-block.patch @@ -0,0 +1,99 @@ +From 1f3868f06855c97a4954c99b36f3fc9eb8f60326 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 8 Dec 2022 13:03:30 +0100 +Subject: udf: Fix extending file within last block + +From: Jan Kara + +commit 1f3868f06855c97a4954c99b36f3fc9eb8f60326 upstream. + +When extending file within last block it can happen that the extent is +already rounded to the blocksize and thus contains the offset we want to +grow up to. In such case we would mistakenly expand the last extent and +make it one block longer than it should be, exposing unallocated block +in a file and causing data corruption. Fix the problem by properly +detecting this case and bailing out. + +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/inode.c | 32 +++++++++++++++++--------------- + 1 file changed, 17 insertions(+), 15 deletions(-) + +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -585,13 +585,17 @@ out: + static void udf_do_extend_final_block(struct inode *inode, + struct extent_position *last_pos, + struct kernel_long_ad *last_ext, +- uint32_t final_block_len) ++ uint32_t new_elen) + { +- struct super_block *sb = inode->i_sb; + uint32_t added_bytes; + +- added_bytes = final_block_len - +- (last_ext->extLength & (sb->s_blocksize - 1)); ++ /* ++ * Extent already large enough? It may be already rounded up to block ++ * size... ++ */ ++ if (new_elen <= (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) ++ return; ++ added_bytes = (last_ext->extLength & UDF_EXTENT_LENGTH_MASK) - new_elen; + last_ext->extLength += added_bytes; + UDF_I(inode)->i_lenExtents += added_bytes; + +@@ -608,12 +612,12 @@ static int udf_extend_file(struct inode + int8_t etype; + struct super_block *sb = inode->i_sb; + sector_t first_block = newsize >> sb->s_blocksize_bits, offset; +- unsigned long partial_final_block; ++ loff_t new_elen; + int adsize; + struct udf_inode_info *iinfo = UDF_I(inode); + struct kernel_long_ad extent; + int err = 0; +- int within_final_block; ++ bool within_last_ext; + + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) + adsize = sizeof(struct short_ad); +@@ -629,9 +633,9 @@ static int udf_extend_file(struct inode + udf_discard_prealloc(inode); + + etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); +- within_final_block = (etype != -1); ++ within_last_ext = (etype != -1); + /* We don't expect extents past EOF... */ +- WARN_ON_ONCE(etype != -1 && ++ WARN_ON_ONCE(within_last_ext && + elen > ((loff_t)offset + 1) << inode->i_blkbits); + + if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || +@@ -648,19 +652,17 @@ static int udf_extend_file(struct inode + extent.extLength |= etype << 30; + } + +- partial_final_block = newsize & (sb->s_blocksize - 1); ++ new_elen = ((loff_t)offset << inode->i_blkbits) | ++ (newsize & (sb->s_blocksize - 1)); + + /* File has extent covering the new size (could happen when extending + * inside a block)? + */ +- if (within_final_block) { ++ if (within_last_ext) { + /* Extending file within the last file block */ +- udf_do_extend_final_block(inode, &epos, &extent, +- partial_final_block); ++ udf_do_extend_final_block(inode, &epos, &extent, new_elen); + } else { +- loff_t add = ((loff_t)offset << sb->s_blocksize_bits) | +- partial_final_block; +- err = udf_do_extend_file(inode, &epos, &extent, add); ++ err = udf_do_extend_file(inode, &epos, &extent, new_elen); + } + + if (err < 0) diff --git a/queue-4.14/udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch b/queue-4.14/udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch new file mode 100644 index 00000000000..d87d45cb622 --- /dev/null +++ b/queue-4.14/udf-fix-preallocation-discarding-at-indirect-extent-boundary.patch @@ -0,0 +1,96 @@ +From cfe4c1b25dd6d2f056afc00b7c98bcb3dd0b1fc3 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 7 Dec 2022 17:25:10 +0100 +Subject: udf: Fix preallocation discarding at indirect extent boundary + +From: Jan Kara + +commit cfe4c1b25dd6d2f056afc00b7c98bcb3dd0b1fc3 upstream. + +When preallocation extent is the first one in the extent block, the +code would corrupt extent tree header instead. Fix the problem and use +udf_delete_aext() for deleting extent to avoid some code duplication. + +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/truncate.c | 45 +++++++++++++-------------------------------- + 1 file changed, 13 insertions(+), 32 deletions(-) + +--- a/fs/udf/truncate.c ++++ b/fs/udf/truncate.c +@@ -120,60 +120,41 @@ void udf_truncate_tail_extent(struct ino + + void udf_discard_prealloc(struct inode *inode) + { +- struct extent_position epos = { NULL, 0, {0, 0} }; ++ struct extent_position epos = {}; ++ struct extent_position prev_epos = {}; + struct kernel_lb_addr eloc; + uint32_t elen; + uint64_t lbcount = 0; + int8_t etype = -1, netype; +- int adsize; + struct udf_inode_info *iinfo = UDF_I(inode); + + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || + inode->i_size == iinfo->i_lenExtents) + return; + +- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) +- adsize = sizeof(struct short_ad); +- else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) +- adsize = sizeof(struct long_ad); +- else +- adsize = 0; +- + epos.block = iinfo->i_location; + + /* Find the last extent in the file */ +- while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { +- etype = netype; ++ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) { ++ brelse(prev_epos.bh); ++ prev_epos = epos; ++ if (prev_epos.bh) ++ get_bh(prev_epos.bh); ++ ++ etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); + lbcount += elen; + } + if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { +- epos.offset -= adsize; + lbcount -= elen; +- extent_trunc(inode, &epos, &eloc, etype, elen, 0); +- if (!epos.bh) { +- iinfo->i_lenAlloc = +- epos.offset - +- udf_file_entry_alloc_offset(inode); +- mark_inode_dirty(inode); +- } else { +- struct allocExtDesc *aed = +- (struct allocExtDesc *)(epos.bh->b_data); +- aed->lengthAllocDescs = +- cpu_to_le32(epos.offset - +- sizeof(struct allocExtDesc)); +- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || +- UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) +- udf_update_tag(epos.bh->b_data, epos.offset); +- else +- udf_update_tag(epos.bh->b_data, +- sizeof(struct allocExtDesc)); +- mark_buffer_dirty_inode(epos.bh, inode); +- } ++ udf_delete_aext(inode, prev_epos); ++ udf_free_blocks(inode->i_sb, inode, &eloc, 0, ++ DIV_ROUND_UP(elen, 1 << inode->i_blkbits)); + } + /* This inode entry is in-memory only and thus we don't have to mark + * the inode dirty */ + iinfo->i_lenExtents = lbcount; + brelse(epos.bh); ++ brelse(prev_epos.bh); + } + + static void udf_update_alloc_ext_desc(struct inode *inode, diff --git a/queue-4.14/usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch b/queue-4.14/usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch new file mode 100644 index 00000000000..247bc40f543 --- /dev/null +++ b/queue-4.14/usb-gadget-uvc-prevent-buffer-overflow-in-setup-handler.patch @@ -0,0 +1,40 @@ +From 4c92670b16727365699fe4b19ed32013bab2c107 Mon Sep 17 00:00:00 2001 +From: Szymon Heidrich +Date: Tue, 6 Dec 2022 15:13:01 +0100 +Subject: usb: gadget: uvc: Prevent buffer overflow in setup handler + +From: Szymon Heidrich + +commit 4c92670b16727365699fe4b19ed32013bab2c107 upstream. + +Setup function uvc_function_setup permits control transfer +requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE), +data stage handler for OUT transfer uses memcpy to copy req->actual +bytes to uvc_event->data.data array of size 60. This may result +in an overflow of 4 bytes. + +Fixes: cdda479f15cd ("USB gadget: video class function driver") +Cc: stable +Reviewed-by: Laurent Pinchart +Reviewed-by: Daniel Scally +Signed-off-by: Szymon Heidrich +Link: https://lore.kernel.org/r/20221206141301.51305-1-szymon.heidrich@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_uvc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/usb/gadget/function/f_uvc.c ++++ b/drivers/usb/gadget/function/f_uvc.c +@@ -220,8 +220,9 @@ uvc_function_ep0_complete(struct usb_ep + + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_DATA; +- uvc_event->data.length = req->actual; +- memcpy(&uvc_event->data.data, req->buf, req->actual); ++ uvc_event->data.length = min_t(unsigned int, req->actual, ++ sizeof(uvc_event->data.data)); ++ memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length); + v4l2_event_queue(&uvc->vdev, &v4l2_event); + } + } diff --git a/queue-4.14/usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch b/queue-4.14/usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch new file mode 100644 index 00000000000..94c71049497 --- /dev/null +++ b/queue-4.14/usb-serial-cp210x-add-kamstrup-rf-sniffer-pids.patch @@ -0,0 +1,37 @@ +From e88906b169ebcb8046e8f0ad76edd09ab41cfdfe Mon Sep 17 00:00:00 2001 +From: Bruno Thomsen +Date: Sun, 27 Nov 2022 18:08:11 +0100 +Subject: USB: serial: cp210x: add Kamstrup RF sniffer PIDs + +From: Bruno Thomsen + +commit e88906b169ebcb8046e8f0ad76edd09ab41cfdfe upstream. + +The RF sniffers are based on cp210x where the RF frontends +are based on a different USB stack. + +RF sniffers can analyze packets meta data including power level +and perform packet injection. + +Can be used to perform RF frontend self-test when connected to +a concentrator, ex. arch/arm/boot/dts/imx7d-flex-concentrator.dts + +Signed-off-by: Bruno Thomsen +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/cp210x.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -199,6 +199,8 @@ static const struct usb_device_id id_tab + { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ ++ { USB_DEVICE(0x17A8, 0x0011) }, /* Kamstrup 444 MHz RF sniffer */ ++ { USB_DEVICE(0x17A8, 0x0013) }, /* Kamstrup 870 MHz RF sniffer */ + { USB_DEVICE(0x17A8, 0x0101) }, /* Kamstrup 868 MHz wM-Bus C-Mode Meter Reader (Int Ant) */ + { USB_DEVICE(0x17A8, 0x0102) }, /* Kamstrup 868 MHz wM-Bus C-Mode Meter Reader (Ext Ant) */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ diff --git a/queue-4.14/usb-serial-option-add-quectel-em05-g-modem.patch b/queue-4.14/usb-serial-option-add-quectel-em05-g-modem.patch new file mode 100644 index 00000000000..dd1f06a0c91 --- /dev/null +++ b/queue-4.14/usb-serial-option-add-quectel-em05-g-modem.patch @@ -0,0 +1,104 @@ +From f0052d7a1edb3d8921b4e154aa8c46c4845b3714 Mon Sep 17 00:00:00 2001 +From: Duke Xin +Date: Sat, 19 Nov 2022 17:44:47 +0800 +Subject: USB: serial: option: add Quectel EM05-G modem + +From: Duke Xin + +commit f0052d7a1edb3d8921b4e154aa8c46c4845b3714 upstream. + +The EM05-G modem has 2 USB configurations that are configurable via the AT +command AT+QCFG="usbnet",[ 0 | 2 ] which make the modem enumerate with +the following interfaces, respectively: + +"RMNET" : AT + DIAG + NMEA + Modem + QMI +"MBIM" : MBIM + AT + DIAG + NMEA + Modem + +The detailed description of the USB configuration for each mode as follows: + +RMNET Mode +-------------- +T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 21 Spd=480 MxCh= 0 +D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=2c7c ProdID=0311 Rev= 3.18 +S: Manufacturer=Quectel +S: Product=Quectel EM05-G +C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA +I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 6 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) +E: Ad=89(I) Atr=03(Int.) MxPS= 8 Ivl=32ms +E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms + +MBIM Mode +-------------- +T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 16 Spd=480 MxCh= 0 +D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=2c7c ProdID=0311 Rev= 3.18 +S: Manufacturer=Quectel +S: Product=Quectel EM05-G +C:* #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA +A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00 +I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option +E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim +E: Ad=89(I) Atr=03(Int.) MxPS= 64 Ivl=32ms +I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim +I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim +E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms + +Signed-off-by: Duke Xin +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/option.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -258,6 +258,7 @@ static void option_instat_callback(struc + #define QUECTEL_PRODUCT_EP06 0x0306 + #define QUECTEL_PRODUCT_EM05G 0x030a + #define QUECTEL_PRODUCT_EM060K 0x030b ++#define QUECTEL_PRODUCT_EM05G_SG 0x0311 + #define QUECTEL_PRODUCT_EM12 0x0512 + #define QUECTEL_PRODUCT_RM500Q 0x0800 + #define QUECTEL_PRODUCT_RM520N 0x0801 +@@ -1163,6 +1164,8 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff), + .driver_info = RSVD(6) | ZLP }, ++ { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff), ++ .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) }, -- 2.47.3