@@ -88,6 +88,25 @@ MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
8888
8989#define OPTi9XX_MC_REG (n ) n
9090
91+ enum {
92+ MIRO_ACI_MASTER ,
93+ MIRO_ACI_MIC ,
94+ MIRO_ACI_LINE ,
95+ MIRO_ACI_CD ,
96+ MIRO_ACI_SYNTH ,
97+ MIRO_ACI_PCM ,
98+ MIRO_ACI_LINE1 ,
99+ MIRO_ACI_LINE2 ,
100+ MIRO_ACI_EQ1 ,
101+ MIRO_ACI_EQ2 ,
102+ MIRO_ACI_EQ3 ,
103+ MIRO_ACI_EQ4 ,
104+ MIRO_ACI_EQ5 ,
105+ MIRO_ACI_EQ6 ,
106+ MIRO_ACI_EQ7 ,
107+ MIRO_ACI_COUNT ,
108+ };
109+
91110struct snd_miro {
92111 unsigned short hardware ;
93112 unsigned char password ;
@@ -102,6 +121,7 @@ struct snd_miro {
102121
103122 spinlock_t lock ;
104123 struct snd_pcm * pcm ;
124+ struct snd_wss * codec ;
105125
106126 long wss_base ;
107127 int irq ;
@@ -113,6 +133,12 @@ struct snd_miro {
113133
114134 struct snd_card * card ;
115135 struct snd_miro_aci * aci ;
136+ #ifdef CONFIG_PM
137+ unsigned char aci_saved [MIRO_ACI_COUNT ][2 ];
138+ unsigned char aci_saved_amp ;
139+ unsigned char aci_saved_preamp ;
140+ unsigned char aci_saved_solomode ;
141+ #endif
116142};
117143
118144static struct snd_miro_aci aci_device ;
@@ -664,6 +690,44 @@ static const unsigned char aci_init_values[][2] = {
664690 { ACI_SET_MASTER + 1 , 0x20 },
665691};
666692
693+ #ifdef CONFIG_PM
694+ static const unsigned char snd_miro_saved_get_regs [MIRO_ACI_COUNT ] = {
695+ [MIRO_ACI_MASTER ] = ACI_GET_MASTER ,
696+ [MIRO_ACI_MIC ] = ACI_GET_MIC ,
697+ [MIRO_ACI_LINE ] = ACI_GET_LINE ,
698+ [MIRO_ACI_CD ] = ACI_GET_CD ,
699+ [MIRO_ACI_SYNTH ] = ACI_GET_SYNTH ,
700+ [MIRO_ACI_PCM ] = ACI_GET_PCM ,
701+ [MIRO_ACI_LINE1 ] = ACI_GET_LINE1 ,
702+ [MIRO_ACI_LINE2 ] = ACI_GET_LINE2 ,
703+ [MIRO_ACI_EQ1 ] = ACI_GET_EQ1 ,
704+ [MIRO_ACI_EQ2 ] = ACI_GET_EQ2 ,
705+ [MIRO_ACI_EQ3 ] = ACI_GET_EQ3 ,
706+ [MIRO_ACI_EQ4 ] = ACI_GET_EQ4 ,
707+ [MIRO_ACI_EQ5 ] = ACI_GET_EQ5 ,
708+ [MIRO_ACI_EQ6 ] = ACI_GET_EQ6 ,
709+ [MIRO_ACI_EQ7 ] = ACI_GET_EQ7 ,
710+ };
711+
712+ static const unsigned char snd_miro_saved_set_regs [MIRO_ACI_COUNT ] = {
713+ [MIRO_ACI_MASTER ] = ACI_SET_MASTER ,
714+ [MIRO_ACI_MIC ] = ACI_SET_MIC ,
715+ [MIRO_ACI_LINE ] = ACI_SET_LINE ,
716+ [MIRO_ACI_CD ] = ACI_SET_CD ,
717+ [MIRO_ACI_SYNTH ] = ACI_SET_SYNTH ,
718+ [MIRO_ACI_PCM ] = ACI_SET_PCM ,
719+ [MIRO_ACI_LINE1 ] = ACI_SET_LINE1 ,
720+ [MIRO_ACI_LINE2 ] = ACI_SET_LINE2 ,
721+ [MIRO_ACI_EQ1 ] = ACI_SET_EQ1 ,
722+ [MIRO_ACI_EQ2 ] = ACI_SET_EQ2 ,
723+ [MIRO_ACI_EQ3 ] = ACI_SET_EQ3 ,
724+ [MIRO_ACI_EQ4 ] = ACI_SET_EQ4 ,
725+ [MIRO_ACI_EQ5 ] = ACI_SET_EQ5 ,
726+ [MIRO_ACI_EQ6 ] = ACI_SET_EQ6 ,
727+ [MIRO_ACI_EQ7 ] = ACI_SET_EQ7 ,
728+ };
729+ #endif
730+
667731static int snd_set_aci_init_values (struct snd_miro * miro )
668732{
669733 int idx , error ;
@@ -702,11 +766,116 @@ static int snd_set_aci_init_values(struct snd_miro *miro)
702766 }
703767 aci -> aci_amp = 0 ;
704768 aci -> aci_preamp = 0 ;
705- aci -> aci_solomode = 1 ;
769+ aci -> aci_solomode = 0 ;
770+
771+ return 0 ;
772+ }
773+
774+ static int snd_miro_aci_force_known_state (struct snd_miro_aci * aci )
775+ {
776+ int i , err ;
777+
778+ for (i = 0 ; i < 3 ; i ++ ) {
779+ err = snd_aci_cmd (aci , ACI_ERROR_OP , -1 , -1 );
780+ if (err < 0 )
781+ return err ;
782+ }
706783
707784 return 0 ;
708785}
709786
787+ static int snd_miro_aci_initialize (struct snd_miro_aci * aci )
788+ {
789+ int err ;
790+
791+ err = snd_aci_cmd (aci , ACI_INIT , -1 , -1 );
792+ if (err < 0 )
793+ return err ;
794+ err = snd_aci_cmd (aci , ACI_ERROR_OP , ACI_ERROR_OP , ACI_ERROR_OP );
795+ if (err < 0 )
796+ return err ;
797+
798+ return snd_aci_cmd (aci , ACI_ERROR_OP , ACI_ERROR_OP , ACI_ERROR_OP );
799+ }
800+
801+ #ifdef CONFIG_PM
802+ static int snd_miro_save_aci_state (struct snd_miro * miro )
803+ {
804+ struct snd_miro_aci * aci = miro -> aci ;
805+ int i , limit , value ;
806+
807+ limit = aci -> aci_product == 'C' ? MIRO_ACI_COUNT : MIRO_ACI_LINE2 + 1 ;
808+ for (i = 0 ; i < limit ; i ++ ) {
809+ value = aci_getvalue (aci , snd_miro_saved_get_regs [i ]);
810+ if (value < 0 )
811+ return value ;
812+ miro -> aci_saved [i ][1 ] = value ;
813+
814+ value = aci_getvalue (aci , snd_miro_saved_get_regs [i ] + 1 );
815+ if (value < 0 )
816+ return value ;
817+ miro -> aci_saved [i ][0 ] = value ;
818+ }
819+
820+ miro -> aci_saved_amp = aci -> aci_amp ;
821+ if (aci -> aci_version <= 176 ) {
822+ miro -> aci_saved_preamp = aci -> aci_preamp ;
823+ } else {
824+ value = aci_getvalue (aci , ACI_GET_PREAMP );
825+ if (value < 0 )
826+ return value ;
827+ miro -> aci_saved_preamp = value ;
828+ }
829+
830+ value = aci_getvalue (aci , ACI_S_GENERAL );
831+ if (value < 0 )
832+ return value ;
833+ miro -> aci_saved_solomode = !(value & 0x20 );
834+
835+ return 0 ;
836+ }
837+
838+ static int snd_miro_restore_aci_state (struct snd_miro * miro )
839+ {
840+ struct snd_miro_aci * aci = miro -> aci ;
841+ int i , limit , err , left_reg ;
842+
843+ err = snd_set_aci_init_values (miro );
844+ if (err < 0 )
845+ return err ;
846+
847+ limit = aci -> aci_product == 'C' ? MIRO_ACI_COUNT : MIRO_ACI_LINE2 + 1 ;
848+ for (i = 0 ; i < limit ; i ++ ) {
849+ left_reg = snd_miro_saved_set_regs [i ] == ACI_SET_MASTER ?
850+ snd_miro_saved_set_regs [i ] + 1 :
851+ snd_miro_saved_set_regs [i ] + 8 ;
852+ err = aci_setvalue (aci , left_reg , miro -> aci_saved [i ][0 ]);
853+ if (err < 0 )
854+ return err ;
855+ err = aci_setvalue (aci , snd_miro_saved_set_regs [i ],
856+ miro -> aci_saved [i ][1 ]);
857+ if (err < 0 )
858+ return err ;
859+ }
860+
861+ err = aci_setvalue (aci , ACI_SET_POWERAMP , miro -> aci_saved_amp );
862+ if (err < 0 )
863+ return err ;
864+ err = aci_setvalue (aci , ACI_SET_PREAMP , miro -> aci_saved_preamp );
865+ if (err < 0 )
866+ return err ;
867+ err = aci_setvalue (aci , ACI_SET_SOLOMODE , miro -> aci_saved_solomode );
868+ if (err < 0 )
869+ return err ;
870+
871+ aci -> aci_amp = miro -> aci_saved_amp ;
872+ aci -> aci_preamp = miro -> aci_saved_preamp ;
873+ aci -> aci_solomode = miro -> aci_saved_solomode ;
874+
875+ return 0 ;
876+ }
877+ #endif
878+
710879static int snd_miro_mixer (struct snd_card * card ,
711880 struct snd_miro * miro )
712881{
@@ -1203,7 +1372,7 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
12031372 struct snd_miro * miro )
12041373{
12051374 unsigned char regval ;
1206- int i ;
1375+ int err ;
12071376 struct snd_miro_aci * aci = & aci_device ;
12081377
12091378 miro -> aci = aci ;
@@ -1224,12 +1393,12 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
12241393 return - ENOMEM ;
12251394 }
12261395
1227- /* force ACI into a known state */
1228- for ( i = 0 ; i < 3 ; i ++ )
1229- if (snd_aci_cmd ( aci , ACI_ERROR_OP , -1 , -1 ) < 0 ) {
1230- dev_err (card -> dev , "can't force aci into known state.\n" );
1231- return - ENXIO ;
1232- }
1396+ /* force ACI into a known state */
1397+ err = snd_miro_aci_force_known_state ( aci );
1398+ if (err < 0 ) {
1399+ dev_err (card -> dev , "can't force aci into known state.\n" );
1400+ return - ENXIO ;
1401+ }
12331402
12341403 aci -> aci_vendor = snd_aci_cmd (aci , ACI_READ_IDCODE , -1 , -1 );
12351404 aci -> aci_product = snd_aci_cmd (aci , ACI_READ_IDCODE , -1 , -1 );
@@ -1246,9 +1415,8 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
12461415 return - ENXIO ;
12471416 }
12481417
1249- if (snd_aci_cmd (aci , ACI_INIT , -1 , -1 ) < 0 ||
1250- snd_aci_cmd (aci , ACI_ERROR_OP , ACI_ERROR_OP , ACI_ERROR_OP ) < 0 ||
1251- snd_aci_cmd (aci , ACI_ERROR_OP , ACI_ERROR_OP , ACI_ERROR_OP ) < 0 ) {
1418+ err = snd_miro_aci_initialize (aci );
1419+ if (err < 0 ) {
12521420 dev_err (card -> dev , "can't initialize aci.\n" );
12531421 return - ENXIO ;
12541422 }
@@ -1299,6 +1467,7 @@ static int snd_miro_probe(struct snd_card *card)
12991467 WSS_HW_DETECT , 0 , & codec );
13001468 if (error < 0 )
13011469 return error ;
1470+ miro -> codec = codec ;
13021471
13031472 error = snd_wss_pcm (codec , 0 );
13041473 if (error < 0 )
@@ -1408,6 +1577,7 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
14081577 return error ;
14091578
14101579 miro = card -> private_data ;
1580+ miro -> card = card ;
14111581
14121582 error = snd_card_miro_detect (card , miro );
14131583 if (error < 0 ) {
@@ -1470,12 +1640,69 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
14701640 return 0 ;
14711641}
14721642
1643+ #ifdef CONFIG_PM
1644+ static int snd_miro_suspend (struct snd_card * card )
1645+ {
1646+ struct snd_miro * miro = card -> private_data ;
1647+ int error ;
1648+
1649+ error = snd_miro_save_aci_state (miro );
1650+ if (error < 0 )
1651+ return error ;
1652+
1653+ snd_power_change_state (card , SNDRV_CTL_POWER_D3hot );
1654+ miro -> codec -> suspend (miro -> codec );
1655+ return 0 ;
1656+ }
1657+
1658+ static int snd_miro_resume (struct snd_card * card )
1659+ {
1660+ struct snd_miro * miro = card -> private_data ;
1661+ int error ;
1662+
1663+ error = snd_miro_configure (miro );
1664+ if (error < 0 )
1665+ return error ;
1666+ error = snd_miro_aci_force_known_state (miro -> aci );
1667+ if (error < 0 ) {
1668+ dev_err (card -> dev , "can't force aci into known state\n" );
1669+ return error ;
1670+ }
1671+ error = snd_miro_aci_initialize (miro -> aci );
1672+ if (error < 0 ) {
1673+ dev_err (card -> dev , "can't initialize aci\n" );
1674+ return error ;
1675+ }
1676+ error = snd_miro_restore_aci_state (miro );
1677+ if (error < 0 )
1678+ return error ;
1679+
1680+ miro -> codec -> resume (miro -> codec );
1681+ snd_power_change_state (card , SNDRV_CTL_POWER_D0 );
1682+ return 0 ;
1683+ }
1684+
1685+ static int snd_miro_isa_suspend (struct device * dev , unsigned int n ,
1686+ pm_message_t state )
1687+ {
1688+ return snd_miro_suspend (dev_get_drvdata (dev ));
1689+ }
1690+
1691+ static int snd_miro_isa_resume (struct device * dev , unsigned int n )
1692+ {
1693+ return snd_miro_resume (dev_get_drvdata (dev ));
1694+ }
1695+ #endif
1696+
14731697#define DEV_NAME "miro"
14741698
14751699static struct isa_driver snd_miro_driver = {
14761700 .match = snd_miro_isa_match ,
14771701 .probe = snd_miro_isa_probe ,
1478- /* FIXME: suspend/resume */
1702+ #ifdef CONFIG_PM
1703+ .suspend = snd_miro_isa_suspend ,
1704+ .resume = snd_miro_isa_resume ,
1705+ #endif
14791706 .driver = {
14801707 .name = DEV_NAME
14811708 },
@@ -1591,12 +1818,29 @@ static void snd_miro_pnp_remove(struct pnp_card_link *pcard)
15911818 snd_miro_pnp_is_probed = 0 ;
15921819}
15931820
1821+ #ifdef CONFIG_PM
1822+ static int snd_miro_pnp_suspend (struct pnp_card_link * pcard ,
1823+ pm_message_t state )
1824+ {
1825+ return snd_miro_suspend (pnp_get_card_drvdata (pcard ));
1826+ }
1827+
1828+ static int snd_miro_pnp_resume (struct pnp_card_link * pcard )
1829+ {
1830+ return snd_miro_resume (pnp_get_card_drvdata (pcard ));
1831+ }
1832+ #endif
1833+
15941834static struct pnp_card_driver miro_pnpc_driver = {
15951835 .flags = PNP_DRIVER_RES_DISABLE ,
15961836 .name = "miro" ,
15971837 .id_table = snd_miro_pnpids ,
15981838 .probe = snd_miro_pnp_probe ,
15991839 .remove = snd_miro_pnp_remove ,
1840+ #ifdef CONFIG_PM
1841+ .suspend = snd_miro_pnp_suspend ,
1842+ .resume = snd_miro_pnp_resume ,
1843+ #endif
16001844};
16011845#endif
16021846
0 commit comments