2 * HD-audio core bus driver
5 #include <linux/init.h>
6 #include <linux/device.h>
7 #include <linux/module.h>
8 #include <linux/export.h>
9 #include <sound/hdaudio.h>
12 static const struct hdac_bus_ops default_ops
= {
13 .command
= snd_hdac_bus_send_cmd
,
14 .get_response
= snd_hdac_bus_get_response
,
18 * snd_hdac_bus_init - initialize a HD-audio bas bus
19 * @bus: the pointer to bus object
20 * @ops: bus verb operators
21 * @io_ops: lowlevel I/O operators
23 * Returns 0 if successful, or a negative error code.
25 int snd_hdac_bus_init(struct hdac_bus
*bus
, struct device
*dev
,
26 const struct hdac_bus_ops
*ops
,
27 const struct hdac_io_ops
*io_ops
)
29 memset(bus
, 0, sizeof(*bus
));
34 bus
->ops
= &default_ops
;
36 INIT_LIST_HEAD(&bus
->stream_list
);
37 INIT_LIST_HEAD(&bus
->codec_list
);
38 INIT_WORK(&bus
->unsol_work
, snd_hdac_bus_process_unsol_events
);
39 spin_lock_init(&bus
->reg_lock
);
40 mutex_init(&bus
->cmd_mutex
);
44 EXPORT_SYMBOL_GPL(snd_hdac_bus_init
);
47 * snd_hdac_bus_exit - clean up a HD-audio bas bus
48 * @bus: the pointer to bus object
50 void snd_hdac_bus_exit(struct hdac_bus
*bus
)
52 WARN_ON(!list_empty(&bus
->stream_list
));
53 WARN_ON(!list_empty(&bus
->codec_list
));
54 cancel_work_sync(&bus
->unsol_work
);
56 EXPORT_SYMBOL_GPL(snd_hdac_bus_exit
);
59 * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus
61 * @cmd: HD-audio encoded verb
62 * @res: pointer to store the response, NULL if performing asynchronously
64 * Returns 0 if successful, or a negative error code.
66 int snd_hdac_bus_exec_verb(struct hdac_bus
*bus
, unsigned int addr
,
67 unsigned int cmd
, unsigned int *res
)
71 mutex_lock(&bus
->cmd_mutex
);
72 err
= snd_hdac_bus_exec_verb_unlocked(bus
, addr
, cmd
, res
);
73 mutex_unlock(&bus
->cmd_mutex
);
76 EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb
);
79 * snd_hdac_bus_exec_verb_unlocked - unlocked version
81 * @cmd: HD-audio encoded verb
82 * @res: pointer to store the response, NULL if performing asynchronously
84 * Returns 0 if successful, or a negative error code.
86 int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus
*bus
, unsigned int addr
,
87 unsigned int cmd
, unsigned int *res
)
97 else if (bus
->sync_write
)
100 trace_hda_send_cmd(bus
, cmd
);
101 err
= bus
->ops
->command(bus
, cmd
);
104 /* process pending verbs */
105 err
= bus
->ops
->get_response(bus
, addr
, &tmp
);
110 err
= bus
->ops
->get_response(bus
, addr
, res
);
111 trace_hda_get_response(bus
, addr
, *res
);
115 EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb_unlocked
);
118 * snd_hdac_bus_queue_event - add an unsolicited event to queue
120 * @res: unsolicited event (lower 32bit of RIRB entry)
121 * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
123 * Adds the given event to the queue. The events are processed in
124 * the workqueue asynchronously. Call this function in the interrupt
125 * hanlder when RIRB receives an unsolicited event.
127 void snd_hdac_bus_queue_event(struct hdac_bus
*bus
, u32 res
, u32 res_ex
)
134 trace_hda_unsol_event(bus
, res
, res_ex
);
135 wp
= (bus
->unsol_wp
+ 1) % HDA_UNSOL_QUEUE_SIZE
;
139 bus
->unsol_queue
[wp
] = res
;
140 bus
->unsol_queue
[wp
+ 1] = res_ex
;
142 schedule_work(&bus
->unsol_work
);
144 EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event
);
147 * process queued unsolicited events
149 void snd_hdac_bus_process_unsol_events(struct work_struct
*work
)
151 struct hdac_bus
*bus
= container_of(work
, struct hdac_bus
, unsol_work
);
152 struct hdac_device
*codec
;
153 struct hdac_driver
*drv
;
154 unsigned int rp
, caddr
, res
;
156 while (bus
->unsol_rp
!= bus
->unsol_wp
) {
157 rp
= (bus
->unsol_rp
+ 1) % HDA_UNSOL_QUEUE_SIZE
;
160 res
= bus
->unsol_queue
[rp
];
161 caddr
= bus
->unsol_queue
[rp
+ 1];
162 if (!(caddr
& (1 << 4))) /* no unsolicited event? */
164 codec
= bus
->caddr_tbl
[caddr
& 0x0f];
165 if (!codec
|| !codec
->dev
.driver
)
167 drv
= drv_to_hdac_driver(codec
->dev
.driver
);
168 if (drv
->unsol_event
)
169 drv
->unsol_event(codec
, res
);
172 EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events
);
175 * snd_hdac_bus_add_device - Add a codec to bus
177 * @codec: HDA core device to add
179 * Adds the given codec to the list in the bus. The caddr_tbl array
180 * and codec_powered bits are updated, as well.
181 * Returns zero if success, or a negative error code.
183 int snd_hdac_bus_add_device(struct hdac_bus
*bus
, struct hdac_device
*codec
)
185 if (bus
->caddr_tbl
[codec
->addr
]) {
186 dev_err(bus
->dev
, "address 0x%x is already occupied\n",
191 list_add_tail(&codec
->list
, &bus
->codec_list
);
192 bus
->caddr_tbl
[codec
->addr
] = codec
;
193 set_bit(codec
->addr
, &bus
->codec_powered
);
197 EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device
);
200 * snd_hdac_bus_remove_device - Remove a codec from bus
202 * @codec: HDA core device to remove
204 void snd_hdac_bus_remove_device(struct hdac_bus
*bus
,
205 struct hdac_device
*codec
)
207 WARN_ON(bus
!= codec
->bus
);
208 if (list_empty(&codec
->list
))
210 list_del_init(&codec
->list
);
211 bus
->caddr_tbl
[codec
->addr
] = NULL
;
212 clear_bit(codec
->addr
, &bus
->codec_powered
);
214 flush_work(&bus
->unsol_work
);
216 EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device
);