From owner-freebsd-current@FreeBSD.ORG Fri Jun 24 07:34:04 2005 Return-Path: X-Original-To: current@FreeBSD.org Delivered-To: freebsd-current@FreeBSD.ORG Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BC48C16A41C for ; Fri, 24 Jun 2005 07:34:04 +0000 (GMT) (envelope-from glebius@FreeBSD.org) Received: from relay.bestcom.ru (relay.bestcom.ru [217.72.144.5]) by mx1.FreeBSD.org (Postfix) with ESMTP id 06EC243D4C for ; Fri, 24 Jun 2005 07:34:03 +0000 (GMT) (envelope-from glebius@FreeBSD.org) Received: from cell.sick.ru (root@cell.sick.ru [217.72.144.68]) by relay.bestcom.ru (8.13.1/8.12.9) with ESMTP id j5O7Y1OW011099 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Fri, 24 Jun 2005 11:34:01 +0400 (MSD) (envelope-from glebius@FreeBSD.org) Received: from cell.sick.ru (glebius@localhost [127.0.0.1]) by cell.sick.ru (8.13.1/8.12.8) with ESMTP id j5O7Y0kt070402 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 24 Jun 2005 11:34:01 +0400 (MSD) (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by cell.sick.ru (8.13.1/8.13.1/Submit) id j5O7Y0fF070401 for current@FreeBSD.org; Fri, 24 Jun 2005 11:34:00 +0400 (MSD) (envelope-from glebius@FreeBSD.org) X-Authentication-Warning: cell.sick.ru: glebius set sender to glebius@FreeBSD.org using -f Date: Fri, 24 Jun 2005 11:34:00 +0400 From: Gleb Smirnoff To: current@FreeBSD.org Message-ID: <20050624073400.GA70323@cell.sick.ru> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="AqsLC8rIMeq19msA" Content-Disposition: inline User-Agent: Mutt/1.5.6i X-Virus-Scanned: ClamAV version devel-20050125, clamav-milter version 0.80ff on relay.bestcom.ru X-Virus-Status: Clean Cc: Subject: who can review&commit kern/82243? X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 24 Jun 2005 07:34:04 -0000 --AqsLC8rIMeq19msA Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Colleagues, recently a patch making csa(4) suspend/resume working. I have tested it on my notebook and it works perfectly. The patch is attached (with small style editing from me) to this message. -- Totus tuus, Glebius. GLEBIUS-RIPN GLEB-RIPE --AqsLC8rIMeq19msA Content-Type: text/plain; charset=koi8-r Content-Disposition: attachment; filename="csa.diff" Index: csa.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/csa.c,v retrieving revision 1.32 diff -u -r1.32 csa.c --- csa.c 1 Mar 2005 08:58:05 -0000 1.32 +++ csa.c 23 Jun 2005 19:42:44 -0000 @@ -87,7 +87,6 @@ struct resource *irq, void *cookie); static driver_intr_t csa_intr; static int csa_initialize(sc_p scp); -static void csa_resetdsp(csa_res *resp); static int csa_downloadimage(csa_res *resp); static devclass_t csa_devclass; @@ -366,15 +365,24 @@ static int csa_resume(device_t dev) { -#if 0 - /* - * XXX: this cannot possibly work - * needs to be properly implemented - */ - csa_detach(dev); - csa_attach(dev); -#endif - return 0; + csa_res *resp; + sc_p scp; + + scp = device_get_softc(dev); + resp = &scp->res; + + /* Initialize the chip. */ + if (csa_initialize(scp)) + return (ENXIO); + + /* Reset the Processor. */ + csa_resetdsp(resp); + + /* Download the Processor Image to the processor. */ + if (csa_downloadimage(resp)) + return (ENXIO); + + return (bus_generic_resume(dev)); } static struct resource * @@ -794,7 +802,7 @@ csa_writeio(resp, BA0_CLKCR1, clkcr1); } -static void +void csa_resetdsp(csa_res *resp) { int i; Index: csapcm.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/csapcm.c,v retrieving revision 1.33 diff -u -r1.33 csapcm.c --- csapcm.c 6 Jan 2005 01:43:19 -0000 1.33 +++ csapcm.c 23 Jun 2005 21:18:39 -0000 @@ -45,6 +45,23 @@ #define GOF_PER_SEC 200 +#define CS461x_AC97_HIGHESTREGTORESTORE 0x26 +#define CS461x_AC97_NUMBER_RESTORE_REGS (CS461x_AC97_HIGHESTREGTORESTORE/2-1) + +#define CS_POWER_DAC 0x0001 +#define CS_POWER_ADC 0x0002 +#define CS_POWER_MIXVON 0x0004 +#define CS_POWER_MIXVOFF 0x0008 +#define CS_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */ +#define CS_AC97_POWER_CONTROL_ADC 0x0100 +#define CS_AC97_POWER_CONTROL_DAC 0x0200 +#define CS_AC97_POWER_CONTROL_MIXVON 0x0400 +#define CS_AC97_POWER_CONTROL_MIXVOFF 0x0800 +#define CS_AC97_POWER_CONTROL_ADC_ON 0x0001 +#define CS_AC97_POWER_CONTROL_DAC_ON 0x0002 +#define CS_AC97_POWER_CONTROL_MIXVON_ON 0x0004 +#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008 + /* device private data */ struct csa_info; @@ -70,6 +87,9 @@ u_long pctl; u_long cctl; struct csa_chinfo pch, rch; + u_int32_t ac97[CS461x_AC97_NUMBER_RESTORE_REGS]; + u_int32_t ac97_powerdown; + u_int32_t ac97_general_purpose; }; /* -------------------------------------------------------------------- */ @@ -84,8 +104,11 @@ static void csa_stopplaydma(struct csa_info *csa); static void csa_stopcapturedma(struct csa_info *csa); static int csa_startdsp(csa_res *resp); +static int csa_stopdsp(csa_res *resp); static int csa_allocres(struct csa_info *scp, device_t dev); static void csa_releaseres(struct csa_info *scp, device_t dev); +static void csa_ac97_suspend(struct csa_info *csa); +static void csa_ac97_resume(struct csa_info *csa); static u_int32_t csa_playfmt[] = { AFMT_U8, @@ -112,16 +135,16 @@ static int csa_active(struct csa_info *csa, int run) { - int old, go; + int old; old = csa->active; csa->active += run; - if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) { - go = csa->active; - if (csa->card->active) - return csa->card->active(go); - } + if ((csa->active > 1) || (csa->active < -1)) + csa->active = 0; + if (csa->card->active) + return (csa->card->active(!(csa->active && old))); + return 0; } @@ -455,6 +478,18 @@ } static int +csa_stopdsp(csa_res *resp) +{ + /* + * Turn off the run, run at frame, and DMA enable bits in the local copy of + * the SP control register. + */ + csa_writemem(resp, BA1_SPCR, 0); + + return (0); +} + +static int csa_setupchan(struct csa_chinfo *ch) { struct csa_info *csa = ch->parent; @@ -833,11 +868,156 @@ return 0; } +static void +csa_ac97_suspend(struct csa_info *csa) +{ + int Count, i; + u_int32_t tmp; + + for(Count = 0x2, i=0; (Count <= CS461x_AC97_HIGHESTREGTORESTORE) && (i < CS461x_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) + { + csa_readcodec(&csa->res, BA0_AC97_RESET + Count, &csa->ac97[i]); + } + /* mute the outputs */ + csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME, 0x8000); + csa_writecodec(&csa->res, BA0_AC97_HEADPHONE_VOLUME, 0x8000); + csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME_MONO, 0x8000); + csa_writecodec(&csa->res, BA0_AC97_PCM_OUT_VOLUME, 0x8000); + /* save the registers that cause pops */ + csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &csa->ac97_powerdown); + csa_readcodec(&csa->res, BA0_AC97_GENERAL_PURPOSE, &csa->ac97_general_purpose); + /* + * And power down everything on the AC97 codec. + * well, for now, only power down the DAC/ADC and MIXER VREFON components. + * trouble with removing VREF. + */ + /* MIXVON*/ + csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); + csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, tmp | CS_AC97_POWER_CONTROL_MIXVON); + /* ADC */ + csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); + csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, tmp | CS_AC97_POWER_CONTROL_ADC); + /* DAC */ + csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); + csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, tmp | CS_AC97_POWER_CONTROL_DAC); +} + +static void +csa_ac97_resume(struct csa_info *csa) +{ + int Count, i; + + /* + * First, we restore the state of the general purpose register. This + * contains the mic select (mic1 or mic2) and if we restore this after + * we restore the mic volume/boost state and mic2 was selected at + * suspend time, we will end up with a brief period of time where mic1 + * is selected with the volume/boost settings for mic2, causing + * acoustic feedback. So we restore the general purpose register + * first, thereby getting the correct mic selected before we restore + * the mic volume/boost. + */ + csa_writecodec(&csa->res, BA0_AC97_GENERAL_PURPOSE, csa->ac97_general_purpose); + /* + * Now, while the outputs are still muted, restore the state of power + * on the AC97 part. + */ + csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, csa->ac97_powerdown); + /* + * Restore just the first set of registers, from register number + * 0x02 to the register number that ulHighestRegToRestore specifies. + */ + for(Count = 0x2, i=0; (Count <= CS461x_AC97_HIGHESTREGTORESTORE) && (i < CS461x_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) + { + csa_writecodec(&csa->res, BA0_AC97_RESET + Count, csa->ac97[i]); + } + +} + +static int +pcmcsa_suspend(device_t dev) +{ + struct csa_info *csa; + csa_res *resp; + + csa = pcm_getdevinfo(dev); + resp = &csa->res; + + csa_active(csa, 1); + + /* playback interrupt disable */ + csa_writemem(resp, BA1_PFIE, (csa_readmem(resp, BA1_PFIE) & ~0x0000f03f) | 0x00000010); + /* capture interrupt disable */ + csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000011); + csa_stopplaydma(csa); + csa_stopcapturedma(csa); + + csa_ac97_suspend(csa); + + csa_resetdsp(resp); + + csa_stopdsp(resp); + /* + * Power down the DAC and ADC. For now leave the other areas on. + */ + csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 0x300); + /* + * Power down the PLL. + */ + csa_writemem(resp, BA0_CLKCR1, 0); + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + csa_writemem(resp, BA0_CLKCR1, csa_readmem(resp, BA0_CLKCR1) & ~CLKCR1_SWCE); + + csa_active(csa, -1); + + return 0; +} + +static int +pcmcsa_resume(device_t dev) +{ + struct csa_info *csa; + csa_res *resp; + + csa = pcm_getdevinfo(dev); + resp = &csa->res; + + csa_active(csa, 1); + + /* cs_hardware_init */ + csa_stopplaydma(csa); + csa_stopcapturedma(csa); + csa_ac97_resume(csa); + if (csa_startdsp(resp)) + return (ENXIO); + /* Enable interrupts on the part. */ + if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0) + csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM); + /* playback interrupt enable */ + csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); + /* capture interrupt enable */ + csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); + /* cs_restart_part */ + csa_setupchan(&csa->pch); + csa_startplaydma(csa); + csa_setupchan(&csa->rch); + csa_startcapturedma(csa); + + csa_active(csa, -1); + + return 0; +} + static device_method_t pcmcsa_methods[] = { /* Device interface */ DEVMETHOD(device_probe , pcmcsa_probe ), DEVMETHOD(device_attach, pcmcsa_attach), DEVMETHOD(device_detach, pcmcsa_detach), + DEVMETHOD(device_suspend, pcmcsa_suspend), + DEVMETHOD(device_resume, pcmcsa_resume), { 0, 0 }, }; Index: csavar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/csavar.h,v retrieving revision 1.4 diff -u -r1.4 csavar.h --- csavar.h 23 Jun 2001 18:00:06 -0000 1.4 +++ csavar.h 23 Jun 2005 19:42:44 -0000 @@ -66,4 +66,5 @@ u_int32_t csa_readmem(csa_res *resp, u_long offset); void csa_writemem(csa_res *resp, u_long offset, u_int32_t data); +void csa_resetdsp(csa_res *resp); #endif /* _CSA_VAR_H */ --AqsLC8rIMeq19msA--