New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Virtual device #41

Merged
merged 122 commits into from Oct 2, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+433 −267
Diff settings

Always

Just for now

Viewing a subset of changes. View all
View
@@ -5,57 +5,23 @@
#include "ctlra.h"
#include "impl.h"
#include "usb.h"
/* For USB initialization */
int ctlra_dev_impl_usb_init(struct ctlra_t *ctlra);
/* For polling hotplug / other events */
void ctlra_impl_usb_idle_iter(struct ctlra_t *);
/* For cleaning up the USB subsystem */
void ctlra_impl_usb_shutdown(struct ctlra_t *ctlra);
struct ctlra_dev_connect_func_t {
uint32_t vid;
uint32_t pid;
ctlra_dev_connect_func connect;
struct ctlra_dev_info_t *info;
};
/* TODO: Cleanup this registration method to be in the .c files of each
* implementation, instead of centrally located here. This allows drivers
* to be "dropped in" to the source, and then automatically register up
* without library code changes */
CTLRA_DEVICE_DECL(ni_kontrol_d2);
CTLRA_DEVICE_DECL(ni_kontrol_z1);
CTLRA_DEVICE_DECL(ni_kontrol_f1);
CTLRA_DEVICE_DECL(ni_kontrol_f1);
CTLRA_DEVICE_DECL(ni_kontrol_s2_mk2);
CTLRA_DEVICE_DECL(ni_kontrol_x1_mk2);
CTLRA_DEVICE_DECL(ni_maschine_mikro_mk2);
CTLRA_DEVICE_DECL(ni_maschine_jam);
CTLRA_DEVICE_DECL(akai_apc);
CTLRA_DEVICE_DECL(avtka);
CTLRA_DEVICE_INFO(ni_kontrol_s2_mk2);
CTLRA_DEVICE_INFO(ni_kontrol_z1);
CTLRA_DEVICE_INFO(ni_maschine_mikro_mk2);
static const struct ctlra_dev_connect_func_t devices[] = {
{0, 0, 0},
{0x17cc, 0x1400, CTLRA_DEVICE_FUNC(ni_kontrol_d2)},
{0x17cc, 0x1210, CTLRA_DEVICE_FUNC(ni_kontrol_z1)},
{0x17cc, 0x1120, CTLRA_DEVICE_FUNC(ni_kontrol_f1)},
{0x17cc, 0x1320, CTLRA_DEVICE_FUNC(ni_kontrol_s2_mk2)},
{0x17cc, 0x1220, CTLRA_DEVICE_FUNC(ni_kontrol_x1_mk2)},
{0x17cc, 0x1200, CTLRA_DEVICE_FUNC(ni_maschine_mikro_mk2)},
{0x17cc, 0x1500, CTLRA_DEVICE_FUNC(ni_maschine_jam)},
/* WIP {0x09e8, 0x0073, CTLRA_DEVICE_FUNC(akai_apc)},*/
};
#define CTLRA_NUM_DEVS (sizeof(devices) / sizeof(devices[0]))
#define CTLRA_MAX_DEVICES 64
struct ctlra_dev_connect_func_t __ctlra_devices[CTLRA_MAX_DEVICES];
uint32_t __ctlra_device_count;
__attribute__((constructor(101)))
static void ctlra_static_setup()
{
printf("%s\n", __func__);
}
int ctlra_impl_get_id_by_vid_pid(uint32_t vid, uint32_t pid)
{
for(unsigned i = 0; i < CTLRA_NUM_DEVS; i++) {
if(devices[i].vid == vid && devices[i].pid == pid) {
for(unsigned i = 0; i < __ctlra_device_count; i++) {
if(__ctlra_devices[i].vid == vid && __ctlra_devices[i].pid == pid) {
return i;
}
}
@@ -69,11 +35,6 @@ int ctlra_impl_dev_get_by_vid_pid(struct ctlra_t *ctlra, int32_t vid,
struct ctlra_dev_t *dev_iter = ctlra->dev_list;
*out_dev = 0x0;
while(dev_iter) {
#if 0
printf("%s, checking %04x %04x\n", __func__,
dev_iter->info.vendor_id,
dev_iter->info.device_id);
#endif
if(dev_iter->info.vendor_id == vid &&
dev_iter->info.device_id == pid) {
*out_dev = dev_iter;
@@ -84,13 +45,12 @@ int ctlra_impl_dev_get_by_vid_pid(struct ctlra_t *ctlra, int32_t vid,
return -1;
}
struct ctlra_dev_t *ctlra_dev_connect(struct ctlra_t *ctlra,
ctlra_dev_connect_func connect,
ctlra_event_func event_func,
void *userdata, void *future)
{
struct ctlra_dev_t *new_dev = 0;
struct ctlra_dev_t *new_dev;
new_dev = connect(event_func, userdata, future);
if(new_dev) {
new_dev->ctlra_context = ctlra;
@@ -113,9 +73,90 @@ struct ctlra_dev_t *ctlra_dev_connect(struct ctlra_t *ctlra,
}
int32_t
ctlra_dev_virtualize(struct ctlra_t *c, struct ctlra_dev_info_t *info)
ctlra_get_devices_by_vendor(const char *vendor, const char *devices[],
int32_t size)
{
memset(devices, 0, sizeof(char *) * size);
int device_idx = 0;
int i;
for(i = 0; i < __ctlra_device_count; i++) {
if(__ctlra_devices[i].info) {
const char *v = __ctlra_devices[i].info->vendor;
const char *d = __ctlra_devices[i].info->device;
/* check this device is by vendor */
if(strcmp(vendor, v) == 0) {
if(device_idx >= size)
break;
devices[device_idx++] = d;
}
}
}
return device_idx;
}
int32_t
ctlra_get_vendors(const char *vendors[], int32_t size)
{
memset(vendors, 0, sizeof(char *) * size);
int vendor_idx = 0;
int i;
for(i = 0; i < __ctlra_device_count; i++) {
if(__ctlra_devices[i].info) {
const char * v = __ctlra_devices[i].info->vendor;
/* check this is not duplicate */
int j = 0;
int unique = 1;
while(vendors[j] != 0) {
if(strcmp(vendors[j], v) == 0) {
unique = 0;
break;
}
j++;
}
if(unique) {
if(vendor_idx >= size)
break;
vendors[vendor_idx++] = v;
}
}
}
return vendor_idx;
}
int32_t
ctlra_dev_virtualize(struct ctlra_t *c, const char *vendor,
const char *device)
{
int i;
struct ctlra_dev_info_t *info = 0;
for(i = 0; i < __ctlra_device_count; i++) {
if(__ctlra_devices[i].info &&
strcmp(vendor, __ctlra_devices[i].info->vendor) == 0 &&
strcmp(device, __ctlra_devices[i].info->device) == 0) {
printf("found device @ %d\n", i);
info = __ctlra_devices[i].info;
break;
}
}
if(!info) {
CTLRA_WARN(c, "Couldn't find device '%s' '%s' in %d registered drivers\n",
vendor, device, i);
return -ENODEV;
}
#ifdef HAVE_AVTKA
/* TODO: find better solution to this hack */
CTLRA_DEVICE_DECL(avtka);
/* call into AVTKA and virtualize the device, passing info through
* the future (void *) to the AVTKA backend. */
CTLRA_INFO(c, "virtualizing dev with info %p\n", info);
@@ -237,52 +278,13 @@ void ctlra_dev_get_info(const struct ctlra_dev_t *dev,
{
if(!dev)
return;
#if 0
memset(info, 0, sizeof(*info));
snprintf(info->vendor, sizeof(info->vendor), "%s", dev->info.vendor);
snprintf(info->device, sizeof(info->device), "%s", dev->info.device);
snprintf(info->serial, sizeof(info->serial), "%s", dev->info.serial);
info->serial_number = dev->info.serial_number;
info->get_name = dev->info.get_name;
#else
*info = dev->info;
#endif
}
static struct ctlra_dev_info_t *
ctlra_dev_match_usb_hid(struct ctlra_dev_id_t *id)
const char *
ctlra_info_get_name(const struct ctlra_dev_info_t *info,
enum ctlra_event_type_t type, uint32_t control_id)
{
int vendor = id->usb_hid.vendor_id;
int device = id->usb_hid.device_id;
/* TODO: iter registered static info structs, return if match */
return &CTLRA_DEVICE_INFO_NAME(ni_kontrol_s2_mk2);
//return &CTLRA_DEVICE_INFO_NAME(ni_kontrol_z1);
//return &CTLRA_DEVICE_INFO_NAME(ni_maschine_mikro_mk2);
}
struct ctlra_dev_info_t *
ctlra_dev_get_info_by_id(struct ctlra_dev_id_t *id)
{
struct ctlra_dev_info_t *tmp = NULL;
switch(id->type) {
case CTLRA_DEV_TYPE_USB_HID:
tmp = ctlra_dev_match_usb_hid(id);
break;
default: break;
};
return tmp;
}
const char * ctlra_info_get_name(const struct ctlra_dev_info_t *info,
enum ctlra_event_type_t type,
uint32_t control_id)
{
/* the info parameter already has the appropriate function pointer
* set by the driver, so we don't need the device instance to be
* passed to the get_name() function */
if(!info)
return 0;
@@ -324,13 +326,13 @@ struct ctlra_t *ctlra_create(const struct ctlra_create_opts_t *opts)
int ctlra_impl_accept_dev(struct ctlra_t *ctlra,
int id)
{
if(id < 0 || id >= CTLRA_NUM_DEVS || !devices[id].connect) {
if(id < 0 || id >= __ctlra_device_count || !__ctlra_devices[id].connect) {
CTLRA_WARN(ctlra, "invalid device id recieved %d\n", id);
return 0;
}
struct ctlra_dev_t* dev = ctlra_dev_connect(ctlra,
devices[id].connect,
__ctlra_devices[id].connect,
0x0,
0 /* userdata */,
0x0);
@@ -366,12 +368,10 @@ int ctlra_probe(struct ctlra_t *ctlra,
ctlra->accept_dev_func = accept_func;
ctlra->accept_dev_func_userdata = userdata;
for(; i < CTLRA_NUM_DEVS; i++) {
for(; i < __ctlra_device_count; i++) {
num_accepted += ctlra_impl_accept_dev(ctlra, i);
}
/* probe midi devices here? */
return num_accepted;
}
@@ -424,5 +424,3 @@ void ctlra_exit(struct ctlra_t *ctlra)
free(ctlra);
}
View
@@ -275,20 +275,6 @@ struct ctlra_t *ctlra_create(const struct ctlra_create_opts_t *opts);
int ctlra_probe(struct ctlra_t *ctlra, ctlra_accept_dev_func accept_func,
void *userdata);
/** Add a virtualized device. This function adds a "virtual" device, which
* provides the controls of the physical device by displaying a user
* interface. In order for this function to operate, the device being
* virtualized must provide its info statically via the
* *ctlra_dev_get_info_by_id* API.
*
* The info provided about the device is used to emulate the device
* itself - the normal accept dev callback will be called in the
* application, with the device descriptor filled out as if it was the
* actual hardware plugged in. This allows total emulate of the hardware.
*/
int32_t ctlra_dev_virtualize(struct ctlra_t *ctlra,
struct ctlra_dev_info_t *info);
/** Iterate backends and see if anything has changed - this enables hotplug
* detection and removal of devices.
*/
@@ -307,6 +293,51 @@ void ctlra_exit(struct ctlra_t *ctlra);
*/
int32_t ctlra_dev_disconnect(struct ctlra_dev_t *dev);
/** Retrieve a list of vendors. The returned strings are human readable
* names of the companies/manufacturers of controller hardware. This
* function is to allow eg: a drop-down list of vendors be displayed to
* the user, which are supported by ctlra (and can be virtualized).
*
* Note that the strings pointed to by vendors after this call *remain*
* owned by the Ctlra library - and they must not be freed by the callee.
*
* @param vendors An array of *size* that will be filled in with null
* terminated strings, where each entry is a vendor's name.
* @param size Size of the callee supplied array
* @returns Number of vendors populated in the array
*/
int32_t ctlra_get_vendors(const char *vendors[], int32_t size);
/** Retrieve a list of devices by a specific vendor. The returned strings
* are human-readable names of devices. These names could be presented to
* the user in eg: a drop down box allowing the user to select a specific
* device. One use case could be virtualizing a specific hardware device
*
* @param vendor The vendor from which to find all supported devices. See
* the *ctlra_get_vendors* function to retrieve vendors.
* @param devices An array of at least *size* to be filled in with null
* terminated strings, with each string representing a device.
* @param size Size of the devices array passed in.
* @return The number of devices populated in the array
*/
int32_t ctlra_get_devices_by_vendor(const char *vendor,
const char *devices[],
int32_t size);
/** Add a virtualized device. This function adds a "virtual" device, which
* provides the controls of the physical device by displaying a user
* interface. In order for this function to operate, the device being
* virtualized must provide its info statically in the driver.
*
* The info provided about the device is used to emulate the device
* itself - the normal accept dev callback will be called in the
* application, with the device descriptor filled out as if it was the
* actual hardware plugged in. This allows total emulation of the hardware.
*/
int32_t ctlra_dev_virtualize(struct ctlra_t *ctlra, const char *vendor,
const char *device);
/** Change the Event func. This may be useful when integrating into
* an application that doesn't know yet which event func to attach to
* the device when connecting to it. A dummy event_func can be used, and
@@ -374,16 +405,6 @@ int32_t ctlra_dev_screen_get_data(struct ctlra_dev_t *dev,
void ctlra_dev_get_info(const struct ctlra_dev_t *dev,
struct ctlra_dev_info_t * info);
/** Get the info struct for a controller by an ID. Note that the controller
* hardware itself does not have to be present to retrieve this info. The
* expected utilization of this function is to allow virtual controllers be
* created for testing and hardware-less development.
* @returns A valid pointer, or NULL if the device ID does not support info
*/
struct ctlra_dev_info_t *
ctlra_dev_get_info_by_id(struct ctlra_dev_id_t *id);
/** Get the human readable name for *control_id* from *dev*. The
* control id is passed in eg: event.button.id, or can be any of the
* DEVICE_NAME_CONTROLS enumeration. Ownership of the string *remains* in
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.