usbh_audio.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*
  2. * Copyright (c) 2022, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbh_core.h"
  7. #include "usbh_audio.h"
  8. #undef USB_DBG_TAG
  9. #define USB_DBG_TAG "usbh_audio"
  10. #include "usb_log.h"
  11. #define DEV_FORMAT "/dev/audio%d"
  12. /* general descriptor field offsets */
  13. #define DESC_bLength 0 /** Length offset */
  14. #define DESC_bDescriptorType 1 /** Descriptor type offset */
  15. #define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
  16. /* interface descriptor field offsets */
  17. #define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
  18. #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
  19. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[128];
  20. static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
  21. static uint32_t g_devinuse = 0;
  22. static struct usbh_audio *usbh_audio_class_alloc(void)
  23. {
  24. uint8_t devno;
  25. for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
  26. if ((g_devinuse & (1U << devno)) == 0) {
  27. g_devinuse |= (1U << devno);
  28. memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
  29. g_audio_class[devno].minor = devno;
  30. return &g_audio_class[devno];
  31. }
  32. }
  33. return NULL;
  34. }
  35. static void usbh_audio_class_free(struct usbh_audio *audio_class)
  36. {
  37. uint8_t devno = audio_class->minor;
  38. if (devno < 32) {
  39. g_devinuse &= ~(1U << devno);
  40. }
  41. memset(audio_class, 0, sizeof(struct usbh_audio));
  42. }
  43. int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution)
  44. {
  45. struct usb_setup_packet *setup;
  46. struct usb_endpoint_descriptor *ep_desc;
  47. uint8_t mult;
  48. uint16_t mps;
  49. int ret;
  50. uint8_t intf = 0xff;
  51. uint8_t altsetting = 1;
  52. if (!audio_class || !audio_class->hport) {
  53. return -USB_ERR_INVAL;
  54. }
  55. setup = audio_class->hport->setup;
  56. if (audio_class->is_opened) {
  57. return 0;
  58. }
  59. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  60. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  61. intf = audio_class->as_msg_table[i].stream_intf;
  62. for (uint8_t j = 1; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
  63. if (audio_class->as_msg_table[i].as_format[j].bBitResolution == bitresolution) {
  64. for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
  65. uint32_t freq = 0;
  66. memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
  67. if (freq == samp_freq) {
  68. altsetting = j;
  69. goto freq_found;
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. return -USB_ERR_NODEV;
  77. freq_found:
  78. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
  79. setup->bRequest = USB_REQUEST_SET_INTERFACE;
  80. setup->wValue = altsetting;
  81. setup->wIndex = intf;
  82. setup->wLength = 0;
  83. ret = usbh_control_transfer(audio_class->hport, setup, NULL);
  84. if (ret < 0) {
  85. return ret;
  86. }
  87. ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
  88. if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].ep_attr & AUDIO_EP_CONTROL_SAMPLING_FEQ) {
  89. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
  90. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  91. setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
  92. setup->wIndex = ep_desc->bEndpointAddress;
  93. setup->wLength = 3;
  94. memcpy(g_audio_buf, &samp_freq, 3);
  95. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  96. if (ret < 0) {
  97. return ret;
  98. }
  99. }
  100. mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
  101. mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
  102. if (ep_desc->bEndpointAddress & 0x80) {
  103. audio_class->isoin_mps = mps * (mult + 1);
  104. USBH_EP_INIT(audio_class->isoin, ep_desc);
  105. } else {
  106. audio_class->isoout_mps = mps * (mult + 1);
  107. USBH_EP_INIT(audio_class->isoout, ep_desc);
  108. }
  109. USB_LOG_INFO("Open audio stream :%s, altsetting: %u\r\n", name, altsetting);
  110. audio_class->is_opened = true;
  111. return ret;
  112. }
  113. int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
  114. {
  115. struct usb_setup_packet *setup;
  116. struct usb_endpoint_descriptor *ep_desc;
  117. int ret;
  118. uint8_t intf = 0xff;
  119. uint8_t altsetting = 1;
  120. if (!audio_class || !audio_class->hport) {
  121. return -USB_ERR_INVAL;
  122. }
  123. setup = audio_class->hport->setup;
  124. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  125. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  126. intf = audio_class->as_msg_table[i].stream_intf;
  127. }
  128. }
  129. if (intf == 0xff) {
  130. return -USB_ERR_NODEV;
  131. }
  132. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
  133. setup->bRequest = USB_REQUEST_SET_INTERFACE;
  134. setup->wValue = 0;
  135. setup->wIndex = intf;
  136. setup->wLength = 0;
  137. ret = usbh_control_transfer(audio_class->hport, setup, NULL);
  138. if (ret < 0) {
  139. return ret;
  140. }
  141. USB_LOG_INFO("Close audio stream :%s\r\n", name);
  142. audio_class->is_opened = false;
  143. ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
  144. if (ep_desc->bEndpointAddress & 0x80) {
  145. if (audio_class->isoin) {
  146. audio_class->isoin = NULL;
  147. }
  148. } else {
  149. if (audio_class->isoout) {
  150. audio_class->isoout = NULL;
  151. }
  152. }
  153. return ret;
  154. }
  155. int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume)
  156. {
  157. struct usb_setup_packet *setup;
  158. int ret;
  159. uint8_t feature_id = 0xff;
  160. uint16_t volume_hex;
  161. if (!audio_class || !audio_class->hport) {
  162. return -USB_ERR_INVAL;
  163. }
  164. if (volume > 100) {
  165. return -USB_ERR_INVAL;
  166. }
  167. setup = audio_class->hport->setup;
  168. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  169. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  170. feature_id = audio_class->as_msg_table[i].feature_terminal_id;
  171. }
  172. }
  173. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  174. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  175. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  176. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  177. setup->wLength = 2;
  178. volume_hex = -0xDB00 / 100 * volume + 0xdb00;
  179. memcpy(g_audio_buf, &volume_hex, 2);
  180. ret = usbh_control_transfer(audio_class->hport, setup, NULL);
  181. return ret;
  182. }
  183. int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
  184. {
  185. struct usb_setup_packet *setup;
  186. int ret;
  187. uint8_t feature_id = 0xff;
  188. if (!audio_class || !audio_class->hport) {
  189. return -USB_ERR_INVAL;
  190. }
  191. setup = audio_class->hport->setup;
  192. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  193. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  194. feature_id = audio_class->as_msg_table[i].feature_terminal_id;
  195. }
  196. }
  197. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  198. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  199. setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
  200. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  201. setup->wLength = 1;
  202. memcpy(g_audio_buf, &mute, 1);
  203. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  204. return ret;
  205. }
  206. void usbh_audio_list_module(struct usbh_audio *audio_class)
  207. {
  208. USB_LOG_INFO("============= Audio module information ===================\r\n");
  209. USB_LOG_RAW("bcdADC :%04x\r\n", audio_class->bcdADC);
  210. USB_LOG_RAW("Num of audio stream :%u\r\n", audio_class->stream_intf_num);
  211. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  212. USB_LOG_RAW("\tstream name :%s\r\n", audio_class->as_msg_table[i].stream_name);
  213. USB_LOG_RAW("\tstream intf :%u\r\n", audio_class->as_msg_table[i].stream_intf);
  214. USB_LOG_RAW("\tNum of altsetting :%u\r\n", audio_class->as_msg_table[i].num_of_altsetting);
  215. for (uint8_t j = 0; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
  216. if (j == 0) {
  217. USB_LOG_RAW("\t\tIngore altsetting 0\r\n");
  218. continue;
  219. }
  220. USB_LOG_RAW("\t\tAltsetting :%u\r\n", j);
  221. USB_LOG_RAW("\t\t\tbNrChannels :%u\r\n", audio_class->as_msg_table[i].as_format[j].bNrChannels);
  222. USB_LOG_RAW("\t\t\tbBitResolution :%u\r\n", audio_class->as_msg_table[i].as_format[j].bBitResolution);
  223. USB_LOG_RAW("\t\t\tbSamFreqType :%u\r\n", audio_class->as_msg_table[i].as_format[j].bSamFreqType);
  224. for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
  225. uint32_t freq = 0;
  226. memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
  227. USB_LOG_RAW("\t\t\t\tSampleFreq :%u\r\n", freq);
  228. }
  229. }
  230. }
  231. USB_LOG_INFO("============= Audio module information ===================\r\n");
  232. }
  233. static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
  234. {
  235. int ret;
  236. uint8_t cur_iface = 0xff;
  237. uint8_t cur_iface_count = 0xff;
  238. uint8_t cur_alt_setting = 0xff;
  239. uint8_t input_offset = 0;
  240. uint8_t output_offset = 0;
  241. uint8_t feature_unit_offset = 0;
  242. uint8_t *p;
  243. struct usbh_audio *audio_class = usbh_audio_class_alloc();
  244. if (audio_class == NULL) {
  245. USB_LOG_ERR("Fail to alloc audio_class\r\n");
  246. return -USB_ERR_NOMEM;
  247. }
  248. audio_class->hport = hport;
  249. audio_class->ctrl_intf = intf;
  250. hport->config.intf[intf].priv = audio_class;
  251. p = hport->raw_config_desc;
  252. while (p[DESC_bLength]) {
  253. switch (p[DESC_bDescriptorType]) {
  254. case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
  255. cur_iface_count = p[3];
  256. break;
  257. case USB_DESCRIPTOR_TYPE_INTERFACE:
  258. cur_iface = p[INTF_DESC_bInterfaceNumber];
  259. cur_alt_setting = p[INTF_DESC_bAlternateSetting];
  260. break;
  261. case USB_DESCRIPTOR_TYPE_ENDPOINT:
  262. break;
  263. case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
  264. if (cur_iface == audio_class->ctrl_intf) {
  265. switch (p[DESC_bDescriptorSubType]) {
  266. case AUDIO_CONTROL_HEADER: {
  267. struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
  268. audio_class->bcdADC = desc->bcdADC;
  269. audio_class->bInCollection = desc->bInCollection;
  270. } break;
  271. case AUDIO_CONTROL_INPUT_TERMINAL: {
  272. struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
  273. memcpy(&audio_class->ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
  274. input_offset++;
  275. } break;
  276. case AUDIO_CONTROL_OUTPUT_TERMINAL: {
  277. struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
  278. memcpy(&audio_class->ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
  279. output_offset++;
  280. } break;
  281. case AUDIO_CONTROL_FEATURE_UNIT: {
  282. struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
  283. memcpy(&audio_class->ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
  284. feature_unit_offset++;
  285. } break;
  286. case AUDIO_CONTROL_PROCESSING_UNIT:
  287. break;
  288. default:
  289. break;
  290. }
  291. } else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
  292. switch (p[DESC_bDescriptorSubType]) {
  293. case AUDIO_STREAMING_GENERAL: {
  294. struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p;
  295. /* all altsetting have the same general */
  296. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].stream_intf = cur_iface;
  297. memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_general, desc, sizeof(struct audio_cs_if_as_general_descriptor));
  298. } break;
  299. case AUDIO_STREAMING_FORMAT_TYPE: {
  300. struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
  301. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].num_of_altsetting = (cur_alt_setting + 1);
  302. memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, desc->bLength);
  303. } break;
  304. default:
  305. break;
  306. }
  307. }
  308. break;
  309. case AUDIO_ENDPOINT_DESCRIPTOR_TYPE:
  310. if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
  311. if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) {
  312. struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p;
  313. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes;
  314. }
  315. }
  316. break;
  317. default:
  318. break;
  319. }
  320. /* skip to next descriptor */
  321. p += p[DESC_bLength];
  322. }
  323. if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
  324. USB_LOG_ERR("Audio descriptor is invalid\r\n");
  325. return -USB_ERR_INVAL;
  326. }
  327. audio_class->stream_intf_num = input_offset;
  328. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  329. /* Search 0x0101 in input or output desc */
  330. for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
  331. if (audio_class->as_msg_table[i].as_general.bTerminalLink == audio_class->ac_msg_table[streamidx].ac_input.bTerminalID) {
  332. /* INPUT --> FEATURE UNIT --> OUTPUT */
  333. audio_class->as_msg_table[i].input_terminal_id = audio_class->ac_msg_table[streamidx].ac_input.bTerminalID;
  334. /* Search input terminal id in feature desc */
  335. for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
  336. if (audio_class->ac_msg_table[streamidx].ac_input.bTerminalID == audio_class->ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
  337. audio_class->as_msg_table[i].feature_terminal_id = audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID;
  338. /* Search feature unit id in output desc */
  339. for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
  340. if (audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID == audio_class->ac_msg_table[outputid].ac_output.bSourceID) {
  341. audio_class->as_msg_table[i].output_terminal_id = audio_class->ac_msg_table[outputid].ac_output.bTerminalID;
  342. switch (audio_class->ac_msg_table[outputid].ac_output.wTerminalType) {
  343. case AUDIO_OUTTERM_SPEAKER:
  344. audio_class->as_msg_table[i].stream_name = "speaker";
  345. break;
  346. case AUDIO_OUTTERM_HEADPHONES:
  347. audio_class->as_msg_table[i].stream_name = "headphoens";
  348. break;
  349. case AUDIO_OUTTERM_HEADDISPLAY:
  350. audio_class->as_msg_table[i].stream_name = "headdisplay";
  351. break;
  352. default:
  353. audio_class->as_msg_table[i].stream_name = "unknown";
  354. break;
  355. }
  356. break;
  357. }
  358. }
  359. break;
  360. }
  361. }
  362. } else if (audio_class->as_msg_table[i].as_general.bTerminalLink == audio_class->ac_msg_table[streamidx].ac_output.bTerminalID) {
  363. /* OUTPUT --> FEATURE UNIT --> INPUT */
  364. audio_class->as_msg_table[i].output_terminal_id = audio_class->ac_msg_table[streamidx].ac_output.bTerminalID;
  365. /* Search output terminal id in feature desc */
  366. for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
  367. if (audio_class->ac_msg_table[streamidx].ac_output.bSourceID == audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
  368. audio_class->as_msg_table[i].feature_terminal_id = audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID;
  369. /* Search feature unit id in input desc */
  370. for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
  371. if (audio_class->ac_msg_table[featureidx].ac_feature_unit.bSourceID == audio_class->ac_msg_table[inputid].ac_input.bTerminalID) {
  372. audio_class->as_msg_table[i].input_terminal_id = audio_class->ac_msg_table[inputid].ac_input.bTerminalID;
  373. switch (audio_class->ac_msg_table[inputid].ac_input.wTerminalType) {
  374. case AUDIO_INTERM_MIC:
  375. audio_class->as_msg_table[i].stream_name = "mic";
  376. break;
  377. default:
  378. audio_class->as_msg_table[i].stream_name = "unknown";
  379. break;
  380. }
  381. break;
  382. }
  383. }
  384. break;
  385. }
  386. }
  387. }
  388. }
  389. }
  390. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  391. ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
  392. if (ret < 0) {
  393. USB_LOG_ERR("Fail to close audio stream :%s\r\n", audio_class->as_msg_table[i].stream_name);
  394. return ret;
  395. }
  396. }
  397. usbh_audio_list_module(audio_class);
  398. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
  399. USB_LOG_INFO("Register Audio Class:%s\r\n", hport->config.intf[intf].devname);
  400. usbh_audio_run(audio_class);
  401. return 0;
  402. }
  403. static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
  404. {
  405. int ret = 0;
  406. struct usbh_audio *audio_class = (struct usbh_audio *)hport->config.intf[intf].priv;
  407. if (audio_class) {
  408. if (audio_class->isoin) {
  409. }
  410. if (audio_class->isoout) {
  411. }
  412. if (hport->config.intf[intf].devname[0] != '\0') {
  413. USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
  414. usbh_audio_stop(audio_class);
  415. }
  416. usbh_audio_class_free(audio_class);
  417. }
  418. return ret;
  419. }
  420. static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
  421. {
  422. (void)hport;
  423. (void)intf;
  424. return 0;
  425. }
  426. static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
  427. {
  428. (void)hport;
  429. (void)intf;
  430. return 0;
  431. }
  432. __WEAK void usbh_audio_run(struct usbh_audio *audio_class)
  433. {
  434. (void)audio_class;
  435. }
  436. __WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
  437. {
  438. (void)audio_class;
  439. }
  440. const struct usbh_class_driver audio_ctrl_class_driver = {
  441. .driver_name = "audio_ctrl",
  442. .connect = usbh_audio_ctrl_connect,
  443. .disconnect = usbh_audio_ctrl_disconnect
  444. };
  445. const struct usbh_class_driver audio_streaming_class_driver = {
  446. .driver_name = "audio_streaming",
  447. .connect = usbh_audio_data_connect,
  448. .disconnect = usbh_audio_data_disconnect
  449. };
  450. CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
  451. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
  452. .class = USB_DEVICE_CLASS_AUDIO,
  453. .subclass = AUDIO_SUBCLASS_AUDIOCONTROL,
  454. .protocol = 0x00,
  455. .id_table = NULL,
  456. .class_driver = &audio_ctrl_class_driver
  457. };
  458. CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
  459. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
  460. .class = USB_DEVICE_CLASS_AUDIO,
  461. .subclass = AUDIO_SUBCLASS_AUDIOSTREAMING,
  462. .protocol = 0x00,
  463. .id_table = NULL,
  464. .class_driver = &audio_streaming_class_driver
  465. };