Newer
Older
}
for (i = 0; i < nums; i++, dev++)
if (! chip->azx_dev[dev].opened) {
chip->azx_dev[dev].opened = 1;
return &chip->azx_dev[dev];
}
return NULL;
}
/* release the assigned stream */
static inline void azx_release_device(struct azx_dev *azx_dev)
static struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
/* No full-resume yet implemented */
/* SNDRV_PCM_INFO_RESUME |*/
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = AZX_MAX_BUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = AZX_MAX_BUF_SIZE / 2,
.periods_min = 2,
.periods_max = AZX_MAX_FRAG,
.fifo_size = 0,
};
struct azx_pcm {
struct hda_codec *codec;
struct hda_pcm_stream *hinfo[2];
};
static int azx_pcm_open(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev;
struct snd_pcm_runtime *runtime = substream->runtime;
azx_dev = azx_assign_device(chip, substream->stream);
if (azx_dev == NULL) {
return -EBUSY;
}
runtime->hw = azx_pcm_hw;
runtime->hw.channels_min = hinfo->channels_min;
runtime->hw.channels_max = hinfo->channels_max;
runtime->hw.formats = hinfo->formats;
runtime->hw.rates = hinfo->rates;
snd_pcm_limit_hw_rates(runtime);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
azx_release_device(azx_dev);
return err;
}
spin_lock_irqsave(&chip->reg_lock, flags);
azx_dev->substream = substream;
azx_dev->running = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
runtime->private_data = azx_dev;
static int azx_pcm_close(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
spin_lock_irqsave(&chip->reg_lock, flags);
azx_dev->substream = NULL;
azx_dev->running = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
azx_release_device(azx_dev);
hinfo->ops.close(hinfo, apcm->codec, substream);
static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_sd_writel(azx_dev, SD_CTL, 0);
hinfo->ops.cleanup(hinfo, apcm->codec, substream);
return snd_pcm_lib_free_pages(substream);
}
static int azx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
struct snd_pcm_runtime *runtime = substream->runtime;
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
hinfo->maxbps);
if (! azx_dev->format_val) {
snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n",
runtime->rate, runtime->channels, runtime->format);
return -EINVAL;
}
snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n",
azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
azx_setup_periods(azx_dev);
azx_setup_controller(chip, azx_dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
else
azx_dev->fifo_size = 0;
return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
azx_dev->format_val, substream);
}
static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream);
struct azx *chip = apcm->chip;
int err = 0;
spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
azx_stream_start(chip, azx_dev);
azx_dev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
azx_stream_stop(chip, azx_dev);
azx_dev->running = 0;
break;
default:
err = -EINVAL;
}
spin_unlock(&chip->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
cmd == SNDRV_PCM_TRIGGER_STOP) {
int timeout = 5000;
while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
;
}
return err;
}
static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
if (chip->position_fix == POS_FIX_POSBUF ||
chip->position_fix == POS_FIX_AUTO) {
if (chip->position_fix == POS_FIX_AUTO &&
azx_dev->period_intr == 1 && ! pos) {
printk(KERN_WARNING
"hda-intel: Invalid position buffer, "
"using LPIB read method instead.\n");
chip->position_fix = POS_FIX_NONE;
goto read_lpib;
}
/* read LPIB */
pos = azx_sd_readl(azx_dev, SD_LPIB);
if (chip->position_fix == POS_FIX_FIFO)
pos += azx_dev->fifo_size;
}
if (pos >= azx_dev->bufsize)
pos = 0;
return bytes_to_frames(substream->runtime, pos);
}
static struct snd_pcm_ops azx_pcm_ops = {
.open = azx_pcm_open,
.close = azx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = azx_pcm_hw_params,
.hw_free = azx_pcm_hw_free,
.prepare = azx_pcm_prepare,
.trigger = azx_pcm_trigger,
.pointer = azx_pcm_pointer,
};
static void azx_pcm_free(struct snd_pcm *pcm)
static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
struct hda_pcm *cpcm, int pcm_dev)
{
int err;
/* if no substreams are defined for both playback and capture,
* it's just a placeholder. ignore it.
*/
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
return 0;
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
snd_assert(cpcm->name, return -EINVAL);
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
cpcm->stream[0].substreams, cpcm->stream[1].substreams,
&pcm);
if (err < 0)
return err;
strcpy(pcm->name, cpcm->name);
apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
if (apcm == NULL)
return -ENOMEM;
apcm->chip = chip;
apcm->codec = codec;
apcm->hinfo[0] = &cpcm->stream[0];
apcm->hinfo[1] = &cpcm->stream[1];
pcm->private_data = apcm;
pcm->private_free = azx_pcm_free;
if (cpcm->stream[0].substreams)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
if (cpcm->stream[1].substreams)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
1024 * 64, 1024 * 128);
chip->pcm[pcm_dev] = pcm;
if (chip->pcm_devs < pcm_dev + 1)
chip->pcm_devs = pcm_dev + 1;
static int __devinit azx_pcm_create(struct azx *chip)
{
struct list_head *p;
struct hda_codec *codec;
int c, err;
int pcm_dev;
if ((err = snd_hda_build_pcms(chip->bus)) < 0)
return err;
pcm_dev = 0;
list_for_each(p, &chip->bus->codec_list) {
codec = list_entry(p, struct hda_codec, list);
for (c = 0; c < codec->num_pcms; c++) {
if (codec->pcm_info[c].is_modem)
continue; /* create later */
if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {
snd_printk(KERN_ERR SFX "Too many audio PCMs\n");
return -EINVAL;
}
err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
if (err < 0)
return err;
pcm_dev++;
}
}
/* create modem PCMs */
pcm_dev = AZX_MAX_AUDIO_PCMS;
list_for_each(p, &chip->bus->codec_list) {
codec = list_entry(p, struct hda_codec, list);
for (c = 0; c < codec->num_pcms; c++) {
if (! codec->pcm_info[c].is_modem)
continue; /* already created */
if (pcm_dev >= AZX_MAX_PCMS) {
snd_printk(KERN_ERR SFX "Too many modem PCMs\n");
return -EINVAL;
}
err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
if (err < 0)
return err;
chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
pcm_dev++;
}
}
return 0;
}
/*
* mixer creation - all stuff is implemented in hda module
*/
static int __devinit azx_mixer_create(struct azx *chip)
{
return snd_hda_build_controls(chip->bus);
}
/*
* initialize SD streams
*/
static int __devinit azx_init_stream(struct azx *chip)
{
int i;
/* initialize each stream (aka device)
* assign the starting bdl address to each stream (device) and initialize
*/
for (i = 0; i < chip->num_streams; i++) {
unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
struct azx_dev *azx_dev = &chip->azx_dev[i];
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
azx_dev->bdl_addr = chip->bdl.addr + off;
azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
azx_dev->sd_int_sta_mask = 1 << i;
/* stream tag: must be non-zero and unique */
azx_dev->index = i;
azx_dev->stream_tag = i + 1;
}
return 0;
}
#ifdef CONFIG_PM
/*
* power management
*/
static int azx_suspend(struct pci_dev *pci, pm_message_t state)
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_free_cmd_io(chip);
if (chip->irq >= 0) {
synchronize_irq(chip->irq);
free_irq(chip->irq, chip);
chip->irq = -1;
}
if (!disable_msi)
pci_disable_msi(chip->pci);
pci_disable_device(pci);
pci_save_state(pci);
pci_set_power_state(pci, pci_choose_state(pci, state));
static int azx_resume(struct pci_dev *pci)
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data;
pci_set_power_state(pci, PCI_D0);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "hda-intel: pci_enable_device failed, "
"disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
pci_set_master(pci);
if (!disable_msi)
pci_enable_msi(pci);
if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
"HDA Intel", chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
return -EIO;
}
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif /* CONFIG_PM */
/*
* destructor
*/
static int azx_free(struct azx *chip)
for (i = 0; i < chip->num_streams; i++)
azx_stream_stop(chip, &chip->azx_dev[i]);
/* disable interrupts */
azx_int_disable(chip);
azx_int_clear(chip);
/* disable CORB/RIRB */
azx_free_cmd_io(chip);
/* disable position buffer */
azx_writel(chip, DPLBASE, 0);
azx_writel(chip, DPUBASE, 0);
}
synchronize_irq(chip->irq);
if (!disable_msi)
pci_disable_msi(chip->pci);
if (chip->remap_addr)
iounmap(chip->remap_addr);
if (chip->bdl.area)
snd_dma_free_pages(&chip->bdl);
if (chip->rb.area)
snd_dma_free_pages(&chip->rb);
if (chip->posbuf.area)
snd_dma_free_pages(&chip->posbuf);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
static int azx_dev_free(struct snd_device *device)
{
return azx_free(device->device_data);
}
/*
* constructor
*/
static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
static struct snd_device_ops ops = {
.dev_free = azx_dev_free,
};
*rchip = NULL;
err = pci_enable_device(pci);
if (err < 0)
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
snd_printk(KERN_ERR SFX "cannot allocate chip\n");
pci_disable_device(pci);
return -ENOMEM;
}
spin_lock_init(&chip->reg_lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->driver_type = driver_type;
chip->position_fix = position_fix;
chip->single_cmd = single_cmd;
#if BITS_PER_LONG != 64
/* Fix up base address on ULI M5461 */
if (chip->driver_type == AZX_DRIVER_ULI) {
u16 tmp3;
pci_read_config_word(pci, 0x40, &tmp3);
pci_write_config_word(pci, 0x40, tmp3 | 0x10);
pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
}
#endif
err = pci_request_regions(pci, "ICH HD audio");
if (err < 0) {
kfree(chip);
pci_disable_device(pci);
return err;
}
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0));
if (chip->remap_addr == NULL) {
snd_printk(KERN_ERR SFX "ioremap error\n");
err = -ENXIO;
goto errout;
}
if (!disable_msi)
pci_enable_msi(pci);
if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
"HDA Intel", (void*)chip)) {
snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto errout;
}
chip->irq = pci->irq;
pci_set_master(pci);
synchronize_irq(chip->irq);
switch (chip->driver_type) {
case AZX_DRIVER_ULI:
chip->playback_streams = ULI_NUM_PLAYBACK;
chip->capture_streams = ULI_NUM_CAPTURE;
chip->playback_index_offset = ULI_PLAYBACK_INDEX;
chip->capture_index_offset = ULI_CAPTURE_INDEX;
break;
case AZX_DRIVER_ATIHDMI:
chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
chip->capture_streams = ATIHDMI_NUM_CAPTURE;
chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
break;
default:
chip->playback_streams = ICH6_NUM_PLAYBACK;
chip->capture_streams = ICH6_NUM_CAPTURE;
chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
chip->capture_index_offset = ICH6_CAPTURE_INDEX;
break;
}
chip->num_streams = chip->playback_streams + chip->capture_streams;
chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
snd_printk(KERN_ERR "cannot malloc azx_dev\n");
goto errout;
}
/* allocate memory for the BDL for each stream */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
goto errout;
}
/* allocate memory for the position buffer */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
chip->num_streams * 8, &chip->posbuf)) < 0) {
snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
goto errout;
if (! chip->single_cmd)
if ((err = azx_alloc_cmd_io(chip)) < 0)
goto errout;
/* initialize streams */
azx_init_stream(chip);
/* initialize chip */
azx_init_chip(chip);
chip->initialized = 1;
snd_printk(KERN_ERR SFX "no codecs found!\n");
err = -ENODEV;
goto errout;
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) {
snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
goto errout;
}
strcpy(card->driver, "HDA-Intel");
strcpy(card->shortname, driver_short_names[chip->driver_type]);
sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
*rchip = chip;
return 0;
errout:
azx_free(chip);
return err;
}
static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
{
struct snd_card *card;
struct azx *chip;
card = snd_card_new(index, id, THIS_MODULE, 0);
snd_printk(KERN_ERR SFX "Error creating card!\n");
return -ENOMEM;
}
err = azx_create(card, pci, pci_id->driver_data, &chip);
if (err < 0) {
if ((err = azx_codec_create(chip, model)) < 0) {
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
snd_card_free(card);
return err;
}
/* create PCM streams */
if ((err = azx_pcm_create(chip)) < 0) {
snd_card_free(card);
return err;
}
/* create mixer controls */
if ((err = azx_mixer_create(chip)) < 0) {
snd_card_free(card);
return err;
}
snd_card_set_dev(card, &pci->dev);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
pci_set_drvdata(pci, card);
return err;
}
static void __devexit azx_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
/* PCI IDs */
static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
{ 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
{ 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
{ 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */
{ 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */
{ 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 03f0 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
/* pci_driver definition */
static struct pci_driver driver = {
.name = "HDA Intel",
.id_table = azx_ids,
.probe = azx_probe,
.remove = __devexit_p(azx_remove),
#ifdef CONFIG_PM
.suspend = azx_suspend,
.resume = azx_resume,
#endif
};
static int __init alsa_card_azx_init(void)
{
return pci_register_driver(&driver);