Loading sound/usb/endpoint.c +171 −11 Original line number Diff line number Diff line Loading @@ -35,6 +35,32 @@ #define EP_FLAG_ACTIVATED 0 #define EP_FLAG_RUNNING 1 /* * snd_usb_endpoint is a model that abstracts everything related to an * USB endpoint and its streaming. * * There are functions to activate and deactivate the streaming URBs and * optinal callbacks to let the pcm logic handle the actual content of the * packets for playback and record. Thus, the bus streaming and the audio * handlers are fully decoupled. * * There are two different types of endpoints in for audio applications. * * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both * inbound and outbound traffic. * * SND_USB_ENDPOINT_TYPE_SYNC are for inbound traffic only and expect the * payload to carry Q16.16 formatted sync information (3 or 4 bytes). * * Each endpoint has to be configured (by calling * snd_usb_endpoint_set_params()) before it can be used. * * The model incorporates a reference counting, so that multiple users * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and * only the first user will effectively start the URBs, and only the last * one will tear them down again. */ /* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz Loading Loading @@ -91,6 +117,14 @@ static const char *usb_error_string(int err) } } /** * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type * * @ep: The endpoint * * Determine whether an endpoint is driven by an implicit feedback * data endpoint source. */ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) { return ep->sync_master && Loading @@ -99,7 +133,13 @@ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) usb_pipeout(ep->pipe); } /* determine the number of frames in the next packet */ /* * For streaming based on information derived from sync endpoints, * prepare_outbound_urb_sizes() will call next_packet_size() to * determine the number of samples to be sent in the next packet. * * For implicit feedback, next_packet_size() is unused. */ static int next_packet_size(struct snd_usb_endpoint *ep) { unsigned long flags; Loading Loading @@ -237,6 +277,19 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, } } /* * Send output urbs that have been prepared previously. Urbs are dequeued * from ep->ready_playback_urbs and in case there there aren't any available * or there are no packets that have been prepared, this function does * nothing. * * The reason why the functionality of sending and preparing urbs is separated * is that host controllers don't guarantee an ordering in returing inbound * and outbound packets to their submitters. * * This function is only used for implicit feedback endpoints. For endpoints * driven by sync endpoints, urbs are submitted from their completion handler. */ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) { while (test_bit(EP_FLAG_RUNNING, &ep->flags)) { Loading Loading @@ -270,6 +323,7 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) for (i = 0; i < packet->packets; i++) ctx->packet_size[i] = packet->packet_size[i]; /* call the data handler to fill in playback data */ prepare_outbound_urb(ep, ctx); err = usb_submit_urb(ctx->urb, GFP_ATOMIC); Loading Loading @@ -336,6 +390,22 @@ static void snd_complete_urb(struct urb *urb) clear_bit(ctx->index, &ep->active_mask); } /** * snd_usb_add_endpoint: Add an endpoint to an audio chip * * @chip: The chip * @alts: The USB host interface * @ep_num: The number of the endpoint to use * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC * * If the requested endpoint has not been added to the given chip before, * a new instance is created. Otherwise, a pointer to the previoulsy * created instance is returned. In case of any error, NULL is returned. * * New endpoints will be added to chip->ep_list and must be freed by * calling snd_usb_endpoint_free(). */ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, struct usb_host_interface *alts, int ep_num, int direction, int type) Loading Loading @@ -506,6 +576,9 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) ep->nurbs = 0; } /* * configure a data endpoint */ static int data_ep_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt, Loading Loading @@ -629,6 +702,9 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, return -ENOMEM; } /* * configure a sync endpoint */ static int sync_ep_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt) Loading Loading @@ -669,6 +745,15 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep, return -ENOMEM; } /** * snd_usb_endpoint_set_params: configure an snd_endpoint * * @ep: the endpoint to configure * * Determine the number of of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt, Loading Loading @@ -717,6 +802,19 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, return err; } /** * snd_usb_endpoint_start: start an snd_usb_endpoint * * @ep: the endpoint to start * * A call to this function will increment the use count of the endpoint. * In case this not already running, the URBs for this endpoint will be * submitted. Otherwise, this function does nothing. * * Must be balanced to calls of snd_usb_endpoint_stop(). * * Returns an error if the URB submission failed, 0 in all other cases. */ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) { int err; Loading Loading @@ -788,6 +886,17 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) return -EPIPE; } /** * snd_usb_endpoint_stop: stop an snd_usb_endpoint * * @ep: the endpoint to stop (may be NULL) * * A call to this function will decrement the use count of the endpoint. * In case the last user has requested the endpoint stop, the URBs will * actually deactivated. * * Must be balanced to calls of snd_usb_endpoint_start(). */ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, int force, int can_sleep, int wait) { Loading @@ -812,6 +921,19 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, } } /** * snd_usb_endpoint_activate: activate an snd_usb_endpoint * * @ep: the endpoint to activate * * If the endpoint is not currently in use, this functions will select the * correct alternate interface setting for the interface of this endpoint. * * In case of any active users, this functions does nothing. * * Returns an error if usb_set_interface() failed, 0 in all other * cases. */ int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep) { if (ep->use_count != 0) Loading @@ -835,6 +957,19 @@ int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep) return -EBUSY; } /** * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint * * @ep: the endpoint to deactivate * * If the endpoint is not currently in use, this functions will select the * alternate interface setting 0 for the interface of this endpoint. * * In case of any active users, this functions does nothing. * * Returns an error if usb_set_interface() failed, 0 in all other * cases. */ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) { if (!ep) Loading @@ -860,6 +995,13 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) return -EBUSY; } /** snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint * * @ep: the list header of the endpoint to free * * This function does not care for the endpoint's use count but will tear * down all the streaming URBs immediately and free all resources. */ void snd_usb_endpoint_free(struct list_head *head) { struct snd_usb_endpoint *ep; Loading @@ -869,15 +1011,15 @@ void snd_usb_endpoint_free(struct list_head *head) kfree(ep); } /* * process after playback sync complete /** * snd_usb_handle_sync_urb: parse an USB sync packet * * Full speed devices report feedback values in 10.14 format as samples per * frame, high speed devices in 16.16 format as samples per microframe. * Because the Audio Class 1 spec was written before USB 2.0, many high speed * devices use a wrong interpretation, some others use an entirely different * format. Therefore, we cannot predict what format any particular device uses * and must detect it automatically. * @ep: the endpoint to handle the packet * @sender: the sending endpoint * @urb: the received packet * * This function is called from the context of an endpoint that received * the packet and is used to let another endpoint object handle the payload. */ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, struct snd_usb_endpoint *sender, Loading @@ -889,6 +1031,11 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, snd_BUG_ON(ep == sender); /* * In case the endpoint is operating in implicit feedback mode, prepare * and a new outbound URB that has the same layout as the received * packet and add it to the list of pending urbs. */ if (snd_usb_endpoint_implict_feedback_sink(ep) && ep->use_count != 0) { Loading Loading @@ -938,7 +1085,20 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, return; } /* parse sync endpoint packet */ /* * process after playback sync complete * * Full speed devices report feedback values in 10.14 format as samples * per frame, high speed devices in 16.16 format as samples per * microframe. * * Because the Audio Class 1 spec was written before USB 2.0, many high * speed devices use a wrong interpretation, some others use an * entirely different format. * * Therefore, we cannot predict what format any particular device uses * and must detect it automatically. */ if (urb->iso_frame_desc[0].status != 0 || urb->iso_frame_desc[0].actual_length < 3) Loading Loading
sound/usb/endpoint.c +171 −11 Original line number Diff line number Diff line Loading @@ -35,6 +35,32 @@ #define EP_FLAG_ACTIVATED 0 #define EP_FLAG_RUNNING 1 /* * snd_usb_endpoint is a model that abstracts everything related to an * USB endpoint and its streaming. * * There are functions to activate and deactivate the streaming URBs and * optinal callbacks to let the pcm logic handle the actual content of the * packets for playback and record. Thus, the bus streaming and the audio * handlers are fully decoupled. * * There are two different types of endpoints in for audio applications. * * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both * inbound and outbound traffic. * * SND_USB_ENDPOINT_TYPE_SYNC are for inbound traffic only and expect the * payload to carry Q16.16 formatted sync information (3 or 4 bytes). * * Each endpoint has to be configured (by calling * snd_usb_endpoint_set_params()) before it can be used. * * The model incorporates a reference counting, so that multiple users * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and * only the first user will effectively start the URBs, and only the last * one will tear them down again. */ /* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz Loading Loading @@ -91,6 +117,14 @@ static const char *usb_error_string(int err) } } /** * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type * * @ep: The endpoint * * Determine whether an endpoint is driven by an implicit feedback * data endpoint source. */ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) { return ep->sync_master && Loading @@ -99,7 +133,13 @@ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) usb_pipeout(ep->pipe); } /* determine the number of frames in the next packet */ /* * For streaming based on information derived from sync endpoints, * prepare_outbound_urb_sizes() will call next_packet_size() to * determine the number of samples to be sent in the next packet. * * For implicit feedback, next_packet_size() is unused. */ static int next_packet_size(struct snd_usb_endpoint *ep) { unsigned long flags; Loading Loading @@ -237,6 +277,19 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, } } /* * Send output urbs that have been prepared previously. Urbs are dequeued * from ep->ready_playback_urbs and in case there there aren't any available * or there are no packets that have been prepared, this function does * nothing. * * The reason why the functionality of sending and preparing urbs is separated * is that host controllers don't guarantee an ordering in returing inbound * and outbound packets to their submitters. * * This function is only used for implicit feedback endpoints. For endpoints * driven by sync endpoints, urbs are submitted from their completion handler. */ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) { while (test_bit(EP_FLAG_RUNNING, &ep->flags)) { Loading Loading @@ -270,6 +323,7 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) for (i = 0; i < packet->packets; i++) ctx->packet_size[i] = packet->packet_size[i]; /* call the data handler to fill in playback data */ prepare_outbound_urb(ep, ctx); err = usb_submit_urb(ctx->urb, GFP_ATOMIC); Loading Loading @@ -336,6 +390,22 @@ static void snd_complete_urb(struct urb *urb) clear_bit(ctx->index, &ep->active_mask); } /** * snd_usb_add_endpoint: Add an endpoint to an audio chip * * @chip: The chip * @alts: The USB host interface * @ep_num: The number of the endpoint to use * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC * * If the requested endpoint has not been added to the given chip before, * a new instance is created. Otherwise, a pointer to the previoulsy * created instance is returned. In case of any error, NULL is returned. * * New endpoints will be added to chip->ep_list and must be freed by * calling snd_usb_endpoint_free(). */ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, struct usb_host_interface *alts, int ep_num, int direction, int type) Loading Loading @@ -506,6 +576,9 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) ep->nurbs = 0; } /* * configure a data endpoint */ static int data_ep_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt, Loading Loading @@ -629,6 +702,9 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, return -ENOMEM; } /* * configure a sync endpoint */ static int sync_ep_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt) Loading Loading @@ -669,6 +745,15 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep, return -ENOMEM; } /** * snd_usb_endpoint_set_params: configure an snd_endpoint * * @ep: the endpoint to configure * * Determine the number of of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, struct snd_pcm_hw_params *hw_params, struct audioformat *fmt, Loading Loading @@ -717,6 +802,19 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, return err; } /** * snd_usb_endpoint_start: start an snd_usb_endpoint * * @ep: the endpoint to start * * A call to this function will increment the use count of the endpoint. * In case this not already running, the URBs for this endpoint will be * submitted. Otherwise, this function does nothing. * * Must be balanced to calls of snd_usb_endpoint_stop(). * * Returns an error if the URB submission failed, 0 in all other cases. */ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) { int err; Loading Loading @@ -788,6 +886,17 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) return -EPIPE; } /** * snd_usb_endpoint_stop: stop an snd_usb_endpoint * * @ep: the endpoint to stop (may be NULL) * * A call to this function will decrement the use count of the endpoint. * In case the last user has requested the endpoint stop, the URBs will * actually deactivated. * * Must be balanced to calls of snd_usb_endpoint_start(). */ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, int force, int can_sleep, int wait) { Loading @@ -812,6 +921,19 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, } } /** * snd_usb_endpoint_activate: activate an snd_usb_endpoint * * @ep: the endpoint to activate * * If the endpoint is not currently in use, this functions will select the * correct alternate interface setting for the interface of this endpoint. * * In case of any active users, this functions does nothing. * * Returns an error if usb_set_interface() failed, 0 in all other * cases. */ int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep) { if (ep->use_count != 0) Loading @@ -835,6 +957,19 @@ int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep) return -EBUSY; } /** * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint * * @ep: the endpoint to deactivate * * If the endpoint is not currently in use, this functions will select the * alternate interface setting 0 for the interface of this endpoint. * * In case of any active users, this functions does nothing. * * Returns an error if usb_set_interface() failed, 0 in all other * cases. */ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) { if (!ep) Loading @@ -860,6 +995,13 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) return -EBUSY; } /** snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint * * @ep: the list header of the endpoint to free * * This function does not care for the endpoint's use count but will tear * down all the streaming URBs immediately and free all resources. */ void snd_usb_endpoint_free(struct list_head *head) { struct snd_usb_endpoint *ep; Loading @@ -869,15 +1011,15 @@ void snd_usb_endpoint_free(struct list_head *head) kfree(ep); } /* * process after playback sync complete /** * snd_usb_handle_sync_urb: parse an USB sync packet * * Full speed devices report feedback values in 10.14 format as samples per * frame, high speed devices in 16.16 format as samples per microframe. * Because the Audio Class 1 spec was written before USB 2.0, many high speed * devices use a wrong interpretation, some others use an entirely different * format. Therefore, we cannot predict what format any particular device uses * and must detect it automatically. * @ep: the endpoint to handle the packet * @sender: the sending endpoint * @urb: the received packet * * This function is called from the context of an endpoint that received * the packet and is used to let another endpoint object handle the payload. */ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, struct snd_usb_endpoint *sender, Loading @@ -889,6 +1031,11 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, snd_BUG_ON(ep == sender); /* * In case the endpoint is operating in implicit feedback mode, prepare * and a new outbound URB that has the same layout as the received * packet and add it to the list of pending urbs. */ if (snd_usb_endpoint_implict_feedback_sink(ep) && ep->use_count != 0) { Loading Loading @@ -938,7 +1085,20 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, return; } /* parse sync endpoint packet */ /* * process after playback sync complete * * Full speed devices report feedback values in 10.14 format as samples * per frame, high speed devices in 16.16 format as samples per * microframe. * * Because the Audio Class 1 spec was written before USB 2.0, many high * speed devices use a wrong interpretation, some others use an * entirely different format. * * Therefore, we cannot predict what format any particular device uses * and must detect it automatically. */ if (urb->iso_frame_desc[0].status != 0 || urb->iso_frame_desc[0].actual_length < 3) Loading