[PATCH xf86-video-amdgpu 03/10] Create drmmode_wait_vblank helper

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Michel Dänzer <michel.daenzer@xxxxxxx>

Allows cleaning up the code considerably.

(Ported from radeon commit 99f1d7a474af3683fe1a66f50c0bb8935478ff0a)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_dri2.c     | 97 +++++++++++++++------------------------------------
 src/amdgpu_drv.h      |  2 --
 src/amdgpu_kms.c      | 23 ++++--------
 src/amdgpu_present.c  | 23 ++----------
 src/drmmode_display.c | 63 ++++++++++++++++++++++-----------
 src/drmmode_display.h |  5 +++
 6 files changed, 85 insertions(+), 128 deletions(-)

diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index 52fac03aa..bf85dfa63 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -778,20 +778,6 @@ cleanup:
 	amdgpu_dri2_frame_event_abort(crtc, event_data);
 }
 
-drmVBlankSeqType amdgpu_populate_vbl_request_type(xf86CrtcPtr crtc)
-{
-	drmVBlankSeqType type = 0;
-	int crtc_id = drmmode_get_crtc_id(crtc);
-
-	if (crtc_id == 1)
-		type |= DRM_VBLANK_SECONDARY;
-	else if (crtc_id > 1)
-		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
-		    DRM_VBLANK_HIGH_CRTC_MASK;
-
-	return type;
-}
-
 /*
  * This function should be called on a disabled CRTC only (i.e., CRTC
  * in DPMS-off state). It will calculate the delay necessary to reach
@@ -971,13 +957,11 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	DRI2FrameEventPtr wait_info = NULL;
 	uintptr_t drm_queue_seq = 0;
 	xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE);
 	uint32_t msc_delta;
-	drmVBlank vbl;
-	int ret;
+	uint32_t seq;
 	CARD64 current_msc;
 
 	/* Truncate to match kernel interfaces; means occasional overflow
@@ -1016,17 +1000,13 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 	}
 
 	/* Get current count */
-	vbl.request.type = DRM_VBLANK_RELATIVE;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-	vbl.request.sequence = 0;
-	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-	if (ret) {
+	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "get vblank counter failed: %s\n", strerror(errno));
 		goto out_complete;
 	}
 
-	current_msc = vbl.reply.sequence + msc_delta;
+	current_msc = seq + msc_delta;
 	current_msc &= 0xffffffff;
 
 	drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, AMDGPU_DRM_QUEUE_ID_DEFAULT,
@@ -1053,12 +1033,9 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 		 */
 		if (current_msc >= target_msc)
 			target_msc = current_msc;
-		vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
-		vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-		vbl.request.sequence = target_msc - msc_delta;
-		vbl.request.signal = drm_queue_seq;
-		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-		if (ret) {
+		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT,
+					 target_msc - msc_delta, drm_queue_seq, NULL,
+					 NULL)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "get vblank counter failed: %s\n",
 				   strerror(errno));
@@ -1073,11 +1050,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 	 * If we get here, target_msc has already passed or we don't have one,
 	 * so we queue an event that will satisfy the divisor/remainder equation.
 	 */
-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-
-	vbl.request.sequence = current_msc - (current_msc % divisor) +
-	    remainder - msc_delta;
+	target_msc = current_msc - (current_msc % divisor) + remainder - msc_delta;
 
 	/*
 	 * If calculated remainder is larger than requested remainder,
@@ -1086,11 +1059,10 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 	 * that will happen.
 	 */
 	if ((current_msc % divisor) >= remainder)
-		vbl.request.sequence += divisor;
+		target_msc += divisor;
 
-	vbl.request.signal = drm_queue_seq;
-	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-	if (ret) {
+	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT,
+				 target_msc, drm_queue_seq, NULL, NULL)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "get vblank counter failed: %s\n", strerror(errno));
 		goto out_complete;
@@ -1134,14 +1106,14 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE);
 	uint32_t msc_delta;
-	drmVBlank vbl;
-	int ret, flip = 0;
+	drmVBlankSeqType type;
+	uint32_t seq;
+	int flip = 0;
 	DRI2FrameEventPtr swap_info = NULL;
 	uintptr_t drm_queue_seq;
-	CARD64 current_msc;
+	CARD64 current_msc, event_msc;
 	BoxRec box;
 	RegionRec region;
 
@@ -1204,18 +1176,14 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	}
 
 	/* Get current count */
-	vbl.request.type = DRM_VBLANK_RELATIVE;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-	vbl.request.sequence = 0;
-	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-	if (ret) {
+	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "first get vblank counter failed: %s\n",
 			   strerror(errno));
 		goto blit_fallback;
 	}
 
-	current_msc = vbl.reply.sequence + msc_delta;
+	current_msc = seq + msc_delta;
 	current_msc &= 0xffffffff;
 
 	/* Flips need to be submitted one frame before */
@@ -1237,14 +1205,13 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	 * the swap.
 	 */
 	if (divisor == 0 || current_msc < *target_msc) {
-		vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+		type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 		/* If non-pageflipping, but blitting/exchanging, we need to use
 		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
 		 * on.
 		 */
 		if (flip == 0)
-			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
-		vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
+			type |= DRM_VBLANK_NEXTONMISS;
 
 		/* If target_msc already reached or passed, set it to
 		 * current_msc to ensure we return a reasonable value back
@@ -1253,17 +1220,15 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 		if (current_msc >= *target_msc)
 			*target_msc = current_msc;
 
-		vbl.request.sequence = *target_msc - msc_delta;
-		vbl.request.signal = drm_queue_seq;
-		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-		if (ret) {
+		if (!drmmode_wait_vblank(crtc, type, *target_msc - msc_delta,
+					 drm_queue_seq, NULL, &seq)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "divisor 0 get vblank counter failed: %s\n",
 				   strerror(errno));
 			goto blit_fallback;
 		}
 
-		*target_msc = vbl.reply.sequence + flip + msc_delta;
+		*target_msc = seq + flip + msc_delta;
 		*target_msc &= 0xffffffff;
 		swap_info->frame = *target_msc;
 
@@ -1275,13 +1240,11 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	 * and we need to queue an event that will satisfy the divisor/remainder
 	 * equation.
 	 */
-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+	type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
 	if (flip == 0)
-		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
+		type |= DRM_VBLANK_NEXTONMISS;
 
-	vbl.request.sequence = current_msc - (current_msc % divisor) +
-	    remainder - msc_delta;
+	event_msc = current_msc - (current_msc % divisor) + remainder - msc_delta;
 
 	/*
 	 * If the calculated deadline vbl.request.sequence is smaller than
@@ -1294,15 +1257,13 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
 	 * if we are blitting/exchanging instead of flipping.
 	 */
-	if (vbl.request.sequence <= current_msc)
-		vbl.request.sequence += divisor;
+	if (event_msc <= current_msc)
+		event_msc += divisor;
 
 	/* Account for 1 frame extra pageflip delay if flip > 0 */
-	vbl.request.sequence -= flip;
+	event_msc -= flip;
 
-	vbl.request.signal = drm_queue_seq;
-	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-	if (ret) {
+	if (!drmmode_wait_vblank(crtc, type, event_msc, drm_queue_seq, NULL, &seq)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "final get vblank counter failed: %s\n",
 			   strerror(errno));
@@ -1310,7 +1271,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	}
 
 	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
-	*target_msc = vbl.reply.sequence + flip + msc_delta;
+	*target_msc = seq + flip + msc_delta;
 	*target_msc &= 0xffffffff;
 	swap_info->frame = *target_msc;
 
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 9e088e71a..da71ce848 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -363,6 +363,4 @@ extern xf86CrtcPtr amdgpu_pick_best_crtc(ScrnInfoPtr pScrn,
 
 extern AMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn);
 
-drmVBlankSeqType amdgpu_populate_vbl_request_type(xf86CrtcPtr crtc);
-
 #endif /* _AMDGPU_DRV_H_ */
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 20a552baa..3e2112578 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -624,11 +624,9 @@ amdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 {
 	ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty);
 	drmmode_crtc_private_ptr drmmode_crtc;
 	uintptr_t drm_queue_seq;
-	drmVBlank vbl;
 
 	if (!xf86_crtc || !xf86_crtc->enabled)
 		return;
@@ -650,13 +648,10 @@ amdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 		return;
 	}
 
-	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
-	vbl.request.sequence = 1;
-	vbl.request.signal = drm_queue_seq;
-	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl)) {
+	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+				 1, drm_queue_seq, NULL, NULL)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "drmWaitVBlank failed for PRIME update: %s\n",
+			   "drmmode_wait_vblank failed for PRIME update: %s\n",
 			   strerror(errno));
 		amdgpu_drm_abort_entry(drm_queue_seq);
 		return;
@@ -915,8 +910,6 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 	uintptr_t drm_queue_seq;
 	ScrnInfoPtr scrn;
-	AMDGPUEntPtr pAMDGPUEnt;
-	drmVBlank vbl;
 	DamagePtr pDamage;
 	RegionPtr pRegion;
 	BoxRec extents;
@@ -953,14 +946,10 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 		return;
 	}
 
-	pAMDGPUEnt = AMDGPUEntPriv(scrn);
-	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
-	vbl.request.sequence = 1;
-	vbl.request.signal = drm_queue_seq;
-	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl)) {
+	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+				 1, drm_queue_seq, NULL, NULL)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "drmWaitVBlank failed for scanout update: %s\n",
+			   "drmmode_wait_vblank failed for scanout update: %s\n",
 			   strerror(errno));
 		amdgpu_drm_abort_entry(drm_queue_seq);
 		return;
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index 7769e1fd6..b6792f361 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -55,16 +55,6 @@ struct amdgpu_present_vblank_event {
 	Bool unflip;
 };
 
-static uint32_t crtc_select(int crtc_id)
-{
-	if (crtc_id > 1)
-		return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
-	else if (crtc_id > 0)
-		return DRM_VBLANK_SECONDARY;
-	else
-		return 0;
-}
-
 static RRCrtcPtr
 amdgpu_present_get_crtc(WindowPtr window)
 {
@@ -155,13 +145,8 @@ amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 {
 	xf86CrtcPtr xf86_crtc = crtc->devPrivate;
 	ScreenPtr screen = crtc->pScreen;
-	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
-	int crtc_id = drmmode_get_crtc_id(xf86_crtc);
 	struct amdgpu_present_vblank_event *event;
 	uintptr_t drm_queue_seq;
-	drmVBlank vbl;
-	int ret;
 
 	event = calloc(sizeof(struct amdgpu_present_vblank_event), 1);
 	if (!event)
@@ -177,12 +162,10 @@ amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 		return BadAlloc;
 	}
 
-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | crtc_select(crtc_id);
-	vbl.request.sequence = msc;
-	vbl.request.signal = drm_queue_seq;
 	for (;;) {
-		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-		if (!ret)
+		if (drmmode_wait_vblank(xf86_crtc,
+					DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, msc,
+					drm_queue_seq, NULL, NULL))
 			break;
 		if (errno != EBUSY || !amdgpu_present_flush_drm_events(screen)) {
 			amdgpu_drm_abort_entry(drm_queue_seq);
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 93f6d271c..1a805b82d 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -189,6 +189,41 @@ drmmode_ConvertToKMode(ScrnInfoPtr scrn,
 
 }
 
+/*
+ * Utility helper for drmWaitVBlank
+ */
+Bool
+drmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
+		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
+		    uint32_t *result_seq)
+{
+	int crtc_id = drmmode_get_crtc_id(crtc);
+	ScrnInfoPtr scrn = crtc->scrn;
+	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+	drmVBlank vbl;
+
+	if (crtc_id == 1)
+		type |= DRM_VBLANK_SECONDARY;
+	else if (crtc_id > 1)
+		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
+			DRM_VBLANK_HIGH_CRTC_MASK;
+
+	vbl.request.type = type;
+	vbl.request.sequence = target_seq;
+	vbl.request.signal = signal;
+
+	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0)
+		return FALSE;
+
+	if (ust)
+		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
+			vbl.reply.tval_usec;
+	if (result_seq)
+		*result_seq = vbl.reply.sequence;
+
+	return TRUE;
+}
+
 /*
  * Retrieves present time in microseconds that is compatible
  * with units used by vblank timestamps. Depending on the kernel
@@ -219,23 +254,15 @@ int drmmode_get_current_ust(int drm_fd, CARD64 * ust)
 int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
 {
 	ScrnInfoPtr scrn = crtc->scrn;
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
-	drmVBlank vbl;
-	int ret;
-
-	vbl.request.type = DRM_VBLANK_RELATIVE;
-	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-	vbl.request.sequence = 0;
+	uint32_t seq;
 
-	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-	if (ret) {
+	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 			   "get vblank counter failed: %s\n", strerror(errno));
-		return ret;
+		return -1;
 	}
 
-	*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
-	*msc = vbl.reply.sequence;
+	*msc = seq;
 
 	return Success;
 }
@@ -252,7 +279,7 @@ drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
 	drmmode_crtc->pending_dpms_mode = mode;
 
 	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
-		drmVBlank vbl;
+		uint32_t seq;
 
 		/* Wait for any pending flip to finish */
 		if (drmmode_crtc->flip_pending)
@@ -262,20 +289,14 @@ drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
 		 * On->Off transition: record the last vblank time,
 		 * sequence number and frame period.
 		 */
-		vbl.request.type = DRM_VBLANK_RELATIVE;
-		vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
-		vbl.request.sequence = 0;
-		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
-		if (ret)
+		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
+					 &seq))
 			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
 				   "%s cannot get last vblank counter\n",
 				   __func__);
 		else {
-			CARD64 seq = (CARD64) vbl.reply.sequence;
 			CARD64 nominal_frame_rate, pix_in_frame;
 
-			ust = ((CARD64) vbl.reply.tval_sec * 1000000) +
-			    vbl.reply.tval_usec;
 			drmmode_crtc->dpms_last_ust = ust;
 			drmmode_crtc->dpms_last_seq = seq;
 			nominal_frame_rate = crtc->mode.Clock;
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index bece0ce73..ba7ec68e1 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -216,4 +216,9 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc);
 int drmmode_get_current_ust(int drm_fd, CARD64 * ust);
 
+Bool drmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
+			 uint32_t target_seq, unsigned long signal,
+			 uint64_t *ust, uint32_t *result_seq);
+
+
 #endif
-- 
2.14.1



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux