18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * uvc_status.c -- USB Video Class driver - Status endpoint 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2009 68c2ecf20Sopenharmony_ci * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/barrier.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/usb.h> 148c2ecf20Sopenharmony_ci#include <linux/usb/input.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "uvcvideo.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 198c2ecf20Sopenharmony_ci * Input device 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV 228c2ecf20Sopenharmony_cistatic int uvc_input_init(struct uvc_device *dev) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct input_dev *input; 258c2ecf20Sopenharmony_ci int ret; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci input = input_allocate_device(); 288c2ecf20Sopenharmony_ci if (input == NULL) 298c2ecf20Sopenharmony_ci return -ENOMEM; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys)); 328c2ecf20Sopenharmony_ci strlcat(dev->input_phys, "/button", sizeof(dev->input_phys)); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci input->name = dev->name; 358c2ecf20Sopenharmony_ci input->phys = dev->input_phys; 368c2ecf20Sopenharmony_ci usb_to_input_id(dev->udev, &input->id); 378c2ecf20Sopenharmony_ci input->dev.parent = &dev->intf->dev; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci __set_bit(EV_KEY, input->evbit); 408c2ecf20Sopenharmony_ci __set_bit(KEY_CAMERA, input->keybit); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if ((ret = input_register_device(input)) < 0) 438c2ecf20Sopenharmony_ci goto error; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci dev->input = input; 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cierror: 498c2ecf20Sopenharmony_ci input_free_device(input); 508c2ecf20Sopenharmony_ci return ret; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void uvc_input_unregister(struct uvc_device *dev) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci if (dev->input) 568c2ecf20Sopenharmony_ci input_unregister_device(dev->input); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void uvc_input_report_key(struct uvc_device *dev, unsigned int code, 608c2ecf20Sopenharmony_ci int value) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (dev->input) { 638c2ecf20Sopenharmony_ci input_report_key(dev->input, code, value); 648c2ecf20Sopenharmony_ci input_sync(dev->input); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#else 698c2ecf20Sopenharmony_ci#define uvc_input_init(dev) 708c2ecf20Sopenharmony_ci#define uvc_input_unregister(dev) 718c2ecf20Sopenharmony_ci#define uvc_input_report_key(dev, code, value) 728c2ecf20Sopenharmony_ci#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 758c2ecf20Sopenharmony_ci * Status interrupt endpoint 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistruct uvc_streaming_status { 788c2ecf20Sopenharmony_ci u8 bStatusType; 798c2ecf20Sopenharmony_ci u8 bOriginator; 808c2ecf20Sopenharmony_ci u8 bEvent; 818c2ecf20Sopenharmony_ci u8 bValue[]; 828c2ecf20Sopenharmony_ci} __packed; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct uvc_control_status { 858c2ecf20Sopenharmony_ci u8 bStatusType; 868c2ecf20Sopenharmony_ci u8 bOriginator; 878c2ecf20Sopenharmony_ci u8 bEvent; 888c2ecf20Sopenharmony_ci u8 bSelector; 898c2ecf20Sopenharmony_ci u8 bAttribute; 908c2ecf20Sopenharmony_ci u8 bValue[]; 918c2ecf20Sopenharmony_ci} __packed; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void uvc_event_streaming(struct uvc_device *dev, 948c2ecf20Sopenharmony_ci struct uvc_streaming_status *status, int len) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (len < 3) { 978c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " 988c2ecf20Sopenharmony_ci "received.\n"); 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (status->bEvent == 0) { 1038c2ecf20Sopenharmony_ci if (len < 4) 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", 1068c2ecf20Sopenharmony_ci status->bOriginator, 1078c2ecf20Sopenharmony_ci status->bValue[0] ? "pressed" : "released", len); 1088c2ecf20Sopenharmony_ci uvc_input_report_key(dev, KEY_CAMERA, status->bValue[0]); 1098c2ecf20Sopenharmony_ci } else { 1108c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, 1118c2ecf20Sopenharmony_ci "Stream %u error event %02x len %d.\n", 1128c2ecf20Sopenharmony_ci status->bOriginator, status->bEvent, len); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define UVC_CTRL_VALUE_CHANGE 0 1178c2ecf20Sopenharmony_ci#define UVC_CTRL_INFO_CHANGE 1 1188c2ecf20Sopenharmony_ci#define UVC_CTRL_FAILURE_CHANGE 2 1198c2ecf20Sopenharmony_ci#define UVC_CTRL_MIN_CHANGE 3 1208c2ecf20Sopenharmony_ci#define UVC_CTRL_MAX_CHANGE 4 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity, 1238c2ecf20Sopenharmony_ci u8 selector) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct uvc_control *ctrl; 1268c2ecf20Sopenharmony_ci unsigned int i; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++) 1298c2ecf20Sopenharmony_ci if (ctrl->info.selector == selector) 1308c2ecf20Sopenharmony_ci return ctrl; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return NULL; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev, 1368c2ecf20Sopenharmony_ci const struct uvc_control_status *status, 1378c2ecf20Sopenharmony_ci struct uvc_video_chain **chain) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci list_for_each_entry((*chain), &dev->chains, list) { 1408c2ecf20Sopenharmony_ci struct uvc_entity *entity; 1418c2ecf20Sopenharmony_ci struct uvc_control *ctrl; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci list_for_each_entry(entity, &(*chain)->entities, chain) { 1448c2ecf20Sopenharmony_ci if (entity->id != status->bOriginator) 1458c2ecf20Sopenharmony_ci continue; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ctrl = uvc_event_entity_find_ctrl(entity, 1488c2ecf20Sopenharmony_ci status->bSelector); 1498c2ecf20Sopenharmony_ci if (ctrl) 1508c2ecf20Sopenharmony_ci return ctrl; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic bool uvc_event_control(struct urb *urb, 1588c2ecf20Sopenharmony_ci const struct uvc_control_status *status, int len) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci static const char *attrs[] = { "value", "info", "failure", "min", "max" }; 1618c2ecf20Sopenharmony_ci struct uvc_device *dev = urb->context; 1628c2ecf20Sopenharmony_ci struct uvc_video_chain *chain; 1638c2ecf20Sopenharmony_ci struct uvc_control *ctrl; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (len < 6 || status->bEvent != 0 || 1668c2ecf20Sopenharmony_ci status->bAttribute >= ARRAY_SIZE(attrs)) { 1678c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, "Invalid control status event " 1688c2ecf20Sopenharmony_ci "received.\n"); 1698c2ecf20Sopenharmony_ci return false; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n", 1738c2ecf20Sopenharmony_ci status->bOriginator, status->bSelector, 1748c2ecf20Sopenharmony_ci attrs[status->bAttribute], len); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* Find the control. */ 1778c2ecf20Sopenharmony_ci ctrl = uvc_event_find_ctrl(dev, status, &chain); 1788c2ecf20Sopenharmony_ci if (!ctrl) 1798c2ecf20Sopenharmony_ci return false; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci switch (status->bAttribute) { 1828c2ecf20Sopenharmony_ci case UVC_CTRL_VALUE_CHANGE: 1838c2ecf20Sopenharmony_ci return uvc_ctrl_status_event_async(urb, chain, ctrl, 1848c2ecf20Sopenharmony_ci status->bValue); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci case UVC_CTRL_INFO_CHANGE: 1878c2ecf20Sopenharmony_ci case UVC_CTRL_FAILURE_CHANGE: 1888c2ecf20Sopenharmony_ci case UVC_CTRL_MIN_CHANGE: 1898c2ecf20Sopenharmony_ci case UVC_CTRL_MAX_CHANGE: 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return false; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void uvc_status_complete(struct urb *urb) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct uvc_device *dev = urb->context; 1998c2ecf20Sopenharmony_ci int len, ret; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci switch (urb->status) { 2028c2ecf20Sopenharmony_ci case 0: 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci case -ENOENT: /* usb_kill_urb() called. */ 2068c2ecf20Sopenharmony_ci case -ECONNRESET: /* usb_unlink_urb() called. */ 2078c2ecf20Sopenharmony_ci case -ESHUTDOWN: /* The endpoint is being disabled. */ 2088c2ecf20Sopenharmony_ci case -EPROTO: /* Device is disconnected (reported by some 2098c2ecf20Sopenharmony_ci * host controller). */ 2108c2ecf20Sopenharmony_ci return; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci default: 2138c2ecf20Sopenharmony_ci uvc_printk(KERN_WARNING, "Non-zero status (%d) in status " 2148c2ecf20Sopenharmony_ci "completion handler.\n", urb->status); 2158c2ecf20Sopenharmony_ci return; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci len = urb->actual_length; 2198c2ecf20Sopenharmony_ci if (len > 0) { 2208c2ecf20Sopenharmony_ci switch (dev->status[0] & 0x0f) { 2218c2ecf20Sopenharmony_ci case UVC_STATUS_TYPE_CONTROL: { 2228c2ecf20Sopenharmony_ci struct uvc_control_status *status = 2238c2ecf20Sopenharmony_ci (struct uvc_control_status *)dev->status; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (uvc_event_control(urb, status, len)) 2268c2ecf20Sopenharmony_ci /* The URB will be resubmitted in work context. */ 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci case UVC_STATUS_TYPE_STREAMING: { 2328c2ecf20Sopenharmony_ci struct uvc_streaming_status *status = 2338c2ecf20Sopenharmony_ci (struct uvc_streaming_status *)dev->status; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci uvc_event_streaming(dev, status, len); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci default: 2408c2ecf20Sopenharmony_ci uvc_trace(UVC_TRACE_STATUS, "Unknown status event " 2418c2ecf20Sopenharmony_ci "type %u.\n", dev->status[0]); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Resubmit the URB. */ 2478c2ecf20Sopenharmony_ci urb->interval = dev->int_ep->desc.bInterval; 2488c2ecf20Sopenharmony_ci if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { 2498c2ecf20Sopenharmony_ci uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", 2508c2ecf20Sopenharmony_ci ret); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciint uvc_status_init(struct uvc_device *dev) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep = dev->int_ep; 2578c2ecf20Sopenharmony_ci unsigned int pipe; 2588c2ecf20Sopenharmony_ci int interval; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (ep == NULL) 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci uvc_input_init(dev); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); 2668c2ecf20Sopenharmony_ci if (dev->status == NULL) 2678c2ecf20Sopenharmony_ci return -ENOMEM; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); 2708c2ecf20Sopenharmony_ci if (dev->int_urb == NULL) { 2718c2ecf20Sopenharmony_ci kfree(dev->status); 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* For high-speed interrupt endpoints, the bInterval value is used as 2788c2ecf20Sopenharmony_ci * an exponent of two. Some developers forgot about it. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci interval = ep->desc.bInterval; 2818c2ecf20Sopenharmony_ci if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH && 2828c2ecf20Sopenharmony_ci (dev->quirks & UVC_QUIRK_STATUS_INTERVAL)) 2838c2ecf20Sopenharmony_ci interval = fls(interval) - 1; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci usb_fill_int_urb(dev->int_urb, dev->udev, pipe, 2868c2ecf20Sopenharmony_ci dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, 2878c2ecf20Sopenharmony_ci dev, interval); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_civoid uvc_status_unregister(struct uvc_device *dev) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci usb_kill_urb(dev->int_urb); 2958c2ecf20Sopenharmony_ci uvc_input_unregister(dev); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_civoid uvc_status_cleanup(struct uvc_device *dev) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci usb_free_urb(dev->int_urb); 3018c2ecf20Sopenharmony_ci kfree(dev->status); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciint uvc_status_start(struct uvc_device *dev, gfp_t flags) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci if (dev->int_urb == NULL) 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return usb_submit_urb(dev->int_urb, flags); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_civoid uvc_status_stop(struct uvc_device *dev) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct uvc_ctrl_work *w = &dev->async_ctrl; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * Prevent the asynchronous control handler from requeing the URB. The 3188c2ecf20Sopenharmony_ci * barrier is needed so the flush_status change is visible to other 3198c2ecf20Sopenharmony_ci * CPUs running the asynchronous handler before usb_kill_urb() is 3208c2ecf20Sopenharmony_ci * called below. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci smp_store_release(&dev->flush_status, true); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Cancel any pending asynchronous work. If any status event was queued, 3268c2ecf20Sopenharmony_ci * process it synchronously. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci if (cancel_work_sync(&w->work)) 3298c2ecf20Sopenharmony_ci uvc_ctrl_status_event(w->chain, w->ctrl, w->data); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Kill the urb. */ 3328c2ecf20Sopenharmony_ci usb_kill_urb(dev->int_urb); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * The URB completion handler may have queued asynchronous work. This 3368c2ecf20Sopenharmony_ci * won't resubmit the URB as flush_status is set, but it needs to be 3378c2ecf20Sopenharmony_ci * cancelled before returning or it could then race with a future 3388c2ecf20Sopenharmony_ci * uvc_status_start() call. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (cancel_work_sync(&w->work)) 3418c2ecf20Sopenharmony_ci uvc_ctrl_status_event(w->chain, w->ctrl, w->data); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * From this point, there are no events on the queue and the status URB 3458c2ecf20Sopenharmony_ci * is dead. No events will be queued until uvc_status_start() is called. 3468c2ecf20Sopenharmony_ci * The barrier is needed to make sure that flush_status is visible to 3478c2ecf20Sopenharmony_ci * uvc_ctrl_status_event_work() when uvc_status_start() will be called 3488c2ecf20Sopenharmony_ci * again. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci smp_store_release(&dev->flush_status, false); 3518c2ecf20Sopenharmony_ci} 352