/* SPDX-License-Identifier: GPL-2.0 */
/*
* u_fs . h
*
* Utility definitions for the FunctionFS
*
* Copyright ( c ) 2013 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
*
* Author : Andrzej Pietrasiewicz < andrzejtp2010 @ gmail . com >
*/
#ifndef U_FFS_H
#define U_FFS_H
#include <linux/usb/composite.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/refcount.h>
#ifdef VERBOSE_DEBUG
#ifndef pr_vdebug
# define pr_vdebug pr_debug
#endif /* pr_vdebug */
# define ffs_dump_mem(prefix, ptr, len) \
print_hex_dump_bytes(pr_fmt(prefix ": " ), DUMP_PREFIX_NONE, ptr, len)
#else
#ifndef pr_vdebug
# define pr_vdebug(...) do { } while (0 )
#endif /* pr_vdebug */
# define ffs_dump_mem(prefix, ptr, len) do { } while (0 )
#endif /* VERBOSE_DEBUG */
struct f_fs_opts;
struct ffs_dev {
struct ffs_data *ffs_data;
struct f_fs_opts *opts;
struct list_head entry;
char name[41 ];
bool mounted;
bool desc_ready;
bool single;
int (*ffs_ready_callback)(struct ffs_data *ffs);
void (*ffs_closed_callback)(struct ffs_data *ffs);
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
void (*ffs_release_dev_callback)(struct ffs_dev *dev);
};
extern struct mutex ffs_lock;
static inline void ffs_dev_lock(void )
{
mutex_lock(&ffs_lock);
}
static inline void ffs_dev_unlock(void )
{
mutex_unlock(&ffs_lock);
}
int ffs_name_dev(struct ffs_dev *dev, const char *name);
int ffs_single_dev(struct ffs_dev *dev);
struct ffs_epfile;
struct ffs_function;
enum ffs_state {
/*
* Waiting for descriptors and strings .
*
* In this state no open ( 2 ) , read ( 2 ) or write ( 2 ) on epfiles
* may succeed ( which should not be the problem as there
* should be no such files opened in the first place ) .
*/
FFS_READ_DESCRIPTORS,
FFS_READ_STRINGS,
/*
* We ' ve got descriptors and strings . We are or have called
* functionfs_ready_callback ( ) . functionfs_bind ( ) may have
* been called but we don ' t know .
*
* This is the only state in which operations on epfiles may
* succeed .
*/
FFS_ACTIVE,
/*
* Function is visible to host , but it ' s not functional . All
* setup requests are stalled and transfers on another endpoints
* are refused . All epfiles , except ep0 , are deleted so there
* is no way to perform any operations on them .
*
* This state is set after closing all functionfs files , when
* mount parameter " no_disconnect = 1 " has been set . Function will
* remain in deactivated state until filesystem is umounted or
* ep0 is opened again . In the second case functionfs state will
* be reset , and it will be ready for descriptors and strings
* writing .
*
* This is useful only when functionfs is composed to gadget
* with another function which can perform some critical
* operations , and it ' s strongly desired to have this operations
* completed , even after functionfs files closure .
*/
FFS_DEACTIVATED,
/*
* All endpoints have been closed . This state is also set if
* we encounter an unrecoverable error . The only
* unrecoverable error is situation when after reading strings
* from user space we fail to initialise epfiles or
* functionfs_ready_callback ( ) returns with error ( < 0 ) .
*
* In this state no open ( 2 ) , read ( 2 ) or write ( 2 ) ( both on ep0
* as well as epfile ) may succeed ( at this point epfiles are
* unlinked and all closed so this is not a problem ; ep0 is
* also closed but ep0 file exists and so open ( 2 ) on ep0 must
* fail ) .
*/
FFS_CLOSING
};
enum ffs_setup_state {
/* There is no setup request pending. */
FFS_NO_SETUP,
/*
* User has read events and there was a setup request event
* there . The next read / write on ep0 will handle the
* request .
*/
FFS_SETUP_PENDING,
/*
* There was event pending but before user space handled it
* some other event was introduced which canceled existing
* setup . If this state is set read / write on ep0 return
* - EIDRM . This state is only set when adding event .
*/
FFS_SETUP_CANCELLED
};
struct ffs_data {
struct usb_gadget *gadget;
/*
* Protect access read / write operations , only one read / write
* at a time . As a consequence protects ep0req and company .
* While setup request is being processed ( queued ) this is
* held .
*/
struct mutex mutex;
/*
* Protect access to endpoint related structures ( basically
* usb_ep_queue ( ) , usb_ep_dequeue ( ) , etc . calls ) except for
* endpoint zero .
*/
spinlock_t eps_lock;
/*
* XXX REVISIT do we need our own request ? Since we are not
* handling setup requests immediately user space may be so
* slow that another setup will be sent to the gadget but this
* time not to us but another function and then there could be
* a race . Is that the case ? Or maybe we can use cdev - > req
* after all , maybe we just need some spinlock for that ?
*/
struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
/* reference counter */
refcount_t ref;
/* how many files are opened (EP0 and others) */
atomic_t opened;
/* EP0 state */
enum ffs_state state;
/*
* Possible transitions :
* + FFS_NO_SETUP - > FFS_SETUP_PENDING - - P : ev . waitq . lock
* happens only in ep0 read which is P : mutex
* + FFS_SETUP_PENDING - > FFS_NO_SETUP - - P : ev . waitq . lock
* happens only in ep0 i / o which is P : mutex
* + FFS_SETUP_PENDING - > FFS_SETUP_CANCELLED - - P : ev . waitq . lock
* + FFS_SETUP_CANCELLED - > FFS_NO_SETUP - - cmpxchg
*
* This field should never be accessed directly and instead
* ffs_setup_state_clear_cancelled function should be used .
*/
enum ffs_setup_state setup_state;
/* Events & such. */
struct {
u8 types[4 ];
unsigned short count;
/* XXX REVISIT need to update it in some places, or do we? */
unsigned short can_stall;
struct usb_ctrlrequest setup;
wait_queue_head_t waitq;
} ev; /* the whole structure, P: ev.waitq.lock */
/* Flags */
unsigned long flags;
#define FFS_FL_CALL_CLOSED_CALLBACK 0
#define FFS_FL_BOUND 1
/* For waking up blocked threads when function is enabled. */
wait_queue_head_t wait;
/* Active function */
struct ffs_function *func;
/*
* Device name , write once when file system is mounted .
* Intended for user to read if she wants .
*/
const char *dev_name;
/* Private data for our user (ie. gadget). Managed by user. */
void *private_data;
/* filled by __ffs_data_got_descs() */
/*
* raw_descs is what you kfree , real_descs points inside of raw_descs ,
* where full speed , high speed and super speed descriptors start .
* real_descs_length is the length of all those descriptors .
*/
const void *raw_descs_data;
const void *raw_descs;
unsigned raw_descs_length;
unsigned fs_descs_count;
unsigned hs_descs_count;
unsigned ss_descs_count;
unsigned ms_os_descs_count;
unsigned ms_os_descs_ext_prop_count;
unsigned ms_os_descs_ext_prop_name_len;
unsigned ms_os_descs_ext_prop_data_len;
void *ms_os_descs_ext_prop_avail;
void *ms_os_descs_ext_prop_name_avail;
void *ms_os_descs_ext_prop_data_avail;
unsigned user_flags;
#define FFS_MAX_EPS_COUNT 31
u8 eps_addrmap[FFS_MAX_EPS_COUNT];
unsigned short strings_count;
unsigned short interfaces_count;
unsigned short eps_count;
unsigned short _pad1;
/* filled by __ffs_data_got_strings() */
/* ids in stringtabs are set in functionfs_bind() */
const void *raw_strings;
struct usb_gadget_strings **stringtabs;
/*
* File system ' s super block , write once when file system is
* mounted .
*/
struct super_block *sb;
/* File permissions, written once when fs is mounted */
struct ffs_file_perms {
umode_t mode;
kuid_t uid;
kgid_t gid;
} file_perms;
struct eventfd_ctx *ffs_eventfd;
struct workqueue_struct *io_completion_wq;
bool no_disconnect;
struct work_struct reset_work;
/*
* The endpoint files , filled by ffs_epfiles_create ( ) ,
* destroyed by ffs_epfiles_destroy ( ) .
*/
struct ffs_epfile *epfiles;
};
struct f_fs_opts {
struct usb_function_instance func_inst;
struct ffs_dev *dev;
unsigned refcnt;
bool no_configfs;
};
static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi)
{
return container_of(fi, struct f_fs_opts, func_inst);
}
#endif /* U_FFS_H */
Messung V0.5 in Prozent C=93 H=90 G=91
¤ Dauer der Verarbeitung: 0.7 Sekunden
¤
*© Formatika GbR, Deutschland