diff --git a/Documentation/filesystems/OWNERS b/Documentation/filesystems/OWNERS new file mode 100644 index 000000000000..5b6ec532f1e2 --- /dev/null +++ b/Documentation/filesystems/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/Documentation/filesystems/OWNERS diff --git a/MAINTAINERS b/MAINTAINERS index 99a57f8118ec..9aa953f4b470 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7320,6 +7320,12 @@ F: drivers/hid/ F: include/linux/hid* F: include/uapi/linux/hid* +HID PLAYSTATION DRIVER +M: Roderick Colenbrander +L: linux-input@vger.kernel.org +S: Supported +F: drivers/hid/hid-playstation.c + HID SENSOR HUB DRIVERS M: Jiri Kosina M: Jonathan Cameron diff --git a/OWNERS b/OWNERS new file mode 100644 index 000000000000..2b5ccceaf513 --- /dev/null +++ b/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/OWNERS diff --git a/android/OWNERS b/android/OWNERS index aefaeef7aee4..15daab5460ab 100644 --- a/android/OWNERS +++ b/android/OWNERS @@ -1,7 +1,6 @@ # If we ever add another OWNERS above this directory, it's likely to be # more permissive, so don't inherit from it set noparent -gki-abi-approvers@google.com adelva@google.com maennich@google.com saravanak@google.com diff --git a/android/abi_gki_aarch64_cuttlefish b/android/abi_gki_aarch64_cuttlefish index df6a9c3c7eb0..ed9d96a0557b 100644 --- a/android/abi_gki_aarch64_cuttlefish +++ b/android/abi_gki_aarch64_cuttlefish @@ -20,6 +20,7 @@ complete __const_udelay consume_skb + _copy_from_iter_full cpu_hwcap_keys cpu_hwcaps cpu_number @@ -63,7 +64,6 @@ kfree_skb __kmalloc kmalloc_caches - kmalloc_order_trace kmem_cache_alloc kmem_cache_alloc_trace kmem_cache_create @@ -159,6 +159,7 @@ sg_init_one sg_init_table skb_clone + skb_dequeue skb_put sk_free snd_device_new @@ -261,6 +262,19 @@ serdev_device_write serdev_device_write_wakeup +# required by hci_vhci.ko + bt_err + hci_alloc_dev + hci_free_dev + hci_recv_frame + hci_register_dev + hci_unregister_dev + skb_pull + skb_push + skb_queue_head + skb_queue_purge + skb_queue_tail + # required by incrementalfs.ko bin2hex __break_lease @@ -312,10 +326,12 @@ __msecs_to_jiffies mutex_is_locked notify_change + override_creds pagecache_get_page path_get path_put register_filesystem + revert_creds seq_puts set_anon_super sget @@ -595,6 +611,7 @@ drm_set_preferred_mode drm_universal_plane_init __get_task_comm + kmalloc_order_trace kvfree kvmalloc_node memdup_user @@ -825,12 +842,13 @@ bpf_trace_run10 bpf_trace_run8 cancel_delayed_work - _copy_from_iter_full _copy_to_iter trace_print_symbols_seq # required by vsock.ko autoremove_wake_function + init_user_ns + ns_capable_noaudit prandom_u32 prepare_to_wait proto_register @@ -839,7 +857,6 @@ _raw_write_unlock_bh security_sock_graft sk_alloc - skb_dequeue sock_init_data sock_no_accept sock_no_getsockopt diff --git a/android/abi_gki_aarch64_imx b/android/abi_gki_aarch64_imx new file mode 100644 index 000000000000..ce8c8cb823f1 --- /dev/null +++ b/android/abi_gki_aarch64_imx @@ -0,0 +1,1882 @@ +[abi_symbol_list] +# commonly used symbols + add_wait_queue + alloc_chrdev_region + alloc_etherdev_mqs + alloc_pages_exact + __alloc_pages_nodemask + __alloc_percpu + alloc_workqueue + __arch_copy_from_user + __arch_copy_to_user + arm64_const_caps_ready + __arm_smccc_smc + atomic_notifier_chain_register + atomic_notifier_chain_unregister + bcmp + bpf_trace_run1 + bpf_trace_run2 + bpf_trace_run3 + cancel_delayed_work + cancel_delayed_work_sync + cancel_work_sync + capable + cdev_add + cdev_del + cdev_init + cec_allocate_adapter + cec_delete_adapter + cec_received_msg_ts + cec_register_adapter + cec_transmit_attempt_done_ts + cec_unregister_adapter + __cfi_slowpath + __check_object_size + __class_create + class_destroy + clk_bulk_disable + clk_bulk_enable + clk_bulk_prepare + clk_bulk_unprepare + clk_disable + clk_enable + clk_gate_ops + clk_get + __clk_get_name + clk_get_parent + clk_get_rate + clk_is_match + clk_prepare + clk_put + clk_register + clk_register_fixed_rate + clk_register_gate + clk_register_mux + clk_round_rate + clk_set_parent + clk_set_rate + clk_unprepare + complete + component_add + component_del + __const_udelay + consume_skb + cpu_hwcap_keys + cpu_hwcaps + cpumask_next + cpu_number + __cpu_online_mask + __cpu_possible_mask + crc32_le + delayed_work_timer_fn + del_timer + del_timer_sync + destroy_workqueue + dev_driver_string + _dev_err + dev_fwnode + device_create + device_create_file + device_destroy + device_for_each_child + device_get_match_data + device_init_wakeup + device_link_add + device_link_del + device_property_present + device_property_read_u32_array + device_remove_file + __device_reset + device_set_wakeup_capable + device_set_wakeup_enable + _dev_info + __dev_kfree_skb_any + devm_add_action + devm_clk_bulk_get + devm_clk_get + devm_clk_get_optional + devm_extcon_dev_allocate + devm_extcon_dev_register + devm_free_irq + devm_gpiod_get + devm_gpiod_get_optional + devm_gpio_request_one + devm_ioremap + devm_ioremap_resource + devm_kfree + devm_kmalloc + __devm_of_phy_provider_register + devm_phy_create + devm_phy_get + devm_pinctrl_get + devm_platform_ioremap_resource + __devm_regmap_init + __devm_regmap_init_i2c + __devm_regmap_init_mmio_clk + devm_regulator_bulk_get + devm_regulator_get + devm_regulator_get_optional + devm_request_threaded_irq + devm_reset_control_array_get + __devm_reset_control_get + devm_reset_controller_register + devm_snd_dmaengine_pcm_register + devm_snd_soc_register_card + devm_snd_soc_register_component + devm_usb_get_phy_by_phandle + dev_pm_domain_attach_by_name + dev_pm_domain_detach + dev_pm_set_wake_irq + dev_set_name + _dev_warn + disable_irq + disable_irq_nosync + dma_alloc_attrs + dma_direct_map_page + dma_direct_map_sg + dma_direct_sync_sg_for_cpu + dma_direct_sync_sg_for_device + dma_direct_sync_single_for_cpu + dma_direct_sync_single_for_device + dma_direct_unmap_page + dma_direct_unmap_sg + dma_free_attrs + dma_get_slave_caps + dmam_alloc_attrs + dma_mmap_attrs + dma_release_channel + __dma_request_channel + dma_request_slave_channel + dma_set_coherent_mask + dma_set_mask + down_interruptible + down_write + drm_add_edid_modes + drm_atomic_helper_check + drm_atomic_helper_check_plane_state + drm_atomic_helper_cleanup_planes + drm_atomic_helper_commit + drm_atomic_helper_commit_hw_done + drm_atomic_helper_commit_modeset_disables + drm_atomic_helper_commit_modeset_enables + drm_atomic_helper_commit_planes + drm_atomic_helper_connector_destroy_state + drm_atomic_helper_connector_duplicate_state + drm_atomic_helper_connector_reset + __drm_atomic_helper_crtc_destroy_state + __drm_atomic_helper_crtc_duplicate_state + drm_atomic_helper_disable_plane + drm_atomic_helper_page_flip + drm_atomic_helper_plane_destroy_state + drm_atomic_helper_plane_duplicate_state + drm_atomic_helper_plane_reset + drm_atomic_helper_set_config + drm_atomic_helper_update_plane + drm_atomic_helper_wait_for_vblanks + drm_bridge_add + drm_bridge_attach + drm_bridge_remove + drm_compat_ioctl + drm_connector_attach_encoder + drm_connector_cleanup + drm_connector_init + drm_connector_update_edid_property + drm_crtc_arm_vblank_event + drm_crtc_cleanup + drm_crtc_handle_vblank + drm_crtc_init_with_planes + drm_crtc_send_vblank_event + drm_crtc_vblank_get + drm_crtc_vblank_off + drm_crtc_vblank_on + drm_detect_hdmi_monitor + drm_dev_alloc + drm_dev_dbg + drm_dev_printk + drm_dev_put + drm_dev_register + drm_dev_unregister + drm_display_info_set_bus_formats + drm_display_mode_from_videomode + drm_display_mode_to_videomode + drm_do_get_edid + drm_encoder_cleanup + drm_encoder_init + drm_err + drm_fb_cma_get_gem_obj + drm_gem_fb_create + drm_gem_prime_fd_to_handle + drm_gem_prime_handle_to_fd + drm_get_edid + drm_get_format_name + drm_hdmi_avi_infoframe_from_display_mode + drm_hdmi_vendor_infoframe_from_display_mode + drm_helper_hpd_irq_event + drm_helper_probe_single_connector_modes + drm_ioctl + drm_match_cea_mode + drm_mode_duplicate + drm_mode_probed_add + drm_mode_set_name + drm_mode_vrefresh + drm_of_find_possible_crtcs + drm_open + drm_panel_add + drm_panel_init + drm_panel_remove + drm_plane_cleanup + drm_plane_create_zpos_immutable_property + drm_poll + drm_read + drm_release + drm_universal_plane_init + dump_stack + enable_irq + eth_type_trans + eth_validate_addr + event_triggers_call + extcon_get_edev_by_phandle + extcon_get_state + extcon_set_state_sync + fd_install + filp_close + filp_open + find_next_bit + finish_wait + flush_work + flush_workqueue + fput + free_irq + free_netdev + __free_pages + free_pages + free_pages_exact + free_percpu + fwnode_graph_get_next_endpoint + fwnode_handle_put + fwnode_property_read_u32_array + generic_handle_irq + get_cpu_device + __get_free_pages + get_random_bytes + get_unused_fd_flags + gpiod_direction_output_raw + gpiod_set_raw_value_cansleep + gpiod_set_value_cansleep + gpio_request + gpio_to_desc + handle_level_irq + hdmi_audio_infoframe_init + hdmi_avi_infoframe_pack + hdmi_vendor_infoframe_pack + i2c_add_adapter + i2c_del_adapter + i2c_del_driver + i2c_register_driver + i2c_transfer + i2c_transfer_buffer_flags + i2c_unregister_device + idr_alloc + idr_destroy + idr_find + idr_remove + init_timer_key + init_wait_entry + __init_waitqueue_head + input_event + input_register_device + input_set_capability + iomem_resource + __ioremap + iounmap + irq_domain_remove + irq_find_mapping + irq_modify_status + irq_set_chained_handler_and_data + irq_set_irq_wake + jiffies + jiffies_to_usecs + kasprintf + kernel_read + kernel_write + kfree + kimage_vaddr + kimage_voffset + __kmalloc + kmalloc_caches + kmalloc_order_trace + kmem_cache_alloc_trace + kmemdup + kobject_create_and_add + kobject_put + kthread_create_on_node + kthread_should_stop + ktime_get + ktime_get_mono_fast_ns + ktime_get_real_ts64 + ktime_get_with_offset + kzfree + __list_add_valid + __list_del_entry_valid + media_create_pad_link + media_entity_pads_init + media_entity_remote_pad + memcpy + memset + mipi_dsi_attach + mipi_dsi_detach + mipi_dsi_driver_register_full + mipi_dsi_driver_unregister + misc_deregister + misc_register + mod_delayed_work_on + mod_timer + module_layout + module_put + __msecs_to_jiffies + msleep + __mutex_init + mutex_lock + mutex_lock_interruptible + mutex_unlock + napi_complete_done + napi_disable + __napi_schedule + napi_schedule_prep + __netdev_alloc_skb + netif_carrier_off + netif_device_attach + netif_device_detach + netif_napi_add + netif_tx_wake_queue + no_llseek + noop_llseek + nr_cpu_ids + ns_to_timespec64 + of_address_to_resource + of_alias_get_id + of_clk_add_provider + of_clk_get + of_clk_get_by_name + of_clk_src_onecell_get + of_count_phandle_with_args + of_device_get_match_data + of_device_is_available + of_device_is_compatible + of_find_compatible_node + of_find_device_by_node + of_find_i2c_device_by_node + of_find_matching_node_and_match + of_find_node_by_name + of_find_property + of_fwnode_ops + of_get_child_by_name + of_get_named_gpio_flags + of_get_next_available_child + of_get_next_child + of_get_parent + of_get_property + of_graph_get_next_endpoint + of_graph_get_port_by_id + of_graph_get_remote_node + of_graph_get_remote_port_parent + of_iomap + of_machine_is_compatible + of_match_device + of_match_node + of_node_name_eq + of_parse_phandle + of_parse_phandle_with_args + of_phy_simple_xlate + of_platform_depopulate + of_platform_populate + of_property_count_elems_of_size + of_property_read_string + of_property_read_u32_index + of_property_read_variable_u32_array + of_reset_control_array_get + param_array_ops + param_ops_bool + param_ops_int + param_ops_uint + param_ops_ullong + __pci_register_driver + pci_set_master + pci_set_power_state + pci_unregister_driver + __per_cpu_offset + perf_trace_buf_alloc + perf_trace_run_bpf_submit + pfn_valid + phy_exit + phy_init + phy_power_off + phy_power_on + physvirt_offset + pinctrl_lookup_state + pinctrl_pm_select_default_state + pinctrl_pm_select_sleep_state + pinctrl_select_state + platform_device_add + platform_device_add_data + platform_device_add_properties + platform_device_add_resources + platform_device_alloc + platform_device_put + platform_device_register_full + platform_device_unregister + __platform_driver_register + platform_driver_unregister + platform_get_irq + platform_get_irq_byname + platform_get_irq_byname_optional + platform_get_irq_optional + platform_get_resource + platform_get_resource_byname + platform_irq_count + pm_qos_add_request + pm_qos_remove_request + __pm_relax + pm_runtime_allow + __pm_runtime_disable + pm_runtime_enable + pm_runtime_forbid + pm_runtime_force_resume + pm_runtime_force_suspend + __pm_runtime_idle + __pm_runtime_resume + pm_runtime_set_autosuspend_delay + __pm_runtime_set_status + __pm_runtime_suspend + __pm_runtime_use_autosuspend + preempt_schedule + preempt_schedule_notrace + prepare_to_wait_event + printk + put_device + __put_page + __put_task_struct + queue_delayed_work_on + queue_work_on + radix_tree_insert + ___ratelimit + _raw_spin_lock + _raw_spin_lock_bh + _raw_spin_lock_irq + _raw_spin_lock_irqsave + _raw_spin_unlock + _raw_spin_unlock_bh + _raw_spin_unlock_irq + _raw_spin_unlock_irqrestore + __rcu_read_lock + __rcu_read_unlock + refcount_dec_and_test_checked + refcount_inc_checked + regcache_cache_only + regcache_mark_dirty + regcache_sync + __register_chrdev + register_netdev + __register_rpmsg_driver + register_virtio_driver + regmap_attach_dev + regmap_read + regmap_update_bits_base + regmap_write + regulator_bulk_disable + regulator_bulk_enable + regulator_disable + regulator_enable + regulator_is_enabled + regulator_set_voltage + release_firmware + __release_region + remap_pfn_range + remove_wait_queue + request_firmware + request_firmware_nowait + __request_region + request_threaded_irq + reset_control_assert + reset_control_deassert + reset_control_put + reset_control_reset + rpmsg_send + rpmsg_sendto + rtnl_lock + rtnl_unlock + schedule + schedule_timeout + scnprintf + seq_printf + seq_puts + sg_alloc_table + sg_free_table + sg_init_one + sg_init_table + sg_next + skb_pull + skb_put + snd_ctl_boolean_mono_info + snd_dma_alloc_pages + snd_dmaengine_pcm_prepare_slave_config + snd_dma_free_pages + snd_pcm_format_physical_width + snd_pcm_format_width + snd_pcm_hw_constraint_integer + snd_pcm_hw_constraint_list + snd_pcm_lib_ioctl + snd_pcm_period_elapsed + snd_soc_add_component_controls + snd_soc_card_jack_new + snd_soc_component_read32 + snd_soc_component_read + snd_soc_component_update_bits + snd_soc_component_write + snd_soc_dai_set_fmt + snd_soc_dai_set_sysclk + snd_soc_dai_set_tdm_slot + snd_soc_dapm_add_routes + snd_soc_dapm_get_volsw + snd_soc_dapm_ignore_suspend + snd_soc_dapm_new_controls + snd_soc_dapm_put_volsw + snd_soc_get_enum_double + snd_soc_get_volsw + snd_soc_info_enum_double + snd_soc_info_volsw + snd_soc_jack_add_gpios + snd_soc_of_parse_audio_routing + snd_soc_of_parse_card_name + snd_soc_params_to_bclk + snd_soc_pm_ops + snd_soc_put_enum_double + snd_soc_put_volsw + snd_soc_rtdcom_lookup + snd_soc_set_runtime_hwparams + snprintf + sprintf + sscanf + __stack_chk_fail + __stack_chk_guard + strcasecmp + strcmp + strcpy + strlcpy + strlen + strncmp + strncpy + strsep + strstr + synchronize_irq + syscon_node_to_regmap + syscon_regmap_lookup_by_compatible + syscon_regmap_lookup_by_phandle + sysfs_create_file_ns + sysfs_create_group + sysfs_remove_file_ns + sysfs_remove_group + system_wq + tasklet_kill + __tasklet_schedule + trace_define_field + trace_event_buffer_commit + trace_event_buffer_reserve + trace_event_ignore_this_pid + trace_event_raw_init + trace_event_reg + trace_handle_return + trace_raw_output_prep + trace_seq_printf + try_module_get + tty_flip_buffer_push + __unregister_chrdev + unregister_chrdev_region + unregister_netdev + unregister_rpmsg_driver + unregister_virtio_driver + up + up_write + usb_add_hcd + usb_disabled + usb_get_dr_mode + usb_hcd_is_primary_hcd + usb_put_hcd + usb_remove_hcd + usleep_range + v4l2_async_notifier_add_subdev + v4l2_async_notifier_init + v4l2_async_notifier_unregister + v4l2_async_register_subdev + v4l2_async_unregister_subdev + v4l2_ctrl_handler_free + v4l2_ctrl_handler_init_class + v4l2_ctrl_new_custom + v4l2_ctrl_new_std + v4l2_ctrl_subdev_subscribe_event + v4l2_device_disconnect + v4l2_device_put + v4l2_device_register + v4l2_device_register_subdev + v4l2_device_register_subdev_nodes + v4l2_device_unregister + v4l2_device_unregister_subdev + v4l2_event_pending + v4l2_event_subdev_unsubscribe + v4l2_event_subscribe + v4l2_event_unsubscribe + v4l2_fh_add + v4l2_fh_del + v4l2_fh_exit + v4l2_fh_init + v4l2_i2c_subdev_init + v4l2_subdev_call_wrappers + v4l2_subdev_init + vabits_actual + vb2_buffer_done + vb2_dma_contig_memops + vb2_dqbuf + vb2_expbuf + vb2_mmap + vb2_ops_wait_finish + vb2_ops_wait_prepare + vb2_plane_cookie + vb2_qbuf + vb2_querybuf + vb2_queue_init + vb2_queue_release + vb2_reqbufs + vb2_streamoff + vb2_streamon + vfree + vfs_mkdir + video_devdata + video_device_release_empty + video_ioctl2 + __video_register_device + video_unregister_device + virtqueue_add_inbuf + virtqueue_add_outbuf + virtqueue_get_buf + virtqueue_get_vring_size + virtqueue_kick + virtqueue_kick_prepare + virtqueue_notify + vmalloc + vmalloc_to_page + vmemmap + vsnprintf + wait_for_completion_interruptible_timeout + wait_for_completion_timeout + __wake_up + wake_up_process + __warn_printk + +# required by adv7511.ko + cec_s_phys_addr + cec_s_phys_addr_from_edid + cec_transmit_done_ts + drm_get_connector_status_name + drm_kms_helper_hotplug_event + drm_mode_copy + hdmi_avi_infoframe_init + i2c_new_ancillary_device + mipi_dsi_device_register_full + mipi_dsi_device_unregister + of_find_mipi_dsi_host_by_node + regmap_bulk_write + regmap_register_patch + +# required by busfreq-imx8mq.ko + register_pm_notifier + register_reboot_notifier + +# required by cdns_mhdp_drmcore.ko + drm_atomic_get_crtc_state + drm_dbg + drm_default_rgb_quant_range + drm_dp_aux_register + drm_dp_aux_unregister + drm_dp_bw_code_to_link_rate + drm_dp_dpcd_read + drm_dp_link_rate_to_bw_code + drm_hdmi_avi_infoframe_colorspace + drm_hdmi_avi_infoframe_quant_range + drm_hdmi_infoframe_set_hdr_metadata + drm_mode_create_hdmi_colorspace_property + drm_mode_is_420_also + drm_mode_is_420_only + drm_object_attach_property + hdmi_audio_infoframe_pack + hdmi_avi_infoframe_check + hdmi_drm_infoframe_pack + +# required by clk-imx8mp.ko + clk_hw_register_divider + clk_hw_register_fixed_factor + clk_hw_register_gate + clk_hw_register_mux + +# required by cpufreq-dt.ko + arch_set_freq_scale + cpufreq_enable_boost_support + cpufreq_freq_attr_scaling_available_freqs + cpufreq_freq_attr_scaling_boost_freqs + cpufreq_generic_frequency_table_verify + cpufreq_generic_get + cpufreq_generic_suspend + cpufreq_register_driver + cpufreq_unregister_driver + dev_pm_opp_free_cpufreq_table + dev_pm_opp_get_max_transition_latency + dev_pm_opp_get_opp_count + dev_pm_opp_get_sharing_cpus + dev_pm_opp_get_suspend_opp_freq + dev_pm_opp_init_cpufreq_table + dev_pm_opp_of_cpumask_add_table + dev_pm_opp_of_cpumask_remove_table + dev_pm_opp_of_get_sharing_cpus + dev_pm_opp_of_register_em + dev_pm_opp_put_regulators + dev_pm_opp_set_rate + dev_pm_opp_set_regulators + dev_pm_opp_set_sharing_cpus + policy_has_boost_freq + regulator_get_optional + regulator_put + +# required by cqhci.ko + dmam_free_coherent + mmc_cqe_request_done + +# required by device_cooling.ko + blocking_notifier_call_chain + blocking_notifier_chain_register + blocking_notifier_chain_unregister + thermal_cooling_device_unregister + thermal_of_cooling_device_register + +# required by dummy_battery.ko + power_supply_register + power_supply_unregister + +# required by dw-hdmi-cec.ko + cec_notifier_cec_adap_register + cec_notifier_cec_adap_unregister + devm_remove_action + +# required by dw-hdmi.ko + cec_fill_conn_info_from_drm + cec_notifier_conn_register + cec_notifier_conn_unregister + cec_notifier_set_phys_addr + cec_notifier_set_phys_addr_from_edid + drm_connector_init_with_ddc + drm_detect_monitor_audio + drm_scdc_read + drm_scdc_set_high_tmds_clock_ratio + drm_scdc_set_scrambling + drm_scdc_write + i2c_put_adapter + of_get_i2c_adapter_by_node + +# required by dw_hdmi-imx.ko + devm_kmemdup + devm_phy_optional_get + drm_of_encoder_active_endpoint + +# required by dwc3-haps.ko + pcim_enable_device + +# required by dwc3-of-simple.ko + clk_bulk_get_all + clk_bulk_put_all + +# required by dwc3-qcom.ko + devm_extcon_register_notifier + of_clk_get_parent_count + +# required by dwc3.ko + bpf_trace_run4 + device_property_read_string + device_property_read_u8_array + devm_clk_bulk_get_all + devm_usb_get_phy + extcon_find_edev_by_node + extcon_get_extcon_dev + extcon_register_notifier + extcon_unregister_notifier + of_usb_get_phy_mode + of_usb_update_otg_caps + phy_pm_runtime_get_sync + phy_pm_runtime_put_sync + phy_set_mode_ext + system_freezable_wq + usb_add_gadget_udc + usb_decode_ctrl + usb_del_gadget_udc + usb_ep_set_maxpacket_limit + usb_gadget_giveback_request + usb_gadget_map_request_by_dev + usb_gadget_set_state + usb_gadget_udc_reset + usb_gadget_unmap_request_by_dev + usb_get_maximum_speed + usb_role_switch_register + usb_role_switch_unregister + +# required by fec.ko + ethtool_op_get_link + ethtool_op_get_ts_info + __local_bh_enable_ip + mdiobus_alloc_size + mdiobus_free + mdiobus_is_registered_device + mdiobus_unregister + napi_gro_receive + netdev_err + netdev_info + netdev_pick_tx + netif_schedule_queue + net_ratelimit + of_find_node_by_phandle + of_get_mac_address + of_get_phy_mode + of_mdiobus_register + of_phy_connect + of_phy_deregister_fixed_link + of_phy_find_device + of_phy_is_fixed_link + of_phy_register_fixed_link + param_ops_byte + phy_attached_info + phy_connect + phy_disconnect + phy_ethtool_get_eee + phy_ethtool_get_link_ksettings + phy_ethtool_nway_reset + phy_ethtool_set_eee + phy_ethtool_set_link_ksettings + phy_init_eee + phy_mii_ioctl + phy_print_status + phy_remove_link_mode + phy_reset_after_clk_enable + phy_set_max_speed + phy_set_sym_pause + phy_start + phy_start_aneg + phy_stop + phy_support_sym_pause + pskb_expand_head + skb_tstamp_tx + timecounter_cyc2time + timecounter_init + timecounter_read + tso_build_data + tso_build_hdr + tso_count_descs + tso_start + +# required by fsl-imx-ldb.ko + devm_drm_panel_bridge_add + drm_of_find_panel_or_bridge + +# required by galcore.ko + anon_inode_getfd + cache_line_size + dev_pm_opp_add + dev_pm_opp_remove + dma_buf_attach + dma_buf_detach + dma_buf_export + dma_buf_fd + dma_buf_get + dma_buf_map_attachment + dma_buf_put + dma_buf_unmap_attachment + dma_fence_array_ops + dma_fence_context_alloc + dma_fence_default_wait + dma_fence_init + dma_fence_release + dma_fence_signal + dma_fence_signal_locked + dma_fence_wait_timeout + down + down_read + down_trylock + driver_create_file + driver_remove_file + drm_gem_handle_create + drm_gem_object_lookup + drm_gem_object_put_unlocked + drm_gem_object_release + drm_gem_private_object_init + find_vma + find_vpid + get_user_pages + hrtimer_resolution + idr_preload + iommu_attach_device + iommu_domain_alloc + iommu_domain_free + iommu_map + iommu_set_fault_handler + iommu_unmap + jiffies_to_msecs + kstrtoint_from_user + kthread_stop + ktime_get_ts64 + mutex_trylock + param_ops_ulong + pid_task + platform_bus_type + schedule_hrtimeout + set_user_nice + sg_alloc_table_from_pages + si_meminfo + sync_file_create + sync_file_get_fence + __task_pid_nr_ns + _totalram_pages + up_read + vmap + vm_mmap + vm_munmap + vunmap + +# required by gmsl-max9286.ko + i2c_smbus_read_byte_data + i2c_smbus_write_byte_data + +# required by gpio-mxc.ko + devm_gpiochip_add_data + __devm_irq_alloc_descs + devm_irq_alloc_generic_chip + devm_irq_setup_generic_chip + gpiochip_generic_free + gpiochip_generic_request + gpiochip_get_data + gpiochip_lock_as_irq + gpiochip_unlock_as_irq + irq_domain_add_legacy + irq_domain_simple_ops + irq_gc_ack_set_bit + irq_gc_mask_clr_bit + irq_gc_mask_set_bit + __irq_set_handler + register_syscore_ops + +# required by gpio-switch.ko + typec_switch_get_drvdata + typec_switch_register + typec_switch_unregister + +# required by i2c-imx.ko + clk_notifier_register + clk_notifier_unregister + dma_request_chan + gpiod_set_raw_value + i2c_add_numbered_adapter + i2c_generic_scl_recovery + i2c_recover_bus + __udelay + +# required by imx-audiomix.ko + devm_of_platform_populate + +# required by imx-cpufreq-dt.ko + dev_pm_opp_put_supported_hw + dev_pm_opp_set_supported_hw + nvmem_cell_read_u32 + +# required by imx-lcdif-crtc.ko + drm_property_destroy + +# required by imx-lcdifv3-crtc.ko + drm_mode_equal + drm_mode_find_dmt + +# required by imx-mailbox.ko + devm_mbox_controller_register + mbox_chan_received_data + mbox_chan_txdone + tasklet_init + +# required by imx-pcm-dma-common.ko + snd_dmaengine_pcm_close_release_chan + snd_dmaengine_pcm_get_chan + snd_dmaengine_pcm_open + snd_dmaengine_pcm_open_request_chan + snd_dmaengine_pcm_pointer + snd_dmaengine_pcm_set_config_from_dai_data + snd_dmaengine_pcm_trigger + snd_hwparams_to_dma_slave_config + +# required by imx-pcm-rpmsg.ko + snd_soc_lookup_component + +# required by imx-sdma.ko + dma_async_device_register + dma_async_device_unregister + dma_async_tx_descriptor_init + gen_pool_dma_alloc + gen_pool_free_owner + of_dma_controller_register + of_gen_pool_get + vchan_dma_desc_free_list + vchan_find_desc + vchan_init + vchan_tx_desc_free + vchan_tx_submit + +# required by imx.ko + do_SAK + handle_sysrq + mctrl_gpio_disable_ms + mctrl_gpio_enable_ms + mctrl_gpio_get + mctrl_gpio_init + mctrl_gpio_set + oops_in_progress + rational_best_approximation + _raw_spin_trylock + __tty_insert_flip_char + tty_insert_flip_string_fixed_flag + tty_termios_encode_baud_rate + uart_add_one_port + uart_console_device + uart_console_write + uart_get_baud_rate + uart_get_divisor + uart_get_rs485_mode + uart_handle_cts_change + uart_handle_dcd_change + uart_parse_options + uart_register_driver + uart_remove_one_port + uart_resume_port + uart_set_options + uart_suspend_port + uart_unregister_driver + uart_update_timeout + uart_write_wakeup + +# required by imx2_wdt.ko + _dev_crit + __platform_driver_probe + watchdog_init_timeout + watchdog_register_device + watchdog_set_restart_priority + watchdog_unregister_device + +# required by imx8-capture.ko + soc_device_match + +# required by imx8-isi-cap.ko + media_graph_walk_cleanup + media_graph_walk_init + media_graph_walk_next + media_graph_walk_start + v4l2_fh_open + v4l2_g_parm_cap + v4l2_s_parm_cap + vb2_fop_mmap + vb2_fop_poll + _vb2_fop_release + vb2_ioctl_create_bufs + vb2_ioctl_dqbuf + vb2_ioctl_expbuf + vb2_ioctl_prepare_buf + vb2_ioctl_qbuf + vb2_ioctl_querybuf + vb2_ioctl_reqbufs + vb2_ioctl_streamoff + vb2_ioctl_streamon + +# required by imx8-media-dev.ko + media_device_cleanup + media_device_init + __media_device_register + media_device_unregister + v4l2_async_notifier_register + +# required by imx8m_pm_domains.ko + of_genpd_add_provider_simple + of_genpd_add_subdomain + of_genpd_del_provider + pm_genpd_init + pm_genpd_remove + +# required by imx8mm_thermal.ko + devm_thermal_zone_of_sensor_register + of_thermal_get_trip_points + thermal_zone_bind_cooling_device + +# required by imx8mp-ldb.ko + devm_of_phy_get + +# required by imx_rpmsg_tty.ko + print_hex_dump + put_tty_driver + __tty_alloc_driver + tty_port_close + tty_port_destroy + tty_port_init + tty_port_install + tty_port_open + tty_prepare_flip_string + tty_register_driver + tty_set_operations + tty_std_termios + tty_unregister_driver + +# required by imx_rproc.ko + mbox_free_channel + mbox_request_channel_byname + mbox_send_message + of_phandle_iterator_init + of_phandle_iterator_next + of_reserved_mem_lookup + reset_control_status + rproc_add + rproc_add_carveout + rproc_alloc + rproc_coredump_add_segment + rproc_da_to_va + rproc_del + rproc_elf_find_loaded_rsc_table + rproc_elf_get_boot_addr + rproc_elf_load_rsc_table + rproc_elf_load_segments + rproc_elf_sanity_check + rproc_free + rproc_mem_entry_init + rproc_of_resm_mem_entry_init + rproc_vq_interrupt + +# required by imxdrm.ko + component_bind_all + component_master_add_with_match + component_master_del + component_match_add_release + component_unbind_all + drm_connector_unregister + drm_gem_cma_dumb_create + drm_gem_cma_free_object + drm_gem_cma_mmap + drm_gem_cma_prime_get_sg_table + drm_gem_cma_prime_import_sg_table + drm_gem_cma_prime_mmap + drm_gem_cma_prime_vmap + drm_gem_cma_prime_vunmap + drm_gem_cma_vm_ops + drm_kms_helper_poll_fini + drm_kms_helper_poll_init + drm_mode_config_cleanup + drm_mode_config_helper_resume + drm_mode_config_helper_suspend + drm_mode_config_init + drm_mode_config_reset + drm_of_component_match_add + drm_vblank_init + +# required by incrementalfs.ko + bin2hex + __break_lease + clear_inode + __close_fd + crypto_alloc_shash + crypto_destroy_tfm + crypto_shash_digest + d_add + d_drop + deactivate_locked_super + dentry_open + dget_parent + d_instantiate + d_make_root + dput + fget + flush_dcache_page + flush_delayed_work + fs_kobj + fsstack_copy_attr_all + generic_file_llseek + generic_file_mmap + generic_file_read_iter + generic_file_splice_read + generic_read_dir + generic_shutdown_super + get_zeroed_page + iget5_locked + ihold + inode_init_once + inode_init_owner + iput + iterate_dir + kern_path + lockref_get + lock_rename + lookup_one_len + LZ4_decompress_safe + match_int + match_token + mutex_is_locked + notify_change + override_creds + pagecache_get_page + path_get + path_put + __put_cred + register_filesystem + revert_creds + set_anon_super + sget + simple_getattr + simple_setattr + simple_statfs + strndup_user + sync_filesystem + truncate_inode_pages + unlock_new_inode + unlock_page + unlock_rename + unregister_filesystem + user_path_at_empty + vfs_create + vfs_fallocate + vfs_getattr + vfs_getxattr + vfs_link + vfs_listxattr + vfs_rename + vfs_rmdir + vfs_setxattr + vfs_unlink + +# required by ion_cma_heap.ko + cma_alloc + cma_for_each_area + cma_get_name + cma_release + ion_buffer_prep_noncached + __ion_device_add_heap + ion_device_remove_heap + +# required by irq-imx-irqsteer.ko + __irq_domain_add + irq_domain_xlate_onecell + irq_of_parse_and_map + irq_set_chip_and_handler_name + irq_set_chip_data + +# required by it6263.ko + i2c_new_dummy + regmap_bulk_read + +# required by moal.ko + alloc_netdev_mqs + __alloc_skb + __cfg80211_alloc_event_skb + __cfg80211_alloc_reply_skb + cfg80211_cac_event + cfg80211_ch_switch_notify + cfg80211_connect_done + cfg80211_cqm_rssi_notify + cfg80211_del_sta_sinfo + cfg80211_disconnected + cfg80211_find_elem_match + cfg80211_ft_event + cfg80211_get_bss + cfg80211_inform_bss_data + cfg80211_mgmt_tx_status + cfg80211_michael_mic_failure + cfg80211_new_sta + cfg80211_pmksa_candidate_notify + cfg80211_put_bss + cfg80211_radar_event + cfg80211_ready_on_channel + cfg80211_remain_on_channel_expired + cfg80211_report_wowlan_wakeup + cfg80211_roamed + cfg80211_rx_assoc_resp + cfg80211_rx_mgmt + cfg80211_rx_mlme_mgmt + cfg80211_scan_done + cfg80211_sched_scan_results + cfg80211_sched_scan_stopped + __cfg80211_send_event_skb + cfg80211_unlink_bss + cfg80211_vendor_cmd_reply + _ctype + default_wake_function + dev_alloc_name + dev_close + ether_setup + hex_dump_to_buffer + ieee80211_bss_get_elem + ieee80211_channel_to_freq_khz + ieee80211_freq_khz_to_channel + ieee80211_get_channel_khz + in4_pton + init_dummy_netdev + init_net + iwe_stream_add_event + iwe_stream_add_point + iwe_stream_add_value + iw_handler_get_spy + iw_handler_get_thrspy + iw_handler_set_spy + iw_handler_set_thrspy + kern_path_create + kfree_skb + ktime_get_raw + ktime_get_raw_ts64 + memcmp + memmove + mmc_set_data_timeout + mmc_wait_for_req + netif_carrier_on + netif_napi_del + netif_rx + netif_rx_ni + netif_tx_stop_all_queues + netlink_broadcast + __netlink_kernel_create + netlink_kernel_release + __nla_parse + nla_put + panic + param_ops_charp + param_ops_ushort + pci_choose_state + pci_disable_device + pci_disable_msi + pci_disable_msix + pci_enable_device + pci_enable_msi + pci_enable_msix_range + pci_enable_wake + pci_iomap + pci_read_config_dword + pci_release_region + pci_request_region + pci_reset_function + pci_restore_state + pci_save_state + PDE_DATA + prandom_u32 + proc_create_data + proc_mkdir + register_netdevice + regulatory_hint + regulatory_set_wiphy_regd + remove_proc_entry + rtnl_is_locked + sdio_claim_host + sdio_claim_irq + sdio_disable_func + sdio_enable_func + sdio_f0_readb + sdio_f0_writeb + sdio_get_host_pm_caps + sdio_readb + sdio_readsb + sdio_register_driver + sdio_release_host + sdio_release_irq + sdio_set_block_size + sdio_set_host_pm_flags + sdio_unregister_driver + sdio_writeb + sdio_writesb + seq_lseek + seq_read + single_open + single_release + skb_realloc_headroom + sort + strcat + strchr + strim + strncasecmp + strrchr + __sw_hweight64 + unregister_netdevice_queue + vprintk + wiphy_apply_custom_regulatory + wiphy_free + wiphy_new_nm + wiphy_register + wiphy_unregister + wireless_send_event + +# required by mxc-clk.ko + __clk_determine_rate + clk_divider_ops + clk_fractional_divider_ops + __clk_get_hw + clk_hw_get_name + clk_hw_get_parent_by_index + clk_hw_is_enabled + clk_hw_register + clk_hw_register_composite + clk_mux_ops + clk_unregister + divider_get_val + divider_recalc_rate + of_clk_get_from_provider + of_find_node_opts_by_path + +# required by nvmem-imx-ocotp.ko + devm_nvmem_register + +# required by os08a20.ko + devm_pinctrl_put + +# required by ov5640.ko + v4l2_ctrl_auto_cluster + v4l2_ctrl_handler_setup + v4l2_ctrl_new_std_menu + v4l2_ctrl_new_std_menu_items + v4l2_ctrl_subdev_log_status + __v4l2_find_nearest_size + +# required by panel-raydium-rm67191.ko + devm_backlight_device_register + mipi_dsi_dcs_enter_sleep_mode + mipi_dsi_dcs_exit_sleep_mode + mipi_dsi_dcs_get_display_brightness + mipi_dsi_dcs_set_display_brightness + mipi_dsi_dcs_set_display_off + mipi_dsi_dcs_set_display_on + mipi_dsi_dcs_set_pixel_format + mipi_dsi_dcs_set_tear_on + mipi_dsi_dcs_set_tear_scanline + mipi_dsi_dcs_soft_reset + mipi_dsi_generic_write + +# required by panel-simple.ko + drm_mode_create + of_find_backlight_by_node + of_find_i2c_adapter_by_node + of_get_display_timing + videomode_from_timing + +# required by pca9450-regulator.ko + of_regulator_match + rdev_get_drvdata + regulator_disable_regmap + regulator_enable_regmap + regulator_get_voltage_sel_regmap + regulator_is_enabled_regmap + regulator_list_voltage_linear + regulator_list_voltage_linear_range + regulator_map_voltage_iterate + regulator_register + regulator_set_voltage_sel_regmap + regulator_set_voltage_time_sel + regulator_unregister + +# required by pca9450.ko + gpiod_to_irq + mfd_add_devices + mfd_remove_devices + regmap_add_irq_chip + regmap_del_irq_chip + regmap_irq_get_domain + +# required by pci-imx6.ko + dw_pcie_ep_init + dw_pcie_ep_raise_legacy_irq + dw_pcie_ep_raise_msi_irq + dw_pcie_ep_raise_msix_irq + dw_pcie_ep_reset_bar + dw_pcie_host_init + dw_pcie_link_up + dw_pcie_msi_init + dw_pcie_read_dbi + dw_pcie_setup_rc + dw_pcie_wait_for_link + dw_pcie_write_dbi + pci_msi_enabled + phy_calibrate + +# required by phy-fsl-imx8mq-usb.ko + power_supply_get_by_phandle + power_supply_get_property + power_supply_put + power_supply_reg_notifier + power_supply_set_property + power_supply_unreg_notifier + +# required by phy-fsl-samsung-hdmi.ko + devm_clk_register + of_clk_del_provider + of_clk_src_simple_get + +# required by pinctrl-imx.ko + devm_pinctrl_register_and_init + pinconf_generic_parse_dt_config + pinctrl_dev_get_drvdata + pinctrl_enable + pinctrl_force_default + pinctrl_force_sleep + pinctrl_generic_get_group + pinctrl_generic_get_group_count + pinctrl_generic_get_group_name + pinctrl_generic_get_group_pins + pin_get_name + pinmux_generic_get_function + pinmux_generic_get_function_count + pinmux_generic_get_function_groups + pinmux_generic_get_function_name + +# required by pps_core.ko + fasync_helper + idr_get_next + kill_fasync + kobject_get + +# required by ptp.ko + device_initialize + ida_alloc_range + ida_destroy + ida_free + kthread_cancel_delayed_work_sync + kthread_create_worker + kthread_delayed_work_timer_fn + kthread_destroy_worker + kthread_mod_delayed_work + kthread_queue_delayed_work + ktime_get_snapshot + memdup_user + posix_clock_register + posix_clock_unregister + +# required by pwm-imx27.ko + of_pwm_xlate_with_flags + pwmchip_add + pwmchip_remove + +# required by pwm_bl.ko + backlight_device_register + backlight_device_unregister + devm_pwm_get + gpiod_direction_output + gpiod_get_direction + gpiod_get_value_cansleep + int_pow + pwm_apply_state + pwm_free + pwm_request + +# required by rtc-snvs.ko + devm_rtc_allocate_device + __rtc_register_device + rtc_time64_to_tm + rtc_tm_to_time64 + rtc_update_irq + +# required by sdhci-esdhc-imx.ko + mmc_gpiod_request_cd + mmc_gpiod_request_ro + mmc_gpio_get_cd + mmc_gpio_get_ro + mmc_of_parse + mmc_of_parse_voltage + mmc_retune_timer_stop + mmc_send_tuning + sdhci_add_host + sdhci_cqe_disable + sdhci_cqe_enable + sdhci_cqe_irq + sdhci_dumpregs + sdhci_execute_tuning + sdhci_pltfm_free + sdhci_pltfm_init + sdhci_remove_host + sdhci_reset + sdhci_resume_host + sdhci_runtime_resume_host + sdhci_runtime_suspend_host + sdhci_suspend_host + +# required by sec-dsim.ko + bsearch + drm_panel_attach + drm_panel_detach + drm_panel_disable + drm_panel_enable + drm_panel_get_modes + drm_panel_prepare + drm_panel_unprepare + mipi_dsi_create_packet + mipi_dsi_host_register + mipi_dsi_host_unregister + of_drm_find_bridge + of_drm_find_panel + +# required by snd-soc-fsl-dsp-cpu.ko + snd_soc_new_compress + snd_soc_register_component + snd_soc_unregister_component + +# required by snd-soc-fsl-dsp.ko + dev_pm_domain_attach_by_id + __memset_io + of_irq_get + pm_system_wakeup + sysfs_streq + vfs_llseek + +# required by snd-soc-fsl-easrc.ko + completion_done + gcd + snd_pcm_format_big_endian + snd_pcm_format_linear + snd_pcm_format_unsigned + snd_soc_dpcm_get_substream + snd_soc_info_xr_sx + +# required by snd-soc-fsl-micfil.ko + kobject_uevent_env + kstrtoull + snd_soc_get_volsw_sx + snd_soc_info_volsw_sx + snd_soc_put_volsw_sx + +# required by snd-soc-fsl-rpmsg-i2s.ko + __pm_stay_awake + wakeup_source_register + wakeup_source_unregister + +# required by snd-soc-fsl-sai.ko + kstrtouint + snd_pcm_hw_constraint_step + __sw_hweight8 + +# required by snd-soc-hdmi-codec.ko + snd_ctl_add + snd_ctl_new1 + snd_pcm_add_chmap_ctls + snd_pcm_create_iec958_consumer_hw_params + snd_pcm_hw_constraint_eld + snd_soc_jack_report + +# required by snd-soc-imx-rpmsg.ko + of_reserved_mem_device_init_by_idx + +# required by snd-soc-imx-wm8960.ko + gpiod_get_raw_value_cansleep + of_parse_phandle_with_fixed_args + snd_soc_dai_set_pll + snd_soc_dapm_disable_pin + snd_soc_dapm_enable_pin + +# required by snd-soc-rpmsg-ak4497.ko + gpio_free + snd_soc_dapm_get_enum_double + snd_soc_dapm_put_enum_double + +# required by snd-soc-rpmsg-cs42xx8.ko + regcache_cache_bypass + +# required by snd-soc-simple-card-utils.ko + devm_get_clk_from_child + devm_kasprintf + devm_kvasprintf + of_property_read_string_helper + snd_soc_dapm_get_pin_switch + snd_soc_dapm_info_pin_switch + snd_soc_dapm_put_pin_switch + snd_soc_of_parse_audio_simple_widgets + snd_soc_of_parse_daifmt + +# required by snd-soc-simple-card.ko + snd_soc_of_get_dai_name + snd_soc_of_parse_node_prefix + snd_soc_of_parse_tdm_slot + +# required by snvs_pwrkey.ko + devm_input_allocate_device + pm_relax + pm_wakeup_dev_event + +# required by soc-imx8m.ko + of_root + soc_device_register + +# required by synaptics_dsx_i2c.ko + input_allocate_device + input_free_device + input_mt_init_slots + input_mt_report_slot_state + input_set_abs_params + input_unregister_device + +# required by tcpci.ko + device_get_named_child_node + regmap_raw_read + regmap_raw_write + tcpm_cc_change + tcpm_pd_hard_reset + tcpm_pd_receive + tcpm_pd_transmit_complete + tcpm_register_port + tcpm_tcpc_reset + tcpm_unregister_port + tcpm_vbus_change + +# required by timer-imx-sysctr.ko + clockevents_config_and_register + cpu_bit_bitmap + timer_of_init + +# required by trusty-arm64-fiq.ko + smp_call_function + smp_call_function_single + +# required by trusty-ipc.ko + _copy_from_iter + _copy_to_iter + idr_for_each + strncpy_from_user + virtqueue_detach_unused_buf + wait_woken + woken_wake_function + +# required by trusty-irq.ko + __cpuhp_remove_state + __cpuhp_setup_state + __cpuhp_state_add_instance + __cpuhp_state_remove_instance + disable_percpu_irq + enable_percpu_irq + free_percpu_irq + irq_create_of_mapping + __request_percpu_irq + +# required by trusty-log.ko + panic_notifier_list + +# required by trusty-virtio.ko + register_virtio_device + unregister_virtio_device + vring_del_virtqueue + vring_interrupt + vring_new_virtqueue + +# required by trusty.ko + atomic_notifier_call_chain + +# required by v4l2-fwnode.ko + fwnode_device_is_available + fwnode_get_next_parent + fwnode_get_parent + fwnode_graph_get_port_parent + fwnode_graph_get_remote_endpoint + fwnode_graph_get_remote_port_parent + fwnode_graph_parse_endpoint + fwnode_property_get_reference_args + fwnode_property_present + fwnode_property_read_u64_array + v4l2_async_notifier_add_fwnode_subdev + v4l2_async_notifier_cleanup + v4l2_async_subdev_notifier_register + +# required by v4l2-mem2mem.ko + media_create_intf_link + media_device_register_entity + media_device_unregister_entity + media_devnode_create + media_devnode_remove + media_entity_remove_links + media_remove_intf_links + vb2_create_bufs + vb2_prepare_buf + vb2_request_object_is_buffer + +# required by virtio_rpmsg_bus.ko + device_unregister + rpmsg_find_device + rpmsg_register_device + rpmsg_unregister_device + virtio_check_driver_offered_feature + virtqueue_disable_cb + virtqueue_enable_cb + +# required by vvcam-csis.ko + of_clk_set_defaults + +# required by vvcam-video.ko + platform_device_register + v4l2_ctrl_poll + v4l2_ctrl_subscribe_event + v4l2_event_queue + v4l_bound_align_image + vb2_poll + video_device_alloc + video_device_release + +# required by xhci-hcd.ko + add_timer + complete_all + dma_pool_alloc + dma_pool_create + dma_pool_destroy + dma_pool_free + __num_online_cpus + pci_alloc_irq_vectors_affinity + pci_free_irq_vectors + pci_irq_vector + radix_tree_delete + radix_tree_lookup + radix_tree_maybe_preload + schedule_timeout_uninterruptible + sg_pcopy_from_buffer + sg_pcopy_to_buffer + __sw_hweight32 + trace_print_symbols_seq + usb_amd_dev_put + usb_amd_pt_check_port + usb_amd_quirk_pll_disable + usb_amd_quirk_pll_enable + usb_asmedia_modifyflowcontrol + usb_disable_xhci_ports + usb_hcd_check_unlink_urb + usb_hcd_end_port_resume + usb_hcd_giveback_urb + usb_hc_died + usb_hcd_irq + usb_hcd_link_urb_to_ep + usb_hcd_map_urb_for_dma + usb_hcd_poll_rh_status + usb_hcd_resume_root_hub + usb_hcd_start_port_resume + usb_hcd_unlink_urb_from_ep + usb_hub_clear_tt_buffer + usb_root_hub_lost_power + usb_wakeup_notification + wait_for_completion + +# required by xhci-pci.ko + pci_d3cold_disable + pci_read_config_byte + pci_set_mwi + usb_amd_quirk_pll_check + usb_create_shared_hcd + usb_enable_intel_xhci_ports + usb_hcd_pci_pm_ops + usb_hcd_pci_probe + usb_hcd_pci_remove + usb_hcd_pci_shutdown + +# required by xhci-plat-hcd.ko + device_wakeup_enable + of_usb_host_tpl_support + pci_bus_type + __usb_create_hcd + usb_hcd_platform_shutdown diff --git a/android/abi_gki_aarch64_qcom b/android/abi_gki_aarch64_qcom index 7c49fc3ae224..af413ee22491 100644 --- a/android/abi_gki_aarch64_qcom +++ b/android/abi_gki_aarch64_qcom @@ -8,6 +8,7 @@ alarm_cancel alarm_init alarm_start_relative + alarm_expires_remaining alloc_chrdev_region __alloc_disk_node alarmtimer_get_rtcdev @@ -617,19 +618,24 @@ drm_atomic_helper_crtc_destroy_state __drm_atomic_helper_crtc_duplicate_state drm_atomic_helper_crtc_duplicate_state + __drm_atomic_helper_crtc_reset drm_atomic_helper_crtc_reset drm_atomic_helper_dirtyfb drm_atomic_helper_disable_plane drm_atomic_helper_duplicate_state drm_atomic_helper_page_flip + __drm_atomic_helper_plane_destroy_state drm_atomic_helper_plane_destroy_state __drm_atomic_helper_plane_duplicate_state drm_atomic_helper_plane_duplicate_state + __drm_atomic_helper_plane_reset drm_atomic_helper_plane_reset drm_atomic_helper_prepare_planes __drm_atomic_helper_private_obj_duplicate_state + drm_atomic_helper_resume drm_atomic_helper_set_config drm_atomic_helper_shutdown + drm_atomic_helper_suspend drm_atomic_helper_swap_state drm_atomic_helper_update_legacy_modeset_state drm_atomic_helper_update_plane @@ -768,6 +774,10 @@ drm_gem_prime_mmap drm_gem_private_object_init drm_gem_put_pages + drm_gem_shmem_dumb_create + drm_gem_shmem_get_pages_sgt + drm_gem_shmem_mmap + drm_gem_shmem_prime_import_sg_table drm_gem_vm_close drm_gem_vm_open drm_get_connector_status_name @@ -835,6 +845,7 @@ drm_panel_remove drm_plane_cleanup drm_plane_create_rotation_property + drm_plane_from_index drm_poll drm_prime_gem_destroy drm_prime_pages_to_sg diff --git a/android/abi_gki_aarch64_unisoc b/android/abi_gki_aarch64_unisoc index 0ca6e1b25e0f..6fbaf2fa4896 100644 --- a/android/abi_gki_aarch64_unisoc +++ b/android/abi_gki_aarch64_unisoc @@ -46,6 +46,7 @@ __class_create class_destroy class_find_device + clear_nlink clk_bulk_disable clk_bulk_enable clk_bulk_prepare @@ -94,6 +95,7 @@ __crypto_xor csum_ipv6_magic csum_partial + d_splice_alias default_llseek delayed_work_timer_fn del_timer @@ -271,6 +273,7 @@ ieee80211_freq_khz_to_channel ieee80211_get_channel_khz ignore_console_lock_warning + igrab inet_proto_csum_replace4 init_net __init_rwsem @@ -571,8 +574,10 @@ seq_putc seq_puts seq_read + set_nlink set_normalized_timespec64 set_user_nice + setattr_prepare sg_init_table sg_miter_next sg_miter_start @@ -679,6 +684,7 @@ trace_handle_return trace_raw_output_prep trace_seq_printf + truncate_setsize try_module_get __tty_alloc_driver tty_flip_buffer_push @@ -1558,6 +1564,7 @@ dev_pm_opp_init_cpufreq_table # required by sprd-drm.ko + adjust_managed_page_count component_add component_bind_all component_del diff --git a/arch/arm/OWNERS b/arch/arm/OWNERS new file mode 100644 index 000000000000..1e390c75956e --- /dev/null +++ b/arch/arm/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/arch/arm/OWNERS diff --git a/arch/arm64/OWNERS b/arch/arm64/OWNERS new file mode 100644 index 000000000000..257f4cf26809 --- /dev/null +++ b/arch/arm64/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/arch/arm64/OWNERS diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig index 3078e6744bda..d72ec6f4ee8d 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -395,8 +395,11 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NINTENDO=y CONFIG_HID_PICOLCD=y CONFIG_HID_PLANTRONICS=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y CONFIG_HID_ROCCAT=y CONFIG_HID_SONY=y +CONFIG_SONY_FF=y CONFIG_HID_STEAM=y CONFIG_HID_WACOM=y CONFIG_HID_WIIMOTE=y diff --git a/arch/x86/OWNERS b/arch/x86/OWNERS new file mode 100644 index 000000000000..ae2c29f6c3b7 --- /dev/null +++ b/arch/x86/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/arch/x86/OWNERS diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig index 8d50179d79c6..1fb1554bd5dc 100644 --- a/arch/x86/configs/gki_defconfig +++ b/arch/x86/configs/gki_defconfig @@ -344,8 +344,11 @@ CONFIG_HID_MULTITOUCH=y CONFIG_HID_NINTENDO=y CONFIG_HID_PICOLCD=y CONFIG_HID_PLANTRONICS=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y CONFIG_HID_ROCCAT=y CONFIG_HID_SONY=y +CONFIG_SONY_FF=y CONFIG_HID_STEAM=y CONFIG_HID_WACOM=y CONFIG_HID_WIIMOTE=y diff --git a/block/OWNERS b/block/OWNERS new file mode 100644 index 000000000000..7786d734d5c6 --- /dev/null +++ b/block/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/block/OWNERS diff --git a/build.config.common b/build.config.common index a3f1b303f2d1..778e5a7d540a 100644 --- a/build.config.common +++ b/build.config.common @@ -6,7 +6,7 @@ LD=ld.lld NM=llvm-nm OBJCOPY=llvm-objcopy DEPMOD=depmod -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r383902/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r416183/bin BUILDTOOLS_PREBUILT_BIN=build/build-tools/path/linux-x86 EXTRA_CMDS='' diff --git a/build.config.gki.aarch64 b/build.config.gki.aarch64 index 2c8a87684413..210264370e9b 100644 --- a/build.config.gki.aarch64 +++ b/build.config.gki.aarch64 @@ -12,6 +12,7 @@ android/abi_gki_aarch64_exynosauto android/abi_gki_aarch64_galaxy android/abi_gki_aarch64_goldfish android/abi_gki_aarch64_hikey960 +android/abi_gki_aarch64_imx android/abi_gki_aarch64_oneplus android/abi_gki_aarch64_oplus android/abi_gki_aarch64_qcom diff --git a/crypto/OWNERS b/crypto/OWNERS new file mode 100644 index 000000000000..f74b7ed228f7 --- /dev/null +++ b/crypto/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/crypto/OWNERS diff --git a/drivers/OWNERS b/drivers/OWNERS new file mode 100644 index 000000000000..22c7eece228f --- /dev/null +++ b/drivers/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/drivers/OWNERS diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 24a041c9cc39..7ac1816d45c8 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -69,11 +69,9 @@ #include #include -#include #include -#include "binder_alloc.h" #include "binder_internal.h" #include "binder_trace.h" #include @@ -167,24 +165,6 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error, #define to_binder_fd_array_object(hdr) \ container_of(hdr, struct binder_fd_array_object, hdr) -enum binder_stat_types { - BINDER_STAT_PROC, - BINDER_STAT_THREAD, - BINDER_STAT_NODE, - BINDER_STAT_REF, - BINDER_STAT_DEATH, - BINDER_STAT_TRANSACTION, - BINDER_STAT_TRANSACTION_COMPLETE, - BINDER_STAT_COUNT -}; - -struct binder_stats { - atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; - atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; - atomic_t obj_created[BINDER_STAT_COUNT]; - atomic_t obj_deleted[BINDER_STAT_COUNT]; -}; - static struct binder_stats binder_stats; static inline void binder_stats_deleted(enum binder_stat_types type) @@ -220,299 +200,11 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( return e; } -/** - * struct binder_work - work enqueued on a worklist - * @entry: node enqueued on list - * @type: type of work to be performed - * - * There are separate work lists for proc, thread, and node (async). - */ -struct binder_work { - struct list_head entry; - - enum binder_work_type { - BINDER_WORK_TRANSACTION = 1, - BINDER_WORK_TRANSACTION_COMPLETE, - BINDER_WORK_RETURN_ERROR, - BINDER_WORK_NODE, - BINDER_WORK_DEAD_BINDER, - BINDER_WORK_DEAD_BINDER_AND_CLEAR, - BINDER_WORK_CLEAR_DEATH_NOTIFICATION, - } type; -}; - -struct binder_error { - struct binder_work work; - uint32_t cmd; -}; - -/** - * struct binder_node - binder node bookkeeping - * @debug_id: unique ID for debugging - * (invariant after initialized) - * @lock: lock for node fields - * @work: worklist element for node work - * (protected by @proc->inner_lock) - * @rb_node: element for proc->nodes tree - * (protected by @proc->inner_lock) - * @dead_node: element for binder_dead_nodes list - * (protected by binder_dead_nodes_lock) - * @proc: binder_proc that owns this node - * (invariant after initialized) - * @refs: list of references on this node - * (protected by @lock) - * @internal_strong_refs: used to take strong references when - * initiating a transaction - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @local_weak_refs: weak user refs from local process - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @local_strong_refs: strong user refs from local process - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @tmp_refs: temporary kernel refs - * (protected by @proc->inner_lock while @proc - * is valid, and by binder_dead_nodes_lock - * if @proc is NULL. During inc/dec and node release - * it is also protected by @lock to provide safety - * as the node dies and @proc becomes NULL) - * @ptr: userspace pointer for node - * (invariant, no lock needed) - * @cookie: userspace cookie for node - * (invariant, no lock needed) - * @has_strong_ref: userspace notified of strong ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @pending_strong_ref: userspace has acked notification of strong ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @has_weak_ref: userspace notified of weak ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @pending_weak_ref: userspace has acked notification of weak ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @has_async_transaction: async transaction to node in progress - * (protected by @lock) - * @sched_policy: minimum scheduling policy for node - * (invariant after initialized) - * @accept_fds: file descriptor operations supported for node - * (invariant after initialized) - * @min_priority: minimum scheduling priority - * (invariant after initialized) - * @inherit_rt: inherit RT scheduling policy from caller - * @txn_security_ctx: require sender's security context - * (invariant after initialized) - * @async_todo: list of async work items - * (protected by @proc->inner_lock) - * - * Bookkeeping structure for binder nodes. - */ -struct binder_node { - int debug_id; - spinlock_t lock; - struct binder_work work; - union { - struct rb_node rb_node; - struct hlist_node dead_node; - }; - struct binder_proc *proc; - struct hlist_head refs; - int internal_strong_refs; - int local_weak_refs; - int local_strong_refs; - int tmp_refs; - binder_uintptr_t ptr; - binder_uintptr_t cookie; - struct { - /* - * bitfield elements protected by - * proc inner_lock - */ - u8 has_strong_ref:1; - u8 pending_strong_ref:1; - u8 has_weak_ref:1; - u8 pending_weak_ref:1; - }; - struct { - /* - * invariant after initialization - */ - u8 sched_policy:2; - u8 inherit_rt:1; - u8 accept_fds:1; - u8 txn_security_ctx:1; - u8 min_priority; - }; - bool has_async_transaction; - struct list_head async_todo; -}; - -struct binder_ref_death { - /** - * @work: worklist element for death notifications - * (protected by inner_lock of the proc that - * this ref belongs to) - */ - struct binder_work work; - binder_uintptr_t cookie; -}; - -/** - * struct binder_ref_data - binder_ref counts and id - * @debug_id: unique ID for the ref - * @desc: unique userspace handle for ref - * @strong: strong ref count (debugging only if not locked) - * @weak: weak ref count (debugging only if not locked) - * - * Structure to hold ref count and ref id information. Since - * the actual ref can only be accessed with a lock, this structure - * is used to return information about the ref to callers of - * ref inc/dec functions. - */ -struct binder_ref_data { - int debug_id; - uint32_t desc; - int strong; - int weak; -}; - -/** - * struct binder_ref - struct to track references on nodes - * @data: binder_ref_data containing id, handle, and current refcounts - * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree - * @rb_node_node: node for lookup by @node in proc's rb_tree - * @node_entry: list entry for node->refs list in target node - * (protected by @node->lock) - * @proc: binder_proc containing ref - * @node: binder_node of target node. When cleaning up a - * ref for deletion in binder_cleanup_ref, a non-NULL - * @node indicates the node must be freed - * @death: pointer to death notification (ref_death) if requested - * (protected by @node->lock) - * - * Structure to track references from procA to target node (on procB). This - * structure is unsafe to access without holding @proc->outer_lock. - */ -struct binder_ref { - /* Lookups needed: */ - /* node + proc => ref (transaction) */ - /* desc + proc => ref (transaction, inc/dec ref) */ - /* node => refs + procs (proc exit) */ - struct binder_ref_data data; - struct rb_node rb_node_desc; - struct rb_node rb_node_node; - struct hlist_node node_entry; - struct binder_proc *proc; - struct binder_node *node; - struct binder_ref_death *death; -}; - enum binder_deferred_state { BINDER_DEFERRED_FLUSH = 0x01, BINDER_DEFERRED_RELEASE = 0x02, }; -/** - * struct binder_priority - scheduler policy and priority - * @sched_policy scheduler policy - * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT - * - * The binder driver supports inheriting the following scheduler policies: - * SCHED_NORMAL - * SCHED_BATCH - * SCHED_FIFO - * SCHED_RR - */ -struct binder_priority { - unsigned int sched_policy; - int prio; -}; - -/** - * struct binder_proc - binder process bookkeeping - * @proc_node: element for binder_procs list - * @threads: rbtree of binder_threads in this proc - * (protected by @inner_lock) - * @nodes: rbtree of binder nodes associated with - * this proc ordered by node->ptr - * (protected by @inner_lock) - * @refs_by_desc: rbtree of refs ordered by ref->desc - * (protected by @outer_lock) - * @refs_by_node: rbtree of refs ordered by ref->node - * (protected by @outer_lock) - * @waiting_threads: threads currently waiting for proc work - * (protected by @inner_lock) - * @pid PID of group_leader of process - * (invariant after initialized) - * @tsk task_struct for group_leader of process - * (invariant after initialized) - * @deferred_work_node: element for binder_deferred_list - * (protected by binder_deferred_lock) - * @deferred_work: bitmap of deferred work to perform - * (protected by binder_deferred_lock) - * @is_dead: process is dead and awaiting free - * when outstanding transactions are cleaned up - * (protected by @inner_lock) - * @todo: list of work for this process - * (protected by @inner_lock) - * @stats: per-process binder statistics - * (atomics, no lock needed) - * @delivered_death: list of delivered death notification - * (protected by @inner_lock) - * @max_threads: cap on number of binder threads - * (protected by @inner_lock) - * @requested_threads: number of binder threads requested but not - * yet started. In current implementation, can - * only be 0 or 1. - * (protected by @inner_lock) - * @requested_threads_started: number binder threads started - * (protected by @inner_lock) - * @tmp_ref: temporary reference to indicate proc is in use - * (protected by @inner_lock) - * @default_priority: default scheduler priority - * (invariant after initialized) - * @debugfs_entry: debugfs node - * @alloc: binder allocator bookkeeping - * @context: binder_context for this proc - * (invariant after initialized) - * @inner_lock: can nest under outer_lock and/or node lock - * @outer_lock: no nesting under innor or node lock - * Lock order: 1) outer, 2) node, 3) inner - * @binderfs_entry: process-specific binderfs log file - * - * Bookkeeping structure for binder processes - */ -struct binder_proc { - struct hlist_node proc_node; - struct rb_root threads; - struct rb_root nodes; - struct rb_root refs_by_desc; - struct rb_root refs_by_node; - struct list_head waiting_threads; - int pid; - struct task_struct *tsk; - struct hlist_node deferred_work_node; - int deferred_work; - bool is_dead; - - struct list_head todo; - struct binder_stats stats; - struct list_head delivered_death; - int max_threads; - int requested_threads; - int requested_threads_started; - int tmp_ref; - struct binder_priority default_priority; - struct dentry *debugfs_entry; - struct binder_alloc alloc; - struct binder_context *context; - spinlock_t inner_lock; - spinlock_t outer_lock; - struct dentry *binderfs_entry; -}; - enum { BINDER_LOOPER_STATE_REGISTERED = 0x01, BINDER_LOOPER_STATE_ENTERED = 0x02, @@ -522,129 +214,6 @@ enum { BINDER_LOOPER_STATE_POLL = 0x20, }; -/** - * struct binder_thread - binder thread bookkeeping - * @proc: binder process for this thread - * (invariant after initialization) - * @rb_node: element for proc->threads rbtree - * (protected by @proc->inner_lock) - * @waiting_thread_node: element for @proc->waiting_threads list - * (protected by @proc->inner_lock) - * @pid: PID for this thread - * (invariant after initialization) - * @looper: bitmap of looping state - * (only accessed by this thread) - * @looper_needs_return: looping thread needs to exit driver - * (no lock needed) - * @transaction_stack: stack of in-progress transactions for this thread - * (protected by @proc->inner_lock) - * @todo: list of work to do for this thread - * (protected by @proc->inner_lock) - * @process_todo: whether work in @todo should be processed - * (protected by @proc->inner_lock) - * @return_error: transaction errors reported by this thread - * (only accessed by this thread) - * @reply_error: transaction errors reported by target thread - * (protected by @proc->inner_lock) - * @wait: wait queue for thread work - * @stats: per-thread statistics - * (atomics, no lock needed) - * @tmp_ref: temporary reference to indicate thread is in use - * (atomic since @proc->inner_lock cannot - * always be acquired) - * @is_dead: thread is dead and awaiting free - * when outstanding transactions are cleaned up - * (protected by @proc->inner_lock) - * @task: struct task_struct for this thread - * - * Bookkeeping structure for binder threads. - */ -struct binder_thread { - struct binder_proc *proc; - struct rb_node rb_node; - struct list_head waiting_thread_node; - int pid; - int looper; /* only modified by this thread */ - bool looper_need_return; /* can be written by other thread */ - struct binder_transaction *transaction_stack; - struct list_head todo; - bool process_todo; - struct binder_error return_error; - struct binder_error reply_error; - wait_queue_head_t wait; - struct binder_stats stats; - atomic_t tmp_ref; - bool is_dead; - struct task_struct *task; -}; - -/** - * struct binder_txn_fd_fixup - transaction fd fixup list element - * @fixup_entry: list entry - * @file: struct file to be associated with new fd - * @offset: offset in buffer data to this fixup - * - * List element for fd fixups in a transaction. Since file - * descriptors need to be allocated in the context of the - * target process, we pass each fd to be processed in this - * struct. - */ -struct binder_txn_fd_fixup { - struct list_head fixup_entry; - struct file *file; - size_t offset; -}; - -struct binder_transaction { - int debug_id; - struct binder_work work; - struct binder_thread *from; - struct binder_transaction *from_parent; - struct binder_proc *to_proc; - struct binder_thread *to_thread; - struct binder_transaction *to_parent; - unsigned need_reply:1; - /* unsigned is_dead:1; */ /* not used at the moment */ - - struct binder_buffer *buffer; - unsigned int code; - unsigned int flags; - struct binder_priority priority; - struct binder_priority saved_priority; - bool set_priority_called; - kuid_t sender_euid; - struct list_head fd_fixups; - binder_uintptr_t security_ctx; - /** - * @lock: protects @from, @to_proc, and @to_thread - * - * @from, @to_proc, and @to_thread can be set to NULL - * during thread teardown - */ - spinlock_t lock; - ANDROID_VENDOR_DATA(1); -}; - -/** - * struct binder_object - union of flat binder object types - * @hdr: generic object header - * @fbo: binder object (nodes and refs) - * @fdo: file descriptor object - * @bbo: binder buffer pointer - * @fdao: file descriptor array - * - * Used for type-independent object copies - */ -struct binder_object { - union { - struct binder_object_header hdr; - struct flat_binder_object fbo; - struct binder_fd_object fdo; - struct binder_buffer_object bbo; - struct binder_fd_array_object fdao; - }; -}; - /** * binder_proc_lock() - Acquire outer lock for given binder_proc * @proc: struct binder_proc to acquire diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 283d3cb9c16e..9765fde875a5 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include "binder_alloc.h" struct binder_context { struct binder_node *binder_context_mgr_node; @@ -141,6 +143,435 @@ struct binder_transaction_log { struct binder_transaction_log_entry entry[32]; }; +enum binder_stat_types { + BINDER_STAT_PROC, + BINDER_STAT_THREAD, + BINDER_STAT_NODE, + BINDER_STAT_REF, + BINDER_STAT_DEATH, + BINDER_STAT_TRANSACTION, + BINDER_STAT_TRANSACTION_COMPLETE, + BINDER_STAT_COUNT +}; + +struct binder_stats { + atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; + atomic_t obj_created[BINDER_STAT_COUNT]; + atomic_t obj_deleted[BINDER_STAT_COUNT]; +}; + +/** + * struct binder_work - work enqueued on a worklist + * @entry: node enqueued on list + * @type: type of work to be performed + * + * There are separate work lists for proc, thread, and node (async). + */ +struct binder_work { + struct list_head entry; + + enum binder_work_type { + BINDER_WORK_TRANSACTION = 1, + BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_RETURN_ERROR, + BINDER_WORK_NODE, + BINDER_WORK_DEAD_BINDER, + BINDER_WORK_DEAD_BINDER_AND_CLEAR, + BINDER_WORK_CLEAR_DEATH_NOTIFICATION, + } type; +}; + +struct binder_error { + struct binder_work work; + uint32_t cmd; +}; + +/** + * struct binder_node - binder node bookkeeping + * @debug_id: unique ID for debugging + * (invariant after initialized) + * @lock: lock for node fields + * @work: worklist element for node work + * (protected by @proc->inner_lock) + * @rb_node: element for proc->nodes tree + * (protected by @proc->inner_lock) + * @dead_node: element for binder_dead_nodes list + * (protected by binder_dead_nodes_lock) + * @proc: binder_proc that owns this node + * (invariant after initialized) + * @refs: list of references on this node + * (protected by @lock) + * @internal_strong_refs: used to take strong references when + * initiating a transaction + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_weak_refs: weak user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_strong_refs: strong user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @tmp_refs: temporary kernel refs + * (protected by @proc->inner_lock while @proc + * is valid, and by binder_dead_nodes_lock + * if @proc is NULL. During inc/dec and node release + * it is also protected by @lock to provide safety + * as the node dies and @proc becomes NULL) + * @ptr: userspace pointer for node + * (invariant, no lock needed) + * @cookie: userspace cookie for node + * (invariant, no lock needed) + * @has_strong_ref: userspace notified of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_strong_ref: userspace has acked notification of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_weak_ref: userspace notified of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_weak_ref: userspace has acked notification of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_async_transaction: async transaction to node in progress + * (protected by @lock) + * @sched_policy: minimum scheduling policy for node + * (invariant after initialized) + * @accept_fds: file descriptor operations supported for node + * (invariant after initialized) + * @min_priority: minimum scheduling priority + * (invariant after initialized) + * @inherit_rt: inherit RT scheduling policy from caller + * @txn_security_ctx: require sender's security context + * (invariant after initialized) + * @async_todo: list of async work items + * (protected by @proc->inner_lock) + * + * Bookkeeping structure for binder nodes. + */ +struct binder_node { + int debug_id; + spinlock_t lock; + struct binder_work work; + union { + struct rb_node rb_node; + struct hlist_node dead_node; + }; + struct binder_proc *proc; + struct hlist_head refs; + int internal_strong_refs; + int local_weak_refs; + int local_strong_refs; + int tmp_refs; + binder_uintptr_t ptr; + binder_uintptr_t cookie; + struct { + /* + * bitfield elements protected by + * proc inner_lock + */ + u8 has_strong_ref:1; + u8 pending_strong_ref:1; + u8 has_weak_ref:1; + u8 pending_weak_ref:1; + }; + struct { + /* + * invariant after initialization + */ + u8 sched_policy:2; + u8 inherit_rt:1; + u8 accept_fds:1; + u8 txn_security_ctx:1; + u8 min_priority; + }; + bool has_async_transaction; + struct list_head async_todo; +}; + +struct binder_ref_death { + /** + * @work: worklist element for death notifications + * (protected by inner_lock of the proc that + * this ref belongs to) + */ + struct binder_work work; + binder_uintptr_t cookie; +}; + +/** + * struct binder_ref_data - binder_ref counts and id + * @debug_id: unique ID for the ref + * @desc: unique userspace handle for ref + * @strong: strong ref count (debugging only if not locked) + * @weak: weak ref count (debugging only if not locked) + * + * Structure to hold ref count and ref id information. Since + * the actual ref can only be accessed with a lock, this structure + * is used to return information about the ref to callers of + * ref inc/dec functions. + */ +struct binder_ref_data { + int debug_id; + uint32_t desc; + int strong; + int weak; +}; + +/** + * struct binder_ref - struct to track references on nodes + * @data: binder_ref_data containing id, handle, and current refcounts + * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree + * @rb_node_node: node for lookup by @node in proc's rb_tree + * @node_entry: list entry for node->refs list in target node + * (protected by @node->lock) + * @proc: binder_proc containing ref + * @node: binder_node of target node. When cleaning up a + * ref for deletion in binder_cleanup_ref, a non-NULL + * @node indicates the node must be freed + * @death: pointer to death notification (ref_death) if requested + * (protected by @node->lock) + * + * Structure to track references from procA to target node (on procB). This + * structure is unsafe to access without holding @proc->outer_lock. + */ +struct binder_ref { + /* Lookups needed: */ + /* node + proc => ref (transaction) */ + /* desc + proc => ref (transaction, inc/dec ref) */ + /* node => refs + procs (proc exit) */ + struct binder_ref_data data; + struct rb_node rb_node_desc; + struct rb_node rb_node_node; + struct hlist_node node_entry; + struct binder_proc *proc; + struct binder_node *node; + struct binder_ref_death *death; +}; + +/** + * struct binder_priority - scheduler policy and priority + * @sched_policy scheduler policy + * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT + * + * The binder driver supports inheriting the following scheduler policies: + * SCHED_NORMAL + * SCHED_BATCH + * SCHED_FIFO + * SCHED_RR + */ +struct binder_priority { + unsigned int sched_policy; + int prio; +}; + +/** + * struct binder_proc - binder process bookkeeping + * @proc_node: element for binder_procs list + * @threads: rbtree of binder_threads in this proc + * (protected by @inner_lock) + * @nodes: rbtree of binder nodes associated with + * this proc ordered by node->ptr + * (protected by @inner_lock) + * @refs_by_desc: rbtree of refs ordered by ref->desc + * (protected by @outer_lock) + * @refs_by_node: rbtree of refs ordered by ref->node + * (protected by @outer_lock) + * @waiting_threads: threads currently waiting for proc work + * (protected by @inner_lock) + * @pid PID of group_leader of process + * (invariant after initialized) + * @tsk task_struct for group_leader of process + * (invariant after initialized) + * @deferred_work_node: element for binder_deferred_list + * (protected by binder_deferred_lock) + * @deferred_work: bitmap of deferred work to perform + * (protected by binder_deferred_lock) + * @is_dead: process is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @inner_lock) + * @todo: list of work for this process + * (protected by @inner_lock) + * @stats: per-process binder statistics + * (atomics, no lock needed) + * @delivered_death: list of delivered death notification + * (protected by @inner_lock) + * @max_threads: cap on number of binder threads + * (protected by @inner_lock) + * @requested_threads: number of binder threads requested but not + * yet started. In current implementation, can + * only be 0 or 1. + * (protected by @inner_lock) + * @requested_threads_started: number binder threads started + * (protected by @inner_lock) + * @tmp_ref: temporary reference to indicate proc is in use + * (protected by @inner_lock) + * @default_priority: default scheduler priority + * (invariant after initialized) + * @debugfs_entry: debugfs node + * @alloc: binder allocator bookkeeping + * @context: binder_context for this proc + * (invariant after initialized) + * @inner_lock: can nest under outer_lock and/or node lock + * @outer_lock: no nesting under innor or node lock + * Lock order: 1) outer, 2) node, 3) inner + * @binderfs_entry: process-specific binderfs log file + * + * Bookkeeping structure for binder processes + */ +struct binder_proc { + struct hlist_node proc_node; + struct rb_root threads; + struct rb_root nodes; + struct rb_root refs_by_desc; + struct rb_root refs_by_node; + struct list_head waiting_threads; + int pid; + struct task_struct *tsk; + struct hlist_node deferred_work_node; + int deferred_work; + bool is_dead; + + struct list_head todo; + struct binder_stats stats; + struct list_head delivered_death; + int max_threads; + int requested_threads; + int requested_threads_started; + int tmp_ref; + struct binder_priority default_priority; + struct dentry *debugfs_entry; + struct binder_alloc alloc; + struct binder_context *context; + spinlock_t inner_lock; + spinlock_t outer_lock; + struct dentry *binderfs_entry; +}; + +/** + * struct binder_thread - binder thread bookkeeping + * @proc: binder process for this thread + * (invariant after initialization) + * @rb_node: element for proc->threads rbtree + * (protected by @proc->inner_lock) + * @waiting_thread_node: element for @proc->waiting_threads list + * (protected by @proc->inner_lock) + * @pid: PID for this thread + * (invariant after initialization) + * @looper: bitmap of looping state + * (only accessed by this thread) + * @looper_needs_return: looping thread needs to exit driver + * (no lock needed) + * @transaction_stack: stack of in-progress transactions for this thread + * (protected by @proc->inner_lock) + * @todo: list of work to do for this thread + * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) + * @return_error: transaction errors reported by this thread + * (only accessed by this thread) + * @reply_error: transaction errors reported by target thread + * (protected by @proc->inner_lock) + * @wait: wait queue for thread work + * @stats: per-thread statistics + * (atomics, no lock needed) + * @tmp_ref: temporary reference to indicate thread is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @is_dead: thread is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @proc->inner_lock) + * @task: struct task_struct for this thread + * + * Bookkeeping structure for binder threads. + */ +struct binder_thread { + struct binder_proc *proc; + struct rb_node rb_node; + struct list_head waiting_thread_node; + int pid; + int looper; /* only modified by this thread */ + bool looper_need_return; /* can be written by other thread */ + struct binder_transaction *transaction_stack; + struct list_head todo; + bool process_todo; + struct binder_error return_error; + struct binder_error reply_error; + wait_queue_head_t wait; + struct binder_stats stats; + atomic_t tmp_ref; + bool is_dead; + struct task_struct *task; +}; + +/** + * struct binder_txn_fd_fixup - transaction fd fixup list element + * @fixup_entry: list entry + * @file: struct file to be associated with new fd + * @offset: offset in buffer data to this fixup + * + * List element for fd fixups in a transaction. Since file + * descriptors need to be allocated in the context of the + * target process, we pass each fd to be processed in this + * struct. + */ +struct binder_txn_fd_fixup { + struct list_head fixup_entry; + struct file *file; + size_t offset; +}; + +struct binder_transaction { + int debug_id; + struct binder_work work; + struct binder_thread *from; + struct binder_transaction *from_parent; + struct binder_proc *to_proc; + struct binder_thread *to_thread; + struct binder_transaction *to_parent; + unsigned need_reply:1; + /* unsigned is_dead:1; */ /* not used at the moment */ + + struct binder_buffer *buffer; + unsigned int code; + unsigned int flags; + struct binder_priority priority; + struct binder_priority saved_priority; + bool set_priority_called; + kuid_t sender_euid; + struct list_head fd_fixups; + binder_uintptr_t security_ctx; + /** + * @lock: protects @from, @to_proc, and @to_thread + * + * @from, @to_proc, and @to_thread can be set to NULL + * during thread teardown + */ + spinlock_t lock; + ANDROID_VENDOR_DATA(1); +}; + +/** + * struct binder_object - union of flat binder object types + * @hdr: generic object header + * @fbo: binder object (nodes and refs) + * @fdo: file descriptor object + * @bbo: binder buffer pointer + * @fdao: file descriptor array + * + * Used for type-independent object copies + */ +struct binder_object { + union { + struct binder_object_header hdr; + struct flat_binder_object fbo; + struct binder_fd_object fdo; + struct binder_buffer_object bbo; + struct binder_fd_array_object fdao; + }; +}; + extern struct binder_transaction_log binder_transaction_log; extern struct binder_transaction_log binder_transaction_log_failed; #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 018fb7220d71..542158d9feb8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -846,6 +846,24 @@ config HID_PLANTRONICS Say M here if you may ever plug in a Plantronics USB audio device. +config HID_PLAYSTATION + tristate "PlayStation HID Driver" + depends on HID + select CRC32 + select POWER_SUPPLY + help + Provides support for Sony PS5 controllers including support for + its special functionalities e.g. touchpad, lights and motion + sensors. + +config PLAYSTATION_FF + bool "PlayStation force feedback support" + depends on HID_PLAYSTATION + select INPUT_FF_MEMLESS + help + Say Y here if you would like to enable force feedback support for + PlayStation game controllers. + config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index eee74c36617a..27595a35cc70 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -91,6 +91,7 @@ hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o +obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o obj-$(CONFIG_HID_RETRODE) += hid-retrode.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3b6c69e71f15..cf593f525a86 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1070,6 +1070,7 @@ #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc #define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0 +#define USB_DEVICE_ID_SONY_PS5_CONTROLLER 0x0ce6 #define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c new file mode 100644 index 000000000000..1c9216436768 --- /dev/null +++ b/drivers/hid/hid-playstation.c @@ -0,0 +1,1351 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for Sony DualSense(TM) controller. + * + * Copyright (c) 2020 Sony Interactive Entertainment + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hid-ids.h" + +/* List of connected playstation devices. */ +static DEFINE_MUTEX(ps_devices_lock); +static LIST_HEAD(ps_devices_list); + +static DEFINE_IDA(ps_player_id_allocator); + +#define HID_PLAYSTATION_VERSION_PATCH 0x8000 + +/* Base class for playstation devices. */ +struct ps_device { + struct list_head list; + struct hid_device *hdev; + spinlock_t lock; + + uint32_t player_id; + + struct power_supply_desc battery_desc; + struct power_supply *battery; + uint8_t battery_capacity; + int battery_status; + + uint8_t mac_address[6]; /* Note: stored in little endian order. */ + uint32_t hw_version; + uint32_t fw_version; + + int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size); +}; + +/* Calibration data for playstation motion sensors. */ +struct ps_calibration_data { + int abs_code; + short bias; + int sens_numer; + int sens_denom; +}; + +/* Seed values for DualShock4 / DualSense CRC32 for different report types. */ +#define PS_INPUT_CRC32_SEED 0xA1 +#define PS_OUTPUT_CRC32_SEED 0xA2 +#define PS_FEATURE_CRC32_SEED 0xA3 + +#define DS_INPUT_REPORT_USB 0x01 +#define DS_INPUT_REPORT_USB_SIZE 64 +#define DS_INPUT_REPORT_BT 0x31 +#define DS_INPUT_REPORT_BT_SIZE 78 +#define DS_OUTPUT_REPORT_USB 0x02 +#define DS_OUTPUT_REPORT_USB_SIZE 63 +#define DS_OUTPUT_REPORT_BT 0x31 +#define DS_OUTPUT_REPORT_BT_SIZE 78 + +#define DS_FEATURE_REPORT_CALIBRATION 0x05 +#define DS_FEATURE_REPORT_CALIBRATION_SIZE 41 +#define DS_FEATURE_REPORT_PAIRING_INFO 0x09 +#define DS_FEATURE_REPORT_PAIRING_INFO_SIZE 20 +#define DS_FEATURE_REPORT_FIRMWARE_INFO 0x20 +#define DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE 64 + +/* Button masks for DualSense input report. */ +#define DS_BUTTONS0_HAT_SWITCH GENMASK(3, 0) +#define DS_BUTTONS0_SQUARE BIT(4) +#define DS_BUTTONS0_CROSS BIT(5) +#define DS_BUTTONS0_CIRCLE BIT(6) +#define DS_BUTTONS0_TRIANGLE BIT(7) +#define DS_BUTTONS1_L1 BIT(0) +#define DS_BUTTONS1_R1 BIT(1) +#define DS_BUTTONS1_L2 BIT(2) +#define DS_BUTTONS1_R2 BIT(3) +#define DS_BUTTONS1_CREATE BIT(4) +#define DS_BUTTONS1_OPTIONS BIT(5) +#define DS_BUTTONS1_L3 BIT(6) +#define DS_BUTTONS1_R3 BIT(7) +#define DS_BUTTONS2_PS_HOME BIT(0) +#define DS_BUTTONS2_TOUCHPAD BIT(1) +#define DS_BUTTONS2_MIC_MUTE BIT(2) + +/* Status field of DualSense input report. */ +#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) +#define DS_STATUS_CHARGING GENMASK(7, 4) +#define DS_STATUS_CHARGING_SHIFT 4 + +/* + * Status of a DualSense touch point contact. + * Contact IDs, with highest bit set are 'inactive' + * and any associated data is then invalid. + */ +#define DS_TOUCH_POINT_INACTIVE BIT(7) + + /* Magic value required in tag field of Bluetooth output report. */ +#define DS_OUTPUT_TAG 0x10 +/* Flags for DualSense output report. */ +#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) +#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) +#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) +#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) +#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) +#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) +#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) + +/* DualSense hardware limits */ +#define DS_ACC_RES_PER_G 8192 +#define DS_ACC_RANGE (4*DS_ACC_RES_PER_G) +#define DS_GYRO_RES_PER_DEG_S 1024 +#define DS_GYRO_RANGE (2048*DS_GYRO_RES_PER_DEG_S) +#define DS_TOUCHPAD_WIDTH 1920 +#define DS_TOUCHPAD_HEIGHT 1080 + +struct dualsense { + struct ps_device base; + struct input_dev *gamepad; + struct input_dev *sensors; + struct input_dev *touchpad; + + /* Calibration data for accelerometer and gyroscope. */ + struct ps_calibration_data accel_calib_data[3]; + struct ps_calibration_data gyro_calib_data[3]; + + /* Timestamp for sensor data */ + bool sensor_timestamp_initialized; + uint32_t prev_sensor_timestamp; + uint32_t sensor_timestamp_us; + + /* Compatible rumble state */ + bool update_rumble; + uint8_t motor_left; + uint8_t motor_right; + + /* RGB lightbar */ + bool update_lightbar; + uint8_t lightbar_red; + uint8_t lightbar_green; + uint8_t lightbar_blue; + + /* Microphone */ + bool update_mic_mute; + bool mic_muted; + bool last_btn_mic_state; + + /* Player leds */ + bool update_player_leds; + uint8_t player_leds_state; + struct led_classdev player_leds[5]; + + struct work_struct output_worker; + void *output_report_dmabuf; + uint8_t output_seq; /* Sequence number for output report. */ +}; + +struct dualsense_touch_point { + uint8_t contact; + uint8_t x_lo; + uint8_t x_hi:4, y_lo:4; + uint8_t y_hi; +} __packed; +static_assert(sizeof(struct dualsense_touch_point) == 4); + +/* Main DualSense input report excluding any BT/USB specific headers. */ +struct dualsense_input_report { + uint8_t x, y; + uint8_t rx, ry; + uint8_t z, rz; + uint8_t seq_number; + uint8_t buttons[4]; + uint8_t reserved[4]; + + /* Motion sensors */ + __le16 gyro[3]; /* x, y, z */ + __le16 accel[3]; /* x, y, z */ + __le32 sensor_timestamp; + uint8_t reserved2; + + /* Touchpad */ + struct dualsense_touch_point points[2]; + + uint8_t reserved3[12]; + uint8_t status; + uint8_t reserved4[10]; +} __packed; +/* Common input report size shared equals the size of the USB report minus 1 byte for ReportID. */ +static_assert(sizeof(struct dualsense_input_report) == DS_INPUT_REPORT_USB_SIZE - 1); + +/* Common data between DualSense BT/USB main output report. */ +struct dualsense_output_report_common { + uint8_t valid_flag0; + uint8_t valid_flag1; + + /* For DualShock 4 compatibility mode. */ + uint8_t motor_right; + uint8_t motor_left; + + /* Audio controls */ + uint8_t reserved[4]; + uint8_t mute_button_led; + + uint8_t power_save_control; + uint8_t reserved2[28]; + + /* LEDs and lightbar */ + uint8_t valid_flag2; + uint8_t reserved3[2]; + uint8_t lightbar_setup; + uint8_t led_brightness; + uint8_t player_leds; + uint8_t lightbar_red; + uint8_t lightbar_green; + uint8_t lightbar_blue; +} __packed; +static_assert(sizeof(struct dualsense_output_report_common) == 47); + +struct dualsense_output_report_bt { + uint8_t report_id; /* 0x31 */ + uint8_t seq_tag; + uint8_t tag; + struct dualsense_output_report_common common; + uint8_t reserved[24]; + __le32 crc32; +} __packed; +static_assert(sizeof(struct dualsense_output_report_bt) == DS_OUTPUT_REPORT_BT_SIZE); + +struct dualsense_output_report_usb { + uint8_t report_id; /* 0x02 */ + struct dualsense_output_report_common common; + uint8_t reserved[15]; +} __packed; +static_assert(sizeof(struct dualsense_output_report_usb) == DS_OUTPUT_REPORT_USB_SIZE); + +/* + * The DualSense has a main output report used to control most features. It is + * largely the same between Bluetooth and USB except for different headers and CRC. + * This structure hide the differences between the two to simplify sending output reports. + */ +struct dualsense_output_report { + uint8_t *data; /* Start of data */ + uint8_t len; /* Size of output report */ + + /* Points to Bluetooth data payload in case for a Bluetooth report else NULL. */ + struct dualsense_output_report_bt *bt; + /* Points to USB data payload in case for a USB report else NULL. */ + struct dualsense_output_report_usb *usb; + /* Points to common section of report, so past any headers. */ + struct dualsense_output_report_common *common; +}; + +/* + * Common gamepad buttons across DualShock 3 / 4 and DualSense. + * Note: for device with a touchpad, touchpad button is not included + * as it will be part of the touchpad device. + */ +static const int ps_gamepad_buttons[] = { + BTN_WEST, /* Square */ + BTN_NORTH, /* Triangle */ + BTN_EAST, /* Circle */ + BTN_SOUTH, /* Cross */ + BTN_TL, /* L1 */ + BTN_TR, /* R1 */ + BTN_TL2, /* L2 */ + BTN_TR2, /* R2 */ + BTN_SELECT, /* Create (PS5) / Share (PS4) */ + BTN_START, /* Option */ + BTN_THUMBL, /* L3 */ + BTN_THUMBR, /* R3 */ + BTN_MODE, /* PS Home */ +}; + +static const struct {int x; int y; } ps_gamepad_hat_mapping[] = { + {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, + {0, 0}, +}; + +/* + * Add a new ps_device to ps_devices if it doesn't exist. + * Return error on duplicate device, which can happen if the same + * device is connected using both Bluetooth and USB. + */ +static int ps_devices_list_add(struct ps_device *dev) +{ + struct ps_device *entry; + + mutex_lock(&ps_devices_lock); + list_for_each_entry(entry, &ps_devices_list, list) { + if (!memcmp(entry->mac_address, dev->mac_address, sizeof(dev->mac_address))) { + hid_err(dev->hdev, "Duplicate device found for MAC address %pMR.\n", + dev->mac_address); + mutex_unlock(&ps_devices_lock); + return -EEXIST; + } + } + + list_add_tail(&dev->list, &ps_devices_list); + mutex_unlock(&ps_devices_lock); + return 0; +} + +static int ps_devices_list_remove(struct ps_device *dev) +{ + mutex_lock(&ps_devices_lock); + list_del(&dev->list); + mutex_unlock(&ps_devices_lock); + return 0; +} + +static int ps_device_set_player_id(struct ps_device *dev) +{ + int ret = ida_alloc(&ps_player_id_allocator, GFP_KERNEL); + + if (ret < 0) + return ret; + + dev->player_id = ret; + return 0; +} + +static void ps_device_release_player_id(struct ps_device *dev) +{ + ida_free(&ps_player_id_allocator, dev->player_id); + + dev->player_id = U32_MAX; +} + +static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const char *name_suffix) +{ + struct input_dev *input_dev; + + input_dev = devm_input_allocate_device(&hdev->dev); + if (!input_dev) + return ERR_PTR(-ENOMEM); + + input_dev->id.bustype = hdev->bus; + input_dev->id.vendor = hdev->vendor; + input_dev->id.product = hdev->product; + input_dev->id.version = hdev->version; + input_dev->uniq = hdev->uniq; + + if (name_suffix) { + input_dev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name, + name_suffix); + if (!input_dev->name) + return ERR_PTR(-ENOMEM); + } else { + input_dev->name = hdev->name; + } + + input_set_drvdata(input_dev, hdev); + + return input_dev; +} + +static enum power_supply_property ps_power_supply_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_SCOPE, +}; + +static int ps_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct ps_device *dev = power_supply_get_drvdata(psy); + uint8_t battery_capacity; + int battery_status; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dev->lock, flags); + battery_capacity = dev->battery_capacity; + battery_status = dev->battery_status; + spin_unlock_irqrestore(&dev->lock, flags); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = battery_status; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = battery_capacity; + break; + case POWER_SUPPLY_PROP_SCOPE: + val->intval = POWER_SUPPLY_SCOPE_DEVICE; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ps_device_register_battery(struct ps_device *dev) +{ + struct power_supply *battery; + struct power_supply_config battery_cfg = { .drv_data = dev }; + int ret; + + dev->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; + dev->battery_desc.properties = ps_power_supply_props; + dev->battery_desc.num_properties = ARRAY_SIZE(ps_power_supply_props); + dev->battery_desc.get_property = ps_battery_get_property; + dev->battery_desc.name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL, + "ps-controller-battery-%pMR", dev->mac_address); + if (!dev->battery_desc.name) + return -ENOMEM; + + battery = devm_power_supply_register(&dev->hdev->dev, &dev->battery_desc, &battery_cfg); + if (IS_ERR(battery)) { + ret = PTR_ERR(battery); + hid_err(dev->hdev, "Unable to register battery device: %d\n", ret); + return ret; + } + dev->battery = battery; + + ret = power_supply_powers(dev->battery, &dev->hdev->dev); + if (ret) { + hid_err(dev->hdev, "Unable to activate battery device: %d\n", ret); + return ret; + } + + return 0; +} + +/* Compute crc32 of HID data and compare against expected CRC. */ +static bool ps_check_crc32(uint8_t seed, uint8_t *data, size_t len, uint32_t report_crc) +{ + uint32_t crc; + + crc = crc32_le(0xFFFFFFFF, &seed, 1); + crc = ~crc32_le(crc, data, len); + + return crc == report_crc; +} + +static struct input_dev *ps_gamepad_create(struct hid_device *hdev, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) +{ + struct input_dev *gamepad; + unsigned int i; + int ret; + + gamepad = ps_allocate_input_dev(hdev, NULL); + if (IS_ERR(gamepad)) + return ERR_CAST(gamepad); + + input_set_abs_params(gamepad, ABS_X, 0, 255, 0, 0); + input_set_abs_params(gamepad, ABS_Y, 0, 255, 0, 0); + input_set_abs_params(gamepad, ABS_Z, 0, 255, 0, 0); + input_set_abs_params(gamepad, ABS_RX, 0, 255, 0, 0); + input_set_abs_params(gamepad, ABS_RY, 0, 255, 0, 0); + input_set_abs_params(gamepad, ABS_RZ, 0, 255, 0, 0); + + input_set_abs_params(gamepad, ABS_HAT0X, -1, 1, 0, 0); + input_set_abs_params(gamepad, ABS_HAT0Y, -1, 1, 0, 0); + + for (i = 0; i < ARRAY_SIZE(ps_gamepad_buttons); i++) + input_set_capability(gamepad, EV_KEY, ps_gamepad_buttons[i]); + +#if IS_ENABLED(CONFIG_PLAYSTATION_FF) + if (play_effect) { + input_set_capability(gamepad, EV_FF, FF_RUMBLE); + input_ff_create_memless(gamepad, NULL, play_effect); + } +#endif + + ret = input_register_device(gamepad); + if (ret) + return ERR_PTR(ret); + + return gamepad; +} + +static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *buf, size_t size) +{ + int ret; + + ret = hid_hw_raw_request(hdev, report_id, buf, size, HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) { + hid_err(hdev, "Failed to retrieve feature with reportID %d: %d\n", report_id, ret); + return ret; + } + + if (ret != size) { + hid_err(hdev, "Invalid byte count transferred, expected %zu got %d\n", size, ret); + return -EINVAL; + } + + if (buf[0] != report_id) { + hid_err(hdev, "Invalid reportID received, expected %d got %d\n", report_id, buf[0]); + return -EINVAL; + } + + if (hdev->bus == BUS_BLUETOOTH) { + /* Last 4 bytes contains crc32. */ + uint8_t crc_offset = size - 4; + uint32_t report_crc = get_unaligned_le32(&buf[crc_offset]); + + if (!ps_check_crc32(PS_FEATURE_CRC32_SEED, buf, crc_offset, report_crc)) { + hid_err(hdev, "CRC check failed for reportID=%d\n", report_id); + return -EILSEQ; + } + } + + return 0; +} + +static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, int accel_res, + int gyro_range, int gyro_res) +{ + struct input_dev *sensors; + int ret; + + sensors = ps_allocate_input_dev(hdev, "Motion Sensors"); + if (IS_ERR(sensors)) + return ERR_CAST(sensors); + + __set_bit(INPUT_PROP_ACCELEROMETER, sensors->propbit); + __set_bit(EV_MSC, sensors->evbit); + __set_bit(MSC_TIMESTAMP, sensors->mscbit); + + /* Accelerometer */ + input_set_abs_params(sensors, ABS_X, -accel_range, accel_range, 16, 0); + input_set_abs_params(sensors, ABS_Y, -accel_range, accel_range, 16, 0); + input_set_abs_params(sensors, ABS_Z, -accel_range, accel_range, 16, 0); + input_abs_set_res(sensors, ABS_X, accel_res); + input_abs_set_res(sensors, ABS_Y, accel_res); + input_abs_set_res(sensors, ABS_Z, accel_res); + + /* Gyroscope */ + input_set_abs_params(sensors, ABS_RX, -gyro_range, gyro_range, 16, 0); + input_set_abs_params(sensors, ABS_RY, -gyro_range, gyro_range, 16, 0); + input_set_abs_params(sensors, ABS_RZ, -gyro_range, gyro_range, 16, 0); + input_abs_set_res(sensors, ABS_RX, gyro_res); + input_abs_set_res(sensors, ABS_RY, gyro_res); + input_abs_set_res(sensors, ABS_RZ, gyro_res); + + ret = input_register_device(sensors); + if (ret) + return ERR_PTR(ret); + + return sensors; +} + +static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, int height, + unsigned int num_contacts) +{ + struct input_dev *touchpad; + int ret; + + touchpad = ps_allocate_input_dev(hdev, "Touchpad"); + if (IS_ERR(touchpad)) + return ERR_CAST(touchpad); + + /* Map button underneath touchpad to BTN_LEFT. */ + input_set_capability(touchpad, EV_KEY, BTN_LEFT); + __set_bit(INPUT_PROP_BUTTONPAD, touchpad->propbit); + + input_set_abs_params(touchpad, ABS_MT_POSITION_X, 0, width - 1, 0, 0); + input_set_abs_params(touchpad, ABS_MT_POSITION_Y, 0, height - 1, 0, 0); + + ret = input_mt_init_slots(touchpad, num_contacts, INPUT_MT_POINTER); + if (ret) + return ERR_PTR(ret); + + ret = input_register_device(touchpad); + if (ret) + return ERR_PTR(ret); + + return touchpad; +} + +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute + *attr, char *buf) +{ + struct hid_device *hdev = to_hid_device(dev); + struct ps_device *ps_dev = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "0x%08x\n", ps_dev->fw_version); +} + +static DEVICE_ATTR_RO(firmware_version); + +static ssize_t hardware_version_show(struct device *dev, + struct device_attribute + *attr, char *buf) +{ + struct hid_device *hdev = to_hid_device(dev); + struct ps_device *ps_dev = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "0x%08x\n", ps_dev->hw_version); +} + +static DEVICE_ATTR_RO(hardware_version); + +static struct attribute *ps_device_attributes[] = { + &dev_attr_firmware_version.attr, + &dev_attr_hardware_version.attr, + NULL +}; + +static const struct attribute_group ps_device_attribute_group = { + .attrs = ps_device_attributes, +}; + +static int dualsense_get_calibration_data(struct dualsense *ds) +{ + short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; + short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus; + short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus; + short gyro_speed_plus, gyro_speed_minus; + short acc_x_plus, acc_x_minus; + short acc_y_plus, acc_y_minus; + short acc_z_plus, acc_z_minus; + int speed_2x; + int range_2g; + int ret = 0; + uint8_t *buf; + + buf = kzalloc(DS_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_CALIBRATION, buf, + DS_FEATURE_REPORT_CALIBRATION_SIZE); + if (ret) { + hid_err(ds->base.hdev, "Failed to retrieve DualSense calibration info: %d\n", ret); + goto err_free; + } + + gyro_pitch_bias = get_unaligned_le16(&buf[1]); + gyro_yaw_bias = get_unaligned_le16(&buf[3]); + gyro_roll_bias = get_unaligned_le16(&buf[5]); + gyro_pitch_plus = get_unaligned_le16(&buf[7]); + gyro_pitch_minus = get_unaligned_le16(&buf[9]); + gyro_yaw_plus = get_unaligned_le16(&buf[11]); + gyro_yaw_minus = get_unaligned_le16(&buf[13]); + gyro_roll_plus = get_unaligned_le16(&buf[15]); + gyro_roll_minus = get_unaligned_le16(&buf[17]); + gyro_speed_plus = get_unaligned_le16(&buf[19]); + gyro_speed_minus = get_unaligned_le16(&buf[21]); + acc_x_plus = get_unaligned_le16(&buf[23]); + acc_x_minus = get_unaligned_le16(&buf[25]); + acc_y_plus = get_unaligned_le16(&buf[27]); + acc_y_minus = get_unaligned_le16(&buf[29]); + acc_z_plus = get_unaligned_le16(&buf[31]); + acc_z_minus = get_unaligned_le16(&buf[33]); + + /* + * Set gyroscope calibration and normalization parameters. + * Data values will be normalized to 1/DS_GYRO_RES_PER_DEG_S degree/s. + */ + speed_2x = (gyro_speed_plus + gyro_speed_minus); + ds->gyro_calib_data[0].abs_code = ABS_RX; + ds->gyro_calib_data[0].bias = gyro_pitch_bias; + ds->gyro_calib_data[0].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus; + + ds->gyro_calib_data[1].abs_code = ABS_RY; + ds->gyro_calib_data[1].bias = gyro_yaw_bias; + ds->gyro_calib_data[1].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus; + + ds->gyro_calib_data[2].abs_code = ABS_RZ; + ds->gyro_calib_data[2].bias = gyro_roll_bias; + ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; + + /* + * Set accelerometer calibration and normalization parameters. + * Data values will be normalized to 1/DS_ACC_RES_PER_G g. + */ + range_2g = acc_x_plus - acc_x_minus; + ds->accel_calib_data[0].abs_code = ABS_X; + ds->accel_calib_data[0].bias = acc_x_plus - range_2g / 2; + ds->accel_calib_data[0].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[0].sens_denom = range_2g; + + range_2g = acc_y_plus - acc_y_minus; + ds->accel_calib_data[1].abs_code = ABS_Y; + ds->accel_calib_data[1].bias = acc_y_plus - range_2g / 2; + ds->accel_calib_data[1].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[1].sens_denom = range_2g; + + range_2g = acc_z_plus - acc_z_minus; + ds->accel_calib_data[2].abs_code = ABS_Z; + ds->accel_calib_data[2].bias = acc_z_plus - range_2g / 2; + ds->accel_calib_data[2].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[2].sens_denom = range_2g; + +err_free: + kfree(buf); + return ret; +} + +static int dualsense_get_firmware_info(struct dualsense *ds) +{ + uint8_t *buf; + int ret; + + buf = kzalloc(DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_FIRMWARE_INFO, buf, + DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE); + if (ret) { + hid_err(ds->base.hdev, "Failed to retrieve DualSense firmware info: %d\n", ret); + goto err_free; + } + + ds->base.hw_version = get_unaligned_le32(&buf[24]); + ds->base.fw_version = get_unaligned_le32(&buf[28]); + +err_free: + kfree(buf); + return ret; +} + +static int dualsense_get_mac_address(struct dualsense *ds) +{ + uint8_t *buf; + int ret = 0; + + buf = kzalloc(DS_FEATURE_REPORT_PAIRING_INFO_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_PAIRING_INFO, buf, + DS_FEATURE_REPORT_PAIRING_INFO_SIZE); + if (ret) { + hid_err(ds->base.hdev, "Failed to retrieve DualSense pairing info: %d\n", ret); + goto err_free; + } + + memcpy(ds->base.mac_address, &buf[1], sizeof(ds->base.mac_address)); + +err_free: + kfree(buf); + return ret; +} + +static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, + void *buf) +{ + struct hid_device *hdev = ds->base.hdev; + + if (hdev->bus == BUS_BLUETOOTH) { + struct dualsense_output_report_bt *bt = buf; + + memset(bt, 0, sizeof(*bt)); + bt->report_id = DS_OUTPUT_REPORT_BT; + bt->tag = DS_OUTPUT_TAG; /* Tag must be set. Exact meaning is unclear. */ + + /* + * Highest 4-bit is a sequence number, which needs to be increased + * every report. Lowest 4-bit is tag and can be zero for now. + */ + bt->seq_tag = (ds->output_seq << 4) | 0x0; + if (++ds->output_seq == 16) + ds->output_seq = 0; + + rp->data = buf; + rp->len = sizeof(*bt); + rp->bt = bt; + rp->usb = NULL; + rp->common = &bt->common; + } else { /* USB */ + struct dualsense_output_report_usb *usb = buf; + + memset(usb, 0, sizeof(*usb)); + usb->report_id = DS_OUTPUT_REPORT_USB; + + rp->data = buf; + rp->len = sizeof(*usb); + rp->bt = NULL; + rp->usb = usb; + rp->common = &usb->common; + } +} + +/* + * Helper function to send DualSense output reports. Applies a CRC at the end of a report + * for Bluetooth reports. + */ +static void dualsense_send_output_report(struct dualsense *ds, + struct dualsense_output_report *report) +{ + struct hid_device *hdev = ds->base.hdev; + + /* Bluetooth packets need to be signed with a CRC in the last 4 bytes. */ + if (report->bt) { + uint32_t crc; + uint8_t seed = PS_OUTPUT_CRC32_SEED; + + crc = crc32_le(0xFFFFFFFF, &seed, 1); + crc = ~crc32_le(crc, report->data, report->len - 4); + + report->bt->crc32 = cpu_to_le32(crc); + } + + hid_hw_output_report(hdev, report->data, report->len); +} + +static void dualsense_output_worker(struct work_struct *work) +{ + struct dualsense *ds = container_of(work, struct dualsense, output_worker); + struct dualsense_output_report report; + struct dualsense_output_report_common *common; + unsigned long flags; + + dualsense_init_output_report(ds, &report, ds->output_report_dmabuf); + common = report.common; + + spin_lock_irqsave(&ds->base.lock, flags); + + if (ds->update_rumble) { + /* Select classic rumble style haptics and enable it. */ + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION; + common->motor_left = ds->motor_left; + common->motor_right = ds->motor_right; + ds->update_rumble = false; + } + + if (ds->update_lightbar) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE; + common->lightbar_red = ds->lightbar_red; + common->lightbar_green = ds->lightbar_green; + common->lightbar_blue = ds->lightbar_blue; + + ds->update_lightbar = false; + } + + if (ds->update_player_leds) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE; + common->player_leds = ds->player_leds_state; + + ds->update_player_leds = false; + } + + if (ds->update_mic_mute) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; + common->mute_button_led = ds->mic_muted; + + if (ds->mic_muted) { + /* Disable microphone */ + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control |= DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } else { + /* Enable microphone */ + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control &= ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } + + ds->update_mic_mute = false; + } + + spin_unlock_irqrestore(&ds->base.lock, flags); + + dualsense_send_output_report(ds, &report); +} + +static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *report, + u8 *data, int size) +{ + struct hid_device *hdev = ps_dev->hdev; + struct dualsense *ds = container_of(ps_dev, struct dualsense, base); + struct dualsense_input_report *ds_report; + uint8_t battery_data, battery_capacity, charging_status, value; + int battery_status; + uint32_t sensor_timestamp; + bool btn_mic_state; + unsigned long flags; + int i; + + /* + * DualSense in USB uses the full HID report for reportID 1, but + * Bluetooth uses a minimal HID report for reportID 1 and reports + * the full report using reportID 49. + */ + if (hdev->bus == BUS_USB && report->id == DS_INPUT_REPORT_USB && + size == DS_INPUT_REPORT_USB_SIZE) { + ds_report = (struct dualsense_input_report *)&data[1]; + } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS_INPUT_REPORT_BT && + size == DS_INPUT_REPORT_BT_SIZE) { + /* Last 4 bytes of input report contain crc32 */ + uint32_t report_crc = get_unaligned_le32(&data[size - 4]); + + if (!ps_check_crc32(PS_INPUT_CRC32_SEED, data, size - 4, report_crc)) { + hid_err(hdev, "DualSense input CRC's check failed\n"); + return -EILSEQ; + } + + ds_report = (struct dualsense_input_report *)&data[2]; + } else { + hid_err(hdev, "Unhandled reportID=%d\n", report->id); + return -1; + } + + input_report_abs(ds->gamepad, ABS_X, ds_report->x); + input_report_abs(ds->gamepad, ABS_Y, ds_report->y); + input_report_abs(ds->gamepad, ABS_RX, ds_report->rx); + input_report_abs(ds->gamepad, ABS_RY, ds_report->ry); + input_report_abs(ds->gamepad, ABS_Z, ds_report->z); + input_report_abs(ds->gamepad, ABS_RZ, ds_report->rz); + + value = ds_report->buttons[0] & DS_BUTTONS0_HAT_SWITCH; + if (value >= ARRAY_SIZE(ps_gamepad_hat_mapping)) + value = 8; /* center */ + input_report_abs(ds->gamepad, ABS_HAT0X, ps_gamepad_hat_mapping[value].x); + input_report_abs(ds->gamepad, ABS_HAT0Y, ps_gamepad_hat_mapping[value].y); + + input_report_key(ds->gamepad, BTN_WEST, ds_report->buttons[0] & DS_BUTTONS0_SQUARE); + input_report_key(ds->gamepad, BTN_SOUTH, ds_report->buttons[0] & DS_BUTTONS0_CROSS); + input_report_key(ds->gamepad, BTN_EAST, ds_report->buttons[0] & DS_BUTTONS0_CIRCLE); + input_report_key(ds->gamepad, BTN_NORTH, ds_report->buttons[0] & DS_BUTTONS0_TRIANGLE); + input_report_key(ds->gamepad, BTN_TL, ds_report->buttons[1] & DS_BUTTONS1_L1); + input_report_key(ds->gamepad, BTN_TR, ds_report->buttons[1] & DS_BUTTONS1_R1); + input_report_key(ds->gamepad, BTN_TL2, ds_report->buttons[1] & DS_BUTTONS1_L2); + input_report_key(ds->gamepad, BTN_TR2, ds_report->buttons[1] & DS_BUTTONS1_R2); + input_report_key(ds->gamepad, BTN_SELECT, ds_report->buttons[1] & DS_BUTTONS1_CREATE); + input_report_key(ds->gamepad, BTN_START, ds_report->buttons[1] & DS_BUTTONS1_OPTIONS); + input_report_key(ds->gamepad, BTN_THUMBL, ds_report->buttons[1] & DS_BUTTONS1_L3); + input_report_key(ds->gamepad, BTN_THUMBR, ds_report->buttons[1] & DS_BUTTONS1_R3); + input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME); + input_sync(ds->gamepad); + + /* + * The DualSense has an internal microphone, which can be muted through a mute button + * on the device. The driver is expected to read the button state and program the device + * to mute/unmute audio at the hardware level. + */ + btn_mic_state = !!(ds_report->buttons[2] & DS_BUTTONS2_MIC_MUTE); + if (btn_mic_state && !ds->last_btn_mic_state) { + spin_lock_irqsave(&ps_dev->lock, flags); + ds->update_mic_mute = true; + ds->mic_muted = !ds->mic_muted; /* toggle */ + spin_unlock_irqrestore(&ps_dev->lock, flags); + + /* Schedule updating of microphone state at hardware level. */ + schedule_work(&ds->output_worker); + } + ds->last_btn_mic_state = btn_mic_state; + + /* Parse and calibrate gyroscope data. */ + for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) { + int raw_data = (short)le16_to_cpu(ds_report->gyro[i]); + int calib_data = mult_frac(ds->gyro_calib_data[i].sens_numer, + raw_data - ds->gyro_calib_data[i].bias, + ds->gyro_calib_data[i].sens_denom); + + input_report_abs(ds->sensors, ds->gyro_calib_data[i].abs_code, calib_data); + } + + /* Parse and calibrate accelerometer data. */ + for (i = 0; i < ARRAY_SIZE(ds_report->accel); i++) { + int raw_data = (short)le16_to_cpu(ds_report->accel[i]); + int calib_data = mult_frac(ds->accel_calib_data[i].sens_numer, + raw_data - ds->accel_calib_data[i].bias, + ds->accel_calib_data[i].sens_denom); + + input_report_abs(ds->sensors, ds->accel_calib_data[i].abs_code, calib_data); + } + + /* Convert timestamp (in 0.33us unit) to timestamp_us */ + sensor_timestamp = le32_to_cpu(ds_report->sensor_timestamp); + if (!ds->sensor_timestamp_initialized) { + ds->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp, 3); + ds->sensor_timestamp_initialized = true; + } else { + uint32_t delta; + + if (ds->prev_sensor_timestamp > sensor_timestamp) + delta = (U32_MAX - ds->prev_sensor_timestamp + sensor_timestamp + 1); + else + delta = sensor_timestamp - ds->prev_sensor_timestamp; + ds->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta, 3); + } + ds->prev_sensor_timestamp = sensor_timestamp; + input_event(ds->sensors, EV_MSC, MSC_TIMESTAMP, ds->sensor_timestamp_us); + input_sync(ds->sensors); + + for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) { + struct dualsense_touch_point *point = &ds_report->points[i]; + bool active = (point->contact & DS_TOUCH_POINT_INACTIVE) ? false : true; + + input_mt_slot(ds->touchpad, i); + input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active); + + if (active) { + int x = (point->x_hi << 8) | point->x_lo; + int y = (point->y_hi << 4) | point->y_lo; + + input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y); + } + } + input_mt_sync_frame(ds->touchpad); + input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); + input_sync(ds->touchpad); + + battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY; + charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT; + + switch (charging_status) { + case 0x0: + /* + * Each unit of battery data corresponds to 10% + * 0 = 0-9%, 1 = 10-19%, .. and 10 = 100% + */ + battery_capacity = min(battery_data * 10 + 5, 100); + battery_status = POWER_SUPPLY_STATUS_DISCHARGING; + break; + case 0x1: + battery_capacity = min(battery_data * 10 + 5, 100); + battery_status = POWER_SUPPLY_STATUS_CHARGING; + break; + case 0x2: + battery_capacity = 100; + battery_status = POWER_SUPPLY_STATUS_FULL; + break; + case 0xa: /* voltage or temperature out of range */ + case 0xb: /* temperature error */ + battery_capacity = 0; + battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case 0xf: /* charging error */ + default: + battery_capacity = 0; + battery_status = POWER_SUPPLY_STATUS_UNKNOWN; + } + + spin_lock_irqsave(&ps_dev->lock, flags); + ps_dev->battery_capacity = battery_capacity; + ps_dev->battery_status = battery_status; + spin_unlock_irqrestore(&ps_dev->lock, flags); + + return 0; +} + +static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct hid_device *hdev = input_get_drvdata(dev); + struct dualsense *ds = hid_get_drvdata(hdev); + unsigned long flags; + + if (effect->type != FF_RUMBLE) + return 0; + + spin_lock_irqsave(&ds->base.lock, flags); + ds->update_rumble = true; + ds->motor_left = effect->u.rumble.strong_magnitude / 256; + ds->motor_right = effect->u.rumble.weak_magnitude / 256; + spin_unlock_irqrestore(&ds->base.lock, flags); + + schedule_work(&ds->output_worker); + return 0; +} + +static int dualsense_reset_leds(struct dualsense *ds) +{ + struct dualsense_output_report report; + uint8_t *buf; + + buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dualsense_init_output_report(ds, &report, buf); + /* + * On Bluetooth the DualSense outputs an animation on the lightbar + * during startup and maintains a color afterwards. We need to explicitly + * reconfigure the lightbar before we can do any programming later on. + * In USB the lightbar is not on by default, but redoing the setup there + * doesn't hurt. + */ + report.common->valid_flag2 = DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE; + report.common->lightbar_setup = DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT; /* Fade light out. */ + dualsense_send_output_report(ds, &report); + + kfree(buf); + return 0; +} + +static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue) +{ + ds->update_lightbar = true; + ds->lightbar_red = red; + ds->lightbar_green = green; + ds->lightbar_blue = blue; + + schedule_work(&ds->output_worker); +} + +static void dualsense_set_player_leds(struct dualsense *ds) +{ + /* + * The DualSense controller has a row of 5 LEDs used for player ids. + * Behavior on the PlayStation 5 console is to center the player id + * across the LEDs, so e.g. player 1 would be "--x--" with x being 'on'. + * Follow a similar mapping here. + */ + static const int player_ids[5] = { + BIT(2), + BIT(3) | BIT(1), + BIT(4) | BIT(2) | BIT(0), + BIT(4) | BIT(3) | BIT(1) | BIT(0), + BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0) + }; + + uint8_t player_id = ds->base.player_id % ARRAY_SIZE(player_ids); + + ds->update_player_leds = true; + ds->player_leds_state = player_ids[player_id]; + schedule_work(&ds->output_worker); +} + +static struct ps_device *dualsense_create(struct hid_device *hdev) +{ + struct dualsense *ds; + struct ps_device *ps_dev; + uint8_t max_output_report_size; + int ret; + + ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL); + if (!ds) + return ERR_PTR(-ENOMEM); + + /* + * Patch version to allow userspace to distinguish between + * hid-generic vs hid-playstation axis and button mapping. + */ + hdev->version |= HID_PLAYSTATION_VERSION_PATCH; + + ps_dev = &ds->base; + ps_dev->hdev = hdev; + spin_lock_init(&ps_dev->lock); + ps_dev->battery_capacity = 100; /* initial value until parse_report. */ + ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN; + ps_dev->parse_report = dualsense_parse_report; + INIT_WORK(&ds->output_worker, dualsense_output_worker); + hid_set_drvdata(hdev, ds); + + max_output_report_size = sizeof(struct dualsense_output_report_bt); + ds->output_report_dmabuf = devm_kzalloc(&hdev->dev, max_output_report_size, GFP_KERNEL); + if (!ds->output_report_dmabuf) + return ERR_PTR(-ENOMEM); + + ret = dualsense_get_mac_address(ds); + if (ret) { + hid_err(hdev, "Failed to get MAC address from DualSense\n"); + return ERR_PTR(ret); + } + snprintf(hdev->uniq, sizeof(hdev->uniq), "%pMR", ds->base.mac_address); + + ret = dualsense_get_firmware_info(ds); + if (ret) { + hid_err(hdev, "Failed to get firmware info from DualSense\n"); + return ERR_PTR(ret); + } + + ret = ps_devices_list_add(ps_dev); + if (ret) + return ERR_PTR(ret); + + ret = dualsense_get_calibration_data(ds); + if (ret) { + hid_err(hdev, "Failed to get calibration data from DualSense\n"); + goto err; + } + + ds->gamepad = ps_gamepad_create(hdev, dualsense_play_effect); + if (IS_ERR(ds->gamepad)) { + ret = PTR_ERR(ds->gamepad); + goto err; + } + + ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G, + DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); + if (IS_ERR(ds->sensors)) { + ret = PTR_ERR(ds->sensors); + goto err; + } + + ds->touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2); + if (IS_ERR(ds->touchpad)) { + ret = PTR_ERR(ds->touchpad); + goto err; + } + + ret = ps_device_register_battery(ps_dev); + if (ret) + goto err; + + /* + * The hardware may have control over the LEDs (e.g. in Bluetooth on startup). + * Reset the LEDs (lightbar, mute, player leds), so we can control them + * from software. + */ + ret = dualsense_reset_leds(ds); + if (ret) + goto err; + + dualsense_set_lightbar(ds, 0, 0, 128); /* blue */ + + ret = ps_device_set_player_id(ps_dev); + if (ret) { + hid_err(hdev, "Failed to assign player id for DualSense: %d\n", ret); + goto err; + } + + /* Set player LEDs to our player id. */ + dualsense_set_player_leds(ds); + + /* + * Reporting hardware and firmware is important as there are frequent updates, which + * can change behavior. + */ + hid_info(hdev, "Registered DualSense controller hw_version=0x%08x fw_version=0x%08x\n", + ds->base.hw_version, ds->base.fw_version); + + return &ds->base; + +err: + ps_devices_list_remove(ps_dev); + return ERR_PTR(ret); +} + +static int ps_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + struct ps_device *dev = hid_get_drvdata(hdev); + + if (dev && dev->parse_report) + return dev->parse_report(dev, report, data, size); + + return 0; +} + +static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct ps_device *dev; + int ret; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "Parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "Failed to start HID device\n"); + return ret; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "Failed to open HID device\n"); + goto err_stop; + } + + if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) { + dev = dualsense_create(hdev); + if (IS_ERR(dev)) { + hid_err(hdev, "Failed to create dualsense.\n"); + ret = PTR_ERR(dev); + goto err_close; + } + } + + ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group); + if (ret) { + hid_err(hdev, "Failed to register sysfs nodes.\n"); + goto err_close; + } + + return ret; + +err_close: + hid_hw_close(hdev); +err_stop: + hid_hw_stop(hdev); + return ret; +} + +static void ps_remove(struct hid_device *hdev) +{ + struct ps_device *dev = hid_get_drvdata(hdev); + + ps_devices_list_remove(dev); + ps_device_release_player_id(dev); + + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id ps_devices[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ps_devices); + +static struct hid_driver ps_driver = { + .name = "playstation", + .id_table = ps_devices, + .probe = ps_probe, + .remove = ps_remove, + .raw_event = ps_raw_event, +}; + +static int __init ps_init(void) +{ + return hid_register_driver(&ps_driver); +} + +static void __exit ps_exit(void) +{ + hid_unregister_driver(&ps_driver); + ida_destroy(&ps_player_id_allocator); +} + +module_init(ps_init); +module_exit(ps_exit); + +MODULE_AUTHOR("Sony Interactive Entertainment"); +MODULE_DESCRIPTION("HID Driver for PlayStation peripherals."); +MODULE_LICENSE("GPL"); diff --git a/fs/OWNERS b/fs/OWNERS new file mode 100644 index 000000000000..a838344a1137 --- /dev/null +++ b/fs/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/fs/OWNERS diff --git a/fs/f2fs/OWNERS b/fs/f2fs/OWNERS new file mode 100644 index 000000000000..f981f44fbffd --- /dev/null +++ b/fs/f2fs/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/fs/f2fs/OWNERS diff --git a/fs/incfs/OWNERS b/fs/incfs/OWNERS new file mode 100644 index 000000000000..17131f337364 --- /dev/null +++ b/fs/incfs/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/fs/incfs/OWNERS diff --git a/include/OWNERS b/include/OWNERS new file mode 100644 index 000000000000..ab8142b271b4 --- /dev/null +++ b/include/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/include/OWNERS diff --git a/include/linux/OWNERS b/include/linux/OWNERS new file mode 100644 index 000000000000..c88808c07797 --- /dev/null +++ b/include/linux/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/include/linux/OWNERS diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h index b139f76060a6..7a22e5b8c9c9 100644 --- a/include/linux/virtio_vsock.h +++ b/include/linux/virtio_vsock.h @@ -12,7 +12,8 @@ #define VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE (1024 * 256) #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4) #define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL -#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) +#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE virtio_transport_max_vsock_pkt_buf_size +extern uint virtio_transport_max_vsock_pkt_buf_size; enum { VSOCK_VQ_RX = 0, /* for host to guest data */ diff --git a/include/trace/events/OWNERS b/include/trace/events/OWNERS new file mode 100644 index 000000000000..de3838b6df38 --- /dev/null +++ b/include/trace/events/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/include/trace/events/OWNERS diff --git a/include/uapi/linux/OWNERS b/include/uapi/linux/OWNERS new file mode 100644 index 000000000000..113046844b1c --- /dev/null +++ b/include/uapi/linux/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/include/uapi/linux/OWNERS diff --git a/init/Kconfig.gki b/init/Kconfig.gki index 48c0cc4aa970..7e37f0040804 100644 --- a/init/Kconfig.gki +++ b/init/Kconfig.gki @@ -3,6 +3,7 @@ config GKI_HIDDEN_DRM_CONFIGS select DRM_KMS_HELPER if (HAS_IOMEM && DRM) select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER + select DRM_GEM_SHMEM_HELPER select DRM_MIPI_DSI select DRM_TTM if (HAS_IOMEM && DRM) select VIDEOMODE_HELPERS diff --git a/kernel/sched/OWNERS b/kernel/sched/OWNERS new file mode 100644 index 000000000000..fc027b64b61b --- /dev/null +++ b/kernel/sched/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/kernel/sched/OWNERS diff --git a/mm/OWNERS b/mm/OWNERS new file mode 100644 index 000000000000..f89766e706e0 --- /dev/null +++ b/mm/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/mm/OWNERS diff --git a/net/OWNERS b/net/OWNERS new file mode 100644 index 000000000000..ddb7653770ec --- /dev/null +++ b/net/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/net/OWNERS diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index dde16a033a09..2e52ca4dbfc7 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -29,6 +29,10 @@ /* Threshold for detecting small packets to copy */ #define GOOD_COPY_LEN 128 +uint virtio_transport_max_vsock_pkt_buf_size = 64 * 1024; +module_param(virtio_transport_max_vsock_pkt_buf_size, uint, 0444); +EXPORT_SYMBOL_GPL(virtio_transport_max_vsock_pkt_buf_size); + static const struct virtio_transport *virtio_transport_get_ops(void) { const struct vsock_transport *t = vsock_core_get_transport(); diff --git a/tools/testing/selftests/filesystems/incfs/OWNERS b/tools/testing/selftests/filesystems/incfs/OWNERS new file mode 100644 index 000000000000..5eb371e1a5a3 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/OWNERS @@ -0,0 +1,2 @@ +# include OWNERS from the authoritative android-mainline branch +include kernel/common:android-mainline:/tools/testing/selftests/filesystems/incfs/OWNERS