/* SPDX-License-Identifier: GPL-2.0 */ #ifndef WCN_USB_H #define WCN_USB_H #include #include #include #include #include #include #include #include #include #include #include #include #include #define wcn_usb_info(fmt, args...) \ pr_info("wcn_usb info " fmt, ## args) #define wcn_usb_info_ratelimited(fmt, args...) \ printk_ratelimited("wcn_usb info " fmt, ## args) #define wcn_usb_debug(fmt, args...) \ pr_debug("wcn_usb debug " fmt, ## args) #define wcn_usb_err(fmt, args...) \ pr_err("wcn_usb err " fmt, ## args) char get_wcn_usb_print_switch(void); #define wcn_usb_print(mask, fmt, args...) \ do { \ if (get_wcn_usb_print_switch() & mask)\ pr_info("wcn_usb info " fmt, ## args); \ } while (0) #define rx_tx_info 0x08 #define packet_info 0x04 #define mbuf_info 0x02 #define extern_info 0x01 #define wcn_usb_print_packet(packet) \ wcn_usb_print(packet_info, \ "%s+%d packet %p ->chn %d ->urb %p\n", \ __func__, __LINE__, packet, \ packet->ep ? packet->ep->channel : -1, packet->urb) /** * struct wcn_usb_store_intf - The object inherited from struct usb_interface. * @interface: We inherited from it. * @udev: interface->usb_device. * @lock: keep { num_users change_flags is a atomic }. * @num_users: How many object need this intf now. * @flags_lock: keep { change_flags } only one can access; * @change_flag: Is this intf need be changed? (if it is, don't add num_users!) */ struct wcn_usb_intf { struct usb_interface *interface; struct usb_device *udev; spinlock_t lock; char num_users; struct mutex flag_lock; char change_flag; wait_queue_head_t wait_user; }; /** * struct wcn_usb_ep - The object descrise a endpoint for wcn usb. * @intf_lock: keep { intf intf->users } is a atomic. * @intf: This endpoint must belong to a interface. * @epNum: This endpoint's index in interface's cur_altsetting->endpoint[] * that it belong to. * @submitted: for retract urb; */ struct wcn_usb_ep { int channel; spinlock_t intf_lock; struct wcn_usb_intf *intf; __u8 numEp; struct usb_anchor submitted; spinlock_t submit_lock; }; /** * struct wcn_usb_packet - The object for broke talk with io. * @urb: from usb_alloc_urb. user don't touch it! * @ep: record ep point. * @is_usb_anchor: to indicate this buf is alloc with usb_alloc_coherent. * @callback: be called after the packet transfer ok. * @pdata: to callback. * * NOTE: user don't touch any feild in this struct, unless you sure it is right * that what you do! */ struct wcn_usb_packet { struct urb *urb; struct wcn_usb_ep *ep; bool is_usb_anchor; void (*callback)(struct wcn_usb_packet *packet); void *pdata; }; struct wcn_usb_rx_tx { struct wcn_usb_packet *packet; struct mbuf_t *head; struct mbuf_t *tail; int num; int channel; int packet_status; struct list_head list; }; #define wcn_usb_print_rx_tx(rx_tx) \ wcn_usb_print(rx_tx_info, "%s+%d rx_tx %p ->packet %p ->head"\ " %p ->tail %p ->num %d ->channel %d ->packet_status %d\n", \ __func__, __LINE__, rx_tx, rx_tx->packet, \ rx_tx->head, rx_tx->tail, rx_tx->num, \ rx_tx->channel, rx_tx->packet_status) struct wcn_usb_notifier { struct notifier_block nb; void (*cb)(void *); void *data; unsigned long event; }; struct wcn_usb_work_data { struct task_struct *wcn_usb_thread; wait_queue_head_t wait_mbuf; wait_queue_head_t work_completion; struct mutex channel_lock; spinlock_t lock; struct list_head rx_tx_head; int channel; int report_num; int report_num_last; int transfer_remains; int goon; struct completion callback_complete; struct wcn_usb_notifier *wn; }; struct wcn_usb_work_data *wcn_usb_store_get_channel_info(int channel); int wcn_usb_store_register_channel_info(int channel, void *info); struct wcn_usb_ep *wcn_usb_store_get_epFRchn(int channel); int wcn_usb_store_init(void); void wcn_usb_store_delet(void); __u8 wcn_usb_store_chn2addr(int channel); struct usb_endpoint_descriptor *wcn_usb_intf2endpoint(struct wcn_usb_intf *intf, __u8 numEp); typedef int (*ep_handle_cb)(struct wcn_usb_ep *ep, void *pdata); int wcn_usb_store_travel_ep(ep_handle_cb cb, void *pdata); int wcn_usb_packet_get_status(struct wcn_usb_packet *packet); void wcn_usb_ep_stop(struct wcn_usb_ep *ep); void wcn_usb_packet_free(struct wcn_usb_packet *packet); void wcn_usb_io_delet(void); int wcn_usb_io_init(void); int wcn_usb_packet_set_buf(struct wcn_usb_packet *packet, void *buf, ssize_t buf_size, gfp_t mem_flags); void wcn_usb_packet_free_buf(struct wcn_usb_packet *packet); int wcn_usb_packet_set_sg(struct wcn_usb_packet *packet, struct scatterlist *sg, int num_sgs, unsigned int buf_len); struct wcn_usb_packet *wcn_usb_alloc_packet(gfp_t mem_flags); struct scatterlist *wcn_usb_packet_pop_sg(struct wcn_usb_packet *packet, int *num_sgs); int wcn_usb_msg(struct wcn_usb_ep *ep, void *data, int len, int *actual_length, int timeout); int wcn_usb_packet_submit(struct wcn_usb_packet *packet, void (*callback)(struct wcn_usb_packet *packet), void *pdata, gfp_t mem_flags); int wcn_usb_ep_can_dma(struct wcn_usb_ep *ep); void wcn_usb_packet_interval(struct wcn_usb_packet *packet, int interval); unsigned int wcn_usb_packet_recv_len(struct wcn_usb_packet *packet); int wcn_usb_ep_set(struct wcn_usb_ep *ep, int setting_id); void wcn_usb_wait_channel_stop(int chn); int wcn_usb_packet_bind(struct wcn_usb_packet *packet, struct wcn_usb_ep *ep, gfp_t mem_flags); void wcn_usb_packet_clean(struct wcn_usb_packet *packet); int wcn_usb_packet_set_setup_packet(struct wcn_usb_packet *packet, struct usb_ctrlrequest *setup_packet); struct usb_ctrlrequest *wcn_usb_packet_pop_setup_packet( struct wcn_usb_packet *packet); #define wcn_usb_packet_get_buf(packet) \ (packet->buf) #define wcn_usb_ep_init(ep, id) \ do { \ ep->channel = id; \ ep->intf = NULL; \ ep->numEp = -1; \ spin_lock_init(&ep->intf_lock); \ init_usb_anchor(&ep->submitted); \ spin_lock_init(&ep->submit_lock); \ } while (0) #if 0 #define wcn_usb_work_data_init(work_data, id) \ do { \ work_data->channel = id; \ mutex_init(&work_data->channel_lock); \ spin_lock_init(&work_data->lock); \ init_waitqueue_head(&work_data->wait_mbuf); \ INIT_WORK(&work_data->wcn_usb_work, wcn_usb_work_func); \ init_waitqueue_head(&work_data->work_completion); \ init_completion(&work_data->callback_complete);\ } while (0) #endif void wcn_usb_work_data_init(struct wcn_usb_work_data *work_data, int id); /* follow macro call wcn_usb_intf2endpoint * So we need hold intf, before we call them */ #define wcn_usb_ep_address(ep) \ (wcn_usb_intf2endpoint(ep->intf, ep->numEp)->bEndpointAddress) #define wcn_usb_ep_interval(ep) \ (wcn_usb_intf2endpoint(ep->intf, ep->numEp)->bInterval) #define wcn_usb_ep_packet_max(ep) \ usb_endpoint_maxp(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_ep_is_isoc(ep) \ usb_endpoint_xfer_isoc(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_ep_is_int(ep) \ usb_endpoint_xfer_int(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_ep_is_ctrl(ep) \ usb_endpoint_xfer_control(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_ep_is_bulk(ep) \ usb_endpoint_xfer_bulk(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_ep_no_sg_constraint(ep) \ (ep->intf->udev->bus->no_sg_constraint) #define wcn_usb_ep_dir(ep) \ usb_endpoint_dir_in(wcn_usb_intf2endpoint(ep->intf, ep->numEp)) #define wcn_usb_packet_get_pdata(packet) \ (packet->pdata) #define wcn_usb_ep_is_stop(ep) \ usb_anchor_empty(&ep->submitted) #define wcn_usb_packet_setup_packet(packet, setup_packet) \ (packet->urb->setup_packet = setup_packet) #define wcn_usb_intf_epNum(intf) \ intf->interface->cur_altsetting->desc.bNumEndpoints /* @head: list's head * @num: list's num * @pos: current node, if eq null then we done all list with success. if eq is * not null, then it point the node that error one. * @posN: current node's index, if pos eq null then it eq num. */ #define mbuf_list_iter(head, num, pos, posN) \ for (pos = head, posN = 0; posN < num && pos; posN++, pos = pos->next) int wcn_usb_push_list_tx(int chn, struct mbuf_t *head, struct mbuf_t *tail, int num); int wcn_usb_push_list_rx(int chn, struct mbuf_t *head, struct mbuf_t *tail, int num); void wcn_usb_begin_poll_rx(int chn); void wcn_usb_mbuf_free_notif(int chn); int wcn_usb_list_alloc(int chn, struct mbuf_t **head, struct mbuf_t **tail, int *num); int wcn_usb_list_free(int chn, struct mbuf_t *head, struct mbuf_t *tail, int num); int wcn_usb_rx_tx_pool_init(void); void wcn_usb_rx_tx_pool_deinit(void); unsigned long long wcn_usb_get_rx_tx_cnt(void); enum wcn_usb_event { interface_plug_base, interface_0_plug = interface_plug_base, interface_1_plug, interface_2_plug, dev_plug_fully, interface_unplug_base, interface_0_unplug = interface_unplug_base, interface_1_unplug, interface_2_unplug, dev_unplug_fully, download_over, cp_ready, pwr_on, pwr_off, pwr_state, error_happen, error_clean, }; int wcn_usb_apostle_begin(int chn); int wcn_usb_store_addr2chn(__u8 epAddress); int wcn_usb_packet_is_freed(struct wcn_usb_packet *packet); void *wcn_usb_packet_pop_buf(struct wcn_usb_packet *packet); void wcn_usb_init_copy_men(void); void channel_debug_mbuf_from_user(int chn, int num); void channel_debug_mbuf_to_user(int chn, int num); void channel_debug_mbuf_free(int chn, int num); void channel_debug_mbuf_alloc(int chn, int num); void channel_debug_rx_tx_from_controller(int chn, int num); void channel_debug_rx_tx_to_controller(int chn, int num); void channel_debug_rx_tx_free(int chn, int num); void channel_debug_rx_tx_alloc(int chn, int num); void channel_debug_to_accept(int chn, int num); void channel_debug_report_num(int chn, int num); void channel_debug_kzalloc(int times); void channel_debug_net_free(int times); void channel_debug_net_malloc(int times); void channel_debug_free_big_men(int chn); void channel_debug_alloc_big_men(int chn); #if 0 void channel_debug_push_list_no_null(int times); #endif void channel_debug_packet_no_full(int times); void channel_debug_free_with_accient(int times); void channel_debug_mbuf_10(int times); void channel_debug_mbuf_4(int times); void channel_debug_mbuf_1(int times); void channel_debug_mbuf_8(int times); void channel_debug_interrupt_callback(int times); void channel_debug_cp_num(int times); int wcn_usb_chnmg_init(void); int wcn_usb_state_sent_event(enum wcn_usb_event event); int wcn_usb_state_register(struct notifier_block *nb); int wcn_usb_state_unregister(struct notifier_block *nb); int wcn_usb_state_get(enum wcn_usb_event event); void wcn_usb_state_clear(enum wcn_usb_event event); /* for test dump */ unsigned int marlin_get_wcn_chipid(void); int marlin_dump_from_romcode_usb(unsigned int addr, void *buf, int len); int marlin_get_version(void); int marlin_connet(void); #endif