From owner-svn-soc-all@freebsd.org Sun Jun 26 17:01:24 2016 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C44D6B816AD for ; Sun, 26 Jun 2016 17:01:24 +0000 (UTC) (envelope-from iateaca@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A8D3E2AF4 for ; Sun, 26 Jun 2016 17:01:24 +0000 (UTC) (envelope-from iateaca@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id u5QH1OMO001644 for ; Sun, 26 Jun 2016 17:01:24 GMT (envelope-from iateaca@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id u5QH1Ma7000832 for svn-soc-all@FreeBSD.org; Sun, 26 Jun 2016 17:01:22 GMT (envelope-from iateaca@FreeBSD.org) Date: Sun, 26 Jun 2016 17:01:22 GMT Message-Id: <201606261701.u5QH1Ma7000832@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to iateaca@FreeBSD.org using -f From: iateaca@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r305562 - soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Jun 2016 17:01:24 -0000 Author: iateaca Date: Sun Jun 26 17:01:21 2016 New Revision: 305562 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=305562 Log: implement the hda_transfer function in order to transfer the samples between the guest system memory and the sound device TODO this function is called from the codec context and must be synchronized with the hda context using a mutex M bhyve/audio.c M bhyve/audio.h M bhyve/hda_codec.c M bhyve/pci_hda.c M bhyve/pci_hda.h Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.c soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.h soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/hda_codec.c soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.h Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.c ============================================================================== --- soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.c Sun Jun 26 16:38:42 2016 (r305561) +++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.c Sun Jun 26 17:01:21 2016 (r305562) @@ -135,7 +135,7 @@ * @buf - the buffer containing the samples * @count - the number of bytes in buffer */ -ssize_t audio_playback(struct audio *aud, const void *buf, size_t count) +int audio_playback(struct audio *aud, const void *buf, size_t count) { int audio_fd = -1; ssize_t len = 0, total = 0; Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.h ============================================================================== --- soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.h Sun Jun 26 16:38:42 2016 (r305561) +++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/audio.h Sun Jun 26 17:01:21 2016 (r305562) @@ -25,6 +25,7 @@ * audio_init - initialize an instance of audio player * @dev_name - the backend sound device used to play / capture * @dir - dir = 1 for write mode, dir = 0 for read mode + * Returns NULL on error and the address of the audio player instance */ struct audio *audio_init(const char *dev_name, uint8_t dir); @@ -32,6 +33,7 @@ * audio_set_params - reset the sound device and set the audio params * @aud - the audio player to be configured * @params - the audio parameters to be set + * Returns -1 on error and 0 on success */ int audio_set_params(struct audio *aud, struct audio_params *params); @@ -40,7 +42,8 @@ * @aud - the audio player used to play the samples * @buf - the buffer containing the samples * @count - the number of bytes in buffer + * Returns -1 on error and 0 on success */ -ssize_t audio_playback(struct audio *aud, const void *buf, size_t count); +int audio_playback(struct audio *aud, const void *buf, size_t count); #endif /* _AUDIO_EMUL_H_ */ Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/hda_codec.c ============================================================================== --- soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/hda_codec.c Sun Jun 26 16:38:42 2016 (r305561) +++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/hda_codec.c Sun Jun 26 17:01:21 2016 (r305562) @@ -121,6 +121,7 @@ }; struct hda_codec_softc { + struct hda_codec_inst *hci; uint32_t subsystem_id; uint32_t no_nodes; const uint32_t (*get_parameters)[HDA_CODEC_PARAMS_COUNT]; @@ -258,6 +259,7 @@ return -1; } + sc->hci = hci; hci->priv = sc; return 0; @@ -462,21 +464,28 @@ hda_codec_audio_output_do_transfer(void *arg) { struct hda_codec_softc *sc = (struct hda_codec_softc *)arg; + struct hda_codec_inst *hci = NULL; + struct hda_ops *hops = NULL; struct hda_codec_stream *st = NULL; struct audio *aud = NULL; int err; + hci = sc->hci; + assert(hci); + + hops = hci->hops; + assert(hops); + st = &sc->streams[HDA_CODEC_STREAM_OUTPUT]; aud = st->aud; - memset(st->buf, 0x31, sizeof(st->buf)); + err = hops->transfer(hci, st->stream, 1, st->buf, sizeof(st->buf)); + if (err) + return; err = audio_playback(aud, st->buf, sizeof(st->buf)); assert(!err); - usleep(20 * 1000); - - DPRINTF("\n"); return; } Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c ============================================================================== --- soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c Sun Jun 26 16:38:42 2016 (r305561) +++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c Sun Jun 26 17:01:21 2016 (r305562) @@ -22,6 +22,7 @@ #define HDA_STREAM_REGS_BASE 0x80 #define HDA_STREAM_REGS_LEN 0x20 +#define HDA_DMA_ACCESS_LEN (sizeof(uint32_t)) #define HDA_BDL_MAX_LEN 0x0100 /* @@ -59,6 +60,11 @@ uint8_t run; uint8_t dir; + /* bp is the no. of bytes transferred in the current bdle */ + uint32_t bp; + /* be is the no. of bdles transferred in the bdl */ + uint32_t be; + struct hda_bdle_desc bdl[HDA_BDL_MAX_LEN]; uint32_t bdl_cnt; }; @@ -156,6 +162,9 @@ hda_signal_state_change(struct hda_codec_inst *hci); static int hda_response(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol); +static int +hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, void *buf, size_t count); + /* * PCI HDA function declarations @@ -218,6 +227,7 @@ static struct hda_ops hops = { .signal = hda_signal_state_change, .response = hda_response, + .transfer = hda_transfer, }; struct pci_devemu pci_de_hda = { @@ -542,6 +552,8 @@ bdle = (struct hda_bdle *)bdl_vaddr; for (i = 0; i < bdl_cnt; i++, bdle++) { bdle_sz = bdle->len; + assert(!(bdle_sz % HDA_DMA_ACCESS_LEN)); + bdle_addrl = bdle->addrl; bdle_addrh = bdle->addrh; @@ -567,6 +579,11 @@ sc->stream_map[strm] = stream_ind; st->stream = strm; st->dir = dir; + st->bp = 0; + st->be = 0; + hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, 0); + + st->run = 1; err = hda_notify_codecs(sc, 1, strm, dir); assert(!err); @@ -584,6 +601,8 @@ DPRINTF("stream: 0x%x, strm: 0x%x, dir: 0x%x\n", stream_ind, strm, dir); + st->run = 0; + err = hda_notify_codecs(sc, 0, strm, dir); assert(!err); @@ -925,6 +944,84 @@ return 0; } +static int +hda_transfer(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, void *buf, size_t count) +{ + struct hda_softc *sc = NULL; + struct hda_stream_desc *st = NULL; + struct hda_bdle_desc *bdl = NULL; + struct hda_bdle_desc *bdle_desc = NULL; + uint8_t stream_ind = 0; + uint32_t lpib = 0; + uint32_t off = 0; + size_t left = 0; + uint8_t irq = 0; + + assert(hci); + assert(hci->hda); + assert(buf); + assert(!(count % HDA_DMA_ACCESS_LEN)); + + sc = hci->hda; + + assert(stream < HDA_STREAM_TAGS_CNT); + stream_ind = sc->stream_map[stream]; + + st = &sc->streams[stream_ind]; + if (!st->run) { + DPRINTF("Stream 0x%x stopped\n", stream); + return -1; + } + + assert(st->stream == stream); + assert(st->dir == dir); + + off = hda_get_offset_stream(stream_ind); + + lpib = hda_get_reg_by_offset(sc, off + HDAC_SDLPIB); + + bdl = st->bdl; + + assert(st->be < st->bdl_cnt); + assert(st->bp < bdl[st->be].len); + + left = count; + while (left) { + bdle_desc = &bdl[st->be]; + + if (dir) + *(uint32_t *)buf = hda_dma_ld_dword(bdle_desc->addr + st->bp); + else + hda_dma_st_dword(bdle_desc->addr + st->bp, *(uint32_t *)buf); + + buf += HDA_DMA_ACCESS_LEN; + st->bp += HDA_DMA_ACCESS_LEN; + lpib += HDA_DMA_ACCESS_LEN; + left -= HDA_DMA_ACCESS_LEN; + + if (st->bp == bdle_desc->len) { + st->bp = 0; + if (bdle_desc->ioc) + irq = 1; + st->be++; + if (st->be == st->bdl_cnt) { + st->be = 0; + lpib = 0; + } + bdle_desc = &bdl[st->be]; + } + } + + hda_set_reg_by_offset(sc, off + HDAC_SDLPIB, lpib); + + if (irq) { + hda_set_field_by_offset(sc, off + HDAC_SDSTS, HDAC_SDSTS_BCIS, HDAC_SDSTS_BCIS); + hda_update_intr(sc); + } + + return 0; +} + /* * PCI HDA function definitions */ Modified: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.h ============================================================================== --- soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.h Sun Jun 26 16:38:42 2016 (r305561) +++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.h Sun Jun 26 17:01:21 2016 (r305562) @@ -49,6 +49,7 @@ struct hda_ops { int (*signal)(struct hda_codec_inst *hci); int (*response)(struct hda_codec_inst *hci, uint32_t response, uint8_t unsol); + int (*transfer)(struct hda_codec_inst *hci, uint8_t stream, uint8_t dir, void *buf, size_t count); }; #define HDA_EMUL_SET(x) DATA_SET(hda_codec_class_set, x);