Slide 1

Slide 1 text

ALSA YM2413υϥΠό NAOMASA MATSUBAYASHI

Slide 2

Slide 2 text

@fadis_ Twitter Github Speakerdeck https://speakerdeck.com/fadis https://github.com/Fadis/ NAOMASA MATSUBAYASHI ීஈ͸େࡕͰήʔϜ࡞ͬͯ·͢

Slide 3

Slide 3 text

ALSA

Slide 4

Slide 4 text

Advanced Linux Sound Architecture

Slide 5

Slide 5 text

#include ! #include ! #include ! #include ! int main() {! snd_pcm_t *pcm = nullptr;! if(snd_pcm_open(&pcm,"default",SND_PCM_STREAM_PLAYBACK,0)<0)return -1;! if(snd_pcm_set_params(pcm,SND_PCM_FORMAT_S16,! SND_PCM_ACCESS_RW_INTERLEAVED,1,44100,1,1)<0)return -1;! std::array< int16_t, 1024 > buf;! int pos = 0, ret;! while(1) {! for(int16_t &elem:buf)elem=sin(double(pos++)*440.*M_PI/44100.)*32767;! if((ret=snd_pcm_writei(pcm,(const void*)buf.data(),buf.size()))<0)! if(snd_pcm_recover(pcm,ret,0)<0)return -1;! }! } Linux؀ڥͰPCMΦʔσΟΦΛ ࠶ੜ͢Δͷʹ࢖͏ https://github.com/Fadis/kernelvm_20150815_samples/blob/master/pcm.cpp

Slide 6

Slide 6 text

#include ! #include ! #include ! #include ! int main() {! snd_pcm_t *pcm = nullptr;! if(snd_pcm_open(&pcm,"default",SND_PCM_STREAM_PLAYBACK,0)<0)return -1;! if(snd_pcm_set_params(pcm,SND_PCM_FORMAT_S16,! SND_PCM_ACCESS_RW_INTERLEAVED,1,44100,1,1)<0)return -1;! std::array< int16_t, 1024 > buf;! int pos = 0, ret;! while(1) {! for(int16_t &elem:buf)elem=sin(double(pos++)*440.*M_PI/44100.)*32767;! if((ret=snd_pcm_writei(pcm,(const void*)buf.data(),buf.size()))<0)! if(snd_pcm_recover(pcm,ret,0)<0)return -1;! }! } σόΠεΛopenͯ͠ ϑΥʔϚοτΛࢦఆ https://github.com/Fadis/kernelvm_20150815_samples/blob/master/pcm.cpp

Slide 7

Slide 7 text

#include ! #include ! #include ! #include ! int main() {! snd_pcm_t *pcm = nullptr;! if(snd_pcm_open(&pcm,"default",SND_PCM_STREAM_PLAYBACK,0)<0)return -1;! if(snd_pcm_set_params(pcm,SND_PCM_FORMAT_S16,! SND_PCM_ACCESS_RW_INTERLEAVED,1,44100,1,1)<0)return -1;! std::array< int16_t, 1024 > buf;! int pos = 0, ret;! while(1) {! for(int16_t &elem:buf)elem=sin(double(pos++)*440.*M_PI/44100.)*32767;! if((ret=snd_pcm_writei(pcm,(const void*)buf.data(),buf.size()))<0)! if(snd_pcm_recover(pcm,ret,0)<0)return -1;! }! } PCMσʔλΛwrite https://github.com/Fadis/kernelvm_20150815_samples/blob/master/pcm.cpp

Slide 8

Slide 8 text

ͦΕ͚ͩ?

Slide 9

Slide 9 text

Control PCM Raw MIDI VirMIDI Seq.MIDI Sequencer Timer Control API PCM API RawMIDI API Sequencer API Control Apps Mixer Apps PCM Apps MIDI Apps Sequencer User client ग़య: http://www.alsa-project.org/~tiwai/lk2k/lk2k.html Χʔωϧ Ϣʔβۭؒ

Slide 10

Slide 10 text

Control PCM Raw MIDI VirMIDI Seq.MIDI Sequencer Timer Control API PCM API RawMIDI API Sequencer API Control Apps Mixer Apps PCM Apps MIDI Apps Sequencer User client ग़య: http://www.alsa-project.org/~tiwai/lk2k/lk2k.html Χʔωϧ Ϣʔβۭؒ Իྔ΍࿥Իιʔεͷબ୒౳ ϋʔυ΢ΣΞશମͷઃఆΛߦ͏

Slide 11

Slide 11 text

Control PCM Raw MIDI VirMIDI Seq.MIDI Sequencer Timer Control API PCM API RawMIDI API Sequencer API Control Apps Mixer Apps PCM Apps MIDI Apps Sequencer User client ग़య: http://www.alsa-project.org/~tiwai/lk2k/lk2k.html Χʔωϧ Ϣʔβۭؒ PCMΛ࠶ੜग़དྷΔσόΠεʹ PCMσʔλΛૹͬͯԻΛग़͢

Slide 12

Slide 12 text

Control PCM Raw MIDI VirMIDI Seq.MIDI Sequencer Timer Control API PCM API RawMIDI API Sequencer API Control Apps Mixer Apps PCM Apps MIDI Apps Sequencer User client ग़య: http://www.alsa-project.org/~tiwai/lk2k/lk2k.html Χʔωϧ Ϣʔβۭؒ γϯηαΠβʔʹίϚϯυΛૹͬͯ MIDI౳Λԋ૗͢Δ

Slide 13

Slide 13 text

CPU γϯηαΠβʔ ♪ ♪ ⽃ γϯηαΠβʔʹίϚϯυΛૹͬͯ MIDI౳Λԋ૗͢Δ ָේ ೾ܗ

Slide 14

Slide 14 text

Control PCM Raw MIDI VirMIDI Seq.MIDI Sequencer Timer Control API PCM API RawMIDI API Sequencer API Control Apps Mixer Apps PCM Apps MIDI Apps Sequencer User client ग़య: http://www.alsa-project.org/~tiwai/lk2k/lk2k.html Χʔωϧ Ϣʔβۭؒ Ϣʔβۭ͔ؒΒLinuxΧʔωϧʹ ԋ૗ΠϕϯτΛ఻͑Δํ๏͸2ͭ͋Δ

Slide 15

Slide 15 text

RawMIDI API ΧʔωϧʹMIDIϝοηʔδΛͦͷ··ૹΔ σόΠευϥΠό͸MIDIϝοηʔδΛͦͷ··ड͚औΔ $ printf '\x90\x3c\x7f' >/dev/snd/midiC0D0 σόΠεϑΝΠϧʹ௚઀ MIDIϝοηʔδΛॻ͖ࠐΉͱ ରԠ͢ΔσόΠε͔ΒԻ͕ग़Δ

Slide 16

Slide 16 text

typedef struct snd_seq_event {! snd_seq_event_type_t type; ! unsigned char flags; ! unsigned char tag; ! unsigned char queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t source; ! snd_seq_addr_t dest; ! union {! snd_seq_ev_note_t note; ! snd_seq_ev_ctrl_t control; ! snd_seq_ev_raw8_t raw8; ! snd_seq_ev_raw32_t raw32; ! snd_seq_ev_ext_t ext; ! snd_seq_ev_queue_control_t queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t addr; ! snd_seq_connect_t connect; ! snd_seq_result_t result; ! } data; ! } snd_seq_event_t; Sequencer API snd_seq_event ΄΅.*%*ͱಉ͡৘ใΛදݱ ݻఆ௕ λΠϜελϯϓͱ ૹ৴ݩɺૹ৴ઌͷ৘ใ͕ ௥Ճ͞Ε͍ͯΔ

Slide 17

Slide 17 text

typedef struct snd_seq_event {! snd_seq_event_type_t type; ! unsigned char flags; ! unsigned char tag; ! unsigned char queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t source; ! snd_seq_addr_t dest; ! union {! snd_seq_ev_note_t note; ! snd_seq_ev_ctrl_t control; ! snd_seq_ev_raw8_t raw8; ! snd_seq_ev_raw32_t raw32; ! snd_seq_ev_ext_t ext; ! snd_seq_ev_queue_control_t queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t addr; ! snd_seq_connect_t connect; ! snd_seq_result_t result; ! } data; ! } snd_seq_event_t; Sequencer API Կ͕ى͔ͬͨ͜ 伴൫͕ԡ͞Εͨ ϐον͕มԽͨ͠ ͍ͭى͔ͬͨ͜ Ͳͷ$MJFOU͔Βདྷ͔ͨ Ͳͷ$MJFOUѼʹૹΒΕ͔ͨ ݸʑͷΠϕϯτͷ ৄࡉ͕ೖΔVOJPO ԡ͞Εͨ伴൫͸ͲΕ ָثͷछྨ͸ͲΕ

Slide 18

Slide 18 text

Χʔωϧ Ϣʔβۭؒ Sequencer API Sequencer Core Client A Client B ♪ ♪ ⽃ snd_seq_eventΛ౤͛ͨΓड͚औͬͨΓ͢Δ ΞϓϦέʔγϣϯ͸clientͱݺ͹ΕΔ ♪ ♪ ⽃ client͔ΒૹΒΕͨsnd_seq_event͸ ΧʔωϧͷSequencer Core͕ εέδϡʔϦϯά͠ɺద੾ͳclientʹ഑ૹ͢Δ

Slide 19

Slide 19 text

$ aplaymidi -p 14:0 hoge.mid &! $ aconnect -l! ΫϥΠΞϯτ 0: 'System' [λΠϓ=Χʔωϧ]! 0 'Timer '! 1 'Announce '! ΫϥΠΞϯτ 14: 'Midi Through' [λΠϓ=Χʔωϧ]! 0 'Midi Through Port-0'! ઀ଓݩ: 128:0! ΫϥΠΞϯτ 128: 'aplaymidi' [λΠϓ=Ϣʔβ]! 0 'aplaymidi '! ઀ଓઌ: 14:0 aconnect Sequencer Clientͷ઀ଓͷ ֬ೝͱมߋΛߦ͏ίϚϯυ

Slide 20

Slide 20 text

$ aplaymidi -p 14:0 hoge.mid &! $ aconnect -l! ΫϥΠΞϯτ 0: 'System' [λΠϓ=Χʔωϧ]! 0 'Timer '! 1 'Announce '! ΫϥΠΞϯτ 14: 'Midi Through' [λΠϓ=Χʔωϧ]! 0 'Midi Through Port-0'! ઀ଓݩ: 128:0! ΫϥΠΞϯτ 128: 'aplaymidi' [λΠϓ=Ϣʔβ]! 0 'aplaymidi '! ઀ଓઌ: 14:0 aconnect aplaymidiͰ14:0ʹ޲͔ͬͯΠϕϯτΛ౤͛Δ

Slide 21

Slide 21 text

$ aplaymidi -p 14:0 hoge.mid &! $ aconnect -l! ΫϥΠΞϯτ 0: 'System' [λΠϓ=Χʔωϧ]! 0 'Timer '! 1 'Announce '! ΫϥΠΞϯτ 14: 'Midi Through' [λΠϓ=Χʔωϧ]! 0 'Midi Through Port-0'! ઀ଓݩ: 128:0! ΫϥΠΞϯτ 128: 'aplaymidi' [λΠϓ=Ϣʔβ]! 0 'aplaymidi '! ઀ଓઌ: 14:0 aconnect ΫϥΠΞϯτ14:0ͱ ઌఔىಈͨ͠aplaymidi͕઀ଓ͞Ε͍ͯΔ

Slide 22

Slide 22 text

static void init_seq(void)! {! int err;! err = snd_seq_open(! &seq, "default", SND_SEQ_OPEN_DUPLEX, 0! );! check_snd("open sequencer", err);! err = snd_seq_set_client_name(seq, "aplaymidi");! check_snd("set client name", err);! client = snd_seq_client_id(seq);! check_snd("get client id", client);! } snd_seq_openͰ Sequencer ClientΛ࡞Δ IUUQTHJUIVCDPNCFBSSXBMTBVUJMTCMPCNBTUFS TFRBQMBZNJEJBQMBZNJEJD

Slide 23

Slide 23 text

static void init_seq(void)! {! int err;! err = snd_seq_open(! &seq, "default", SND_SEQ_OPEN_DUPLEX, 0! );! check_snd("open sequencer", err);! err = snd_seq_set_client_name(seq, "aplaymidi");! check_snd("set client name", err);! client = snd_seq_client_id(seq);! check_snd("get client id", client);! } snd_seq_openͰ Sequencer ClientΛ࡞Δ IUUQTHJUIVCDPNCFBSSXBMTBVUJMTCMPCNBTUFS TFRBQMBZNJEJBQMBZNJEJD

Slide 24

Slide 24 text

static void create_source_port(void)! {! snd_seq_port_info_t *pinfo;! int err;! snd_seq_port_info_alloca(&pinfo);! snd_seq_port_info_set_port(pinfo, 0);! snd_seq_port_info_set_port_specified(pinfo, 1);! snd_seq_port_info_set_name(pinfo, "aplaymidi");! snd_seq_port_info_set_capability(pinfo, 0);! snd_seq_port_info_set_type(pinfo,! SND_SEQ_PORT_TYPE_MIDI_GENERIC |! SND_SEQ_PORT_TYPE_APPLICATION);! err = snd_seq_create_port(seq, pinfo);! check_snd("create port", err);! } snd_seq_create_portͰ Sequencer ClientʹϙʔτΛ࡞੒͢Δ

Slide 25

Slide 25 text

$ aconnect -l! …! ΫϥΠΞϯτ 128: 'hoge' [λΠϓ=Ϣʔβ]! 0 'hoge port 0 '! 1 'hoge port 1 ‘! …! $ aconnect 128:1 14:0 1ͭͷSequencer Clientʹ͸ ෳ਺ͷϙʔτΛઃ͚Δࣄ͕ग़དྷΔ Clientಉ࢜ͷ઀ଓ͸ϙʔτ୯ҐͰߦ͏ ΫϥΠΞϯτͷϙʔτΛ ΫϥΠΞϯτͷϙʔτʹ઀ଓ

Slide 26

Slide 26 text

typedef struct snd_seq_event {! snd_seq_event_type_t type; ! unsigned char flags; ! unsigned char tag; ! unsigned char queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t source; ! snd_seq_addr_t dest; ! union {! snd_seq_ev_note_t note; ! snd_seq_ev_ctrl_t control; ! snd_seq_ev_raw8_t raw8; ! snd_seq_ev_raw32_t raw32; ! snd_seq_ev_ext_t ext; ! snd_seq_ev_queue_control_t queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t addr; ! snd_seq_connect_t connect; ! snd_seq_result_t result; ! } data; ! } snd_seq_event_t; Ͳͷϙʔτ͔ΒΠϕϯτΛඈ͹͔͢͸ event.source.portͰࢦఆ͢Δ typedef struct snd_seq_addr {! unsigned char client; ! unsigned char port; ! } snd_seq_addr_t; ͜Ε

Slide 27

Slide 27 text

static void connect_ports(void)! {! int i, err;! ! for (i = 0; i < port_count; ++i) {! err = snd_seq_connect_to(seq, 0, ports[i].client, ports[i].port);! if (err < 0)! fatal("Cannot connect to port %d:%d - %s",! ports[i].client, ports[i].port, snd_strerror(err));! }! } snd_seq_connect_to Ͱ 2ͭͷϙʔτΛ઀ଓ

Slide 28

Slide 28 text

/* this blocks when the output pool has been filled */! err = snd_seq_event_output(seq, &ev);! check_snd("output event", err); ͋ͱ͸snd_seq_event_outputͰ ΠϕϯτΛ౤͛Δ snd_seq_event_t *event;! err = snd_seq_event_input(seq, &event);! if (err < 0)! break; ͋Δ͍͸snd_seq_event_inputͰ ඈΜͰ͖ͨΠϕϯτΛड͚औΔ IUUQTHJUIVCDPNCFBSSXBMTBVUJMTCMPCNBTUFS TFRBTFREVNQBTFREVNQD

Slide 29

Slide 29 text

snd_seq_event_t *event;! err = snd_seq_event_input(seq, &event);! if (err < 0)! break; ͋Δ͍͸snd_seq_event_inputͰ ඈΜͰ͖ͨΠϕϯτΛड͚औΔ snd_seq_event_input͸σϑΥϧτͰ͸ Πϕϯτ͕ඈΜͰ͘Δ·ͰϒϩοΫ͢Δ͕ snd_seq_nonblock( seq, 1 ); snd_seq_nonblockͰ non-blockingϞʔυʹ͓ͯ͘͠ͱ Πϕϯτ͕ແ͍࣌͸௚ͪʹEAGAIN͕ฦΔΑ͏ʹͳΔ

Slide 30

Slide 30 text

$ aplaymidi -p 14:0 hoge.mid &! $ aconnect -l! ΫϥΠΞϯτ 0: 'System' [λΠϓ=Χʔωϧ]! 0 'Timer '! 1 'Announce '! ΫϥΠΞϯτ 14: 'Midi Through' [λΠϓ=Χʔωϧ]! 0 'Midi Through Port-0'! ઀ଓݩ: 128:0! ΫϥΠΞϯτ 128: 'aplaymidi' [λΠϓ=Ϣʔβ]! 0 'aplaymidi '! ઀ଓઌ: 14:0 ϢʔβΫϥΠΞϯτͱΧʔωϧΫϥΠΞϯτ

Slide 31

Slide 31 text

Χʔωϧ Ϣʔβۭؒ Sequencer Core Client A Client B Client C Sequencer Client͸Χʔωϧ಺Ͱ΋ ࡞Δ͜ͱ͕Ͱ͖Δ λΠϓ: Ϣʔβ λΠϓ: Ϣʔβ λΠϓ: Χʔωϧ

Slide 32

Slide 32 text

Χʔωϧ ۭؒ Sequencer Core Client A Client B Client C σόΠευϥΠό γϯηαΠβʔ σόΠεͷυϥΠό ͱ͔͕࢖͏

Slide 33

Slide 33 text

Կނ͔ALSAυϥΠόͷυΩϡϝϯτͰ Ұ੾৮ΕΒΕ͍ͯͳ͍ IUUQXXXBMTBQSPKFDUPSHNBJOJOEFYQIQ "-4"@%SJWFS@%PDVNFOUBUJPO

Slide 34

Slide 34 text

SequencerͷΠϕϯτΛड͚औΔͱ printkͰग़ྗ͢ΔclientΛॻ͍ͯΈΑ͏ $ dmesg! …! [ 326.691419] NoteOn: 1 61 63! [ 326.691434] NoteOn: 1 66 63! [ 326.691436] NoteOn: 3 57 65! [ 326.691437] NoteOn: 4 49 78! [ 326.691438] NoteOn: 9 46 90! [ 326.692419] NoteOff: 9 46! [ 326.791411] NoteOff: 3 57! [ 326.791433] NoteOff: 4 49! [ 326.793413] NoteOn: 3 61 65! [ 326.793429] NoteOn: 4 49 78! $

Slide 35

Slide 35 text

}! if (!platform_get_drvdata(device_)) {! platform_device_unregister(device_);! device = NULL;! #ifdef MODULE! printk(! KERN_ERR! "Card-printkMIDI soundcard not found or device busy\n”! );! #endif! snd_printkmidi_unregister_all();! return -ENODEV;! }! device = device_;! return 0;! }! ! static void __exit alsa_card_printkmidi_exit(void) {! snd_printkmidi_unregister_all();! }! ! module_init(alsa_card_printkmidi_init);! module_exit(alsa_card_printkmidi_exit);! ! MODULE_AUTHOR("Naomasa Matsubayashi <>");! MODULE_DESCRIPTION("printk Client Driver");! MODULE_LICENSE("GPL"); SequencerͷΠϕϯτΛड͚औΔͱ printkͰग़ྗ͢ΔclientΛॻ͍ͯΈΑ͏ ιʔείʔυ͸ͪ͜Β https://github.com/Fadis/kernelvm_20150815_samples/blob/ master/kernel/printkmidi.c

Slide 36

Slide 36 text

static int __init alsa_card_printkmidi_init(void) {! int err;! struct platform_device *device_;! err = platform_driver_register(&snd_printkmidi_driver);! if (err < 0) return err;! device_ = platform_device_register_simple(! "snd_printk", 0, NULL, 0! ); ! if (IS_ERR(device_)) {! device = NULL;! #ifdef MODULE! printk(! KERN_ERR! "Card-printkMIDI soundcard not found or device busy\n”! );! #endif! snd_printkmidi_unregister_all();! return -ENODEV;! }! if (!platform_get_drvdata(device_)) {! platform_device_unregister(device_);! device = NULL;! #ifdef MODULE! printk(! KERN_ERR! "Card-printkMIDI soundcard not found or device busy\n”! ιʔείʔυ͸ͪ͜Β https://github.com/Fadis/kernelvm_20150815_samples/blob/ master/kernel/printkmidi.c

Slide 37

Slide 37 text

! ! ! ! ! static int __init alsa_card_printkmidi_init(void) {! int err;! struct platform_device *device_;! err = platform_driver_register(&snd_printkmidi_driver);! if (err < 0) return err;! device_ = platform_device_register_simple(! "snd_printk", 0, NULL, 0! ); ! if (IS_ERR(device_)) {! device = NULL;! #ifdef MODULE! printk(! KERN_ERR! "Card-printkMIDI soundcard not found or device busy\n”! );! #endif! snd_printkmidi_unregister_all();! return -ENODEV;! }! if (!platform_get_drvdata(device_)) {! platform_device_unregister(device_);! device = NULL;! platform busʹ৽͍͠σόΠε snd_printk Λ௥Ճ ιʔείʔυ͸ͪ͜Β https://github.com/Fadis/kernelvm_20150815_samples/blob/ master/kernel/printkmidi.c

Slide 38

Slide 38 text

static int snd_printkmidi_probe( struct platform_device *devptr ) {! struct snd_card *card;! struct snd_printk *printk_;! struct snd_seq_printk_dev *rdev;! int err;! int client;! card = NULL;! err = snd_card_new(! &devptr->dev, -1, NULL, THIS_MODULE,! sizeof(struct snd_printk ), &card! );! if( err < 0 ) {! dev_err( &devptr->dev, "Unable to create snd_card: %d\n", err );! return err;! }! printk_ = card->private_data;! printk_->card = card;! ! /* create client */! client = snd_seq_create_kernel_client( card, 0, "printk" );! if ( client < 0 ) {! snd_card_free( card );! return client;! }! rdev = create_port( client, 0 );! if ( rdev == NULL ) {!

Slide 39

Slide 39 text

static int snd_printkmidi_probe( struct platform_device *devptr ) {! struct snd_card *card;! struct snd_printk *printk_;! struct snd_seq_printk_dev *rdev;! int err;! int client;! card = NULL;! err = snd_card_new(! &devptr->dev, -1, NULL, THIS_MODULE,! sizeof(struct snd_printk ), &card! );! if( err < 0 ) {! dev_err( &devptr->dev, "Unable to create snd_card: %d\n", err );! return err;! }! printk_ = card->private_data;! printk_->card = card;! ! /* create client */! client = snd_seq_create_kernel_client( card, 0, "printk" );! if ( client < 0 ) {! snd_card_free( card );! return client;! }! rdev = create_port( client, 0 );! if ( rdev == NULL ) {! snd_card_new Ͱ ৽͍͠α΢ϯυΧʔυΛ࡞੒ ͜ͷลΓ͸ PCMͷα΢ϯυΧʔυͷ৔߹ͱҰॹ

Slide 40

Slide 40 text

}! printk_ = card->private_data;! printk_->card = card;! ! /* create client */! client = snd_seq_create_kernel_client( card, 0, "printk" );! if ( client < 0 ) {! snd_card_free( card );! return client;! }! rdev = create_port( client, 0 );! if ( rdev == NULL ) {! snd_seq_delete_kernel_client( client );! snd_card_free( card );! return -ENOMEM;! }! printk_->rdev = rdev;! rdev->card = card;! rdev->chset = snd_midi_channel_alloc_set( 16 );! if ( rdev->chset == NULL ) {! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free( card );! err = -ENOMEM;! }! rdev->client = client;! snd_seq_create_kernel_client Ͱ Sequencer ClientΛ࡞੒ Client͕ग़དྷͨΒϙʔτΛ࡞੒͢Δ

Slide 41

Slide 41 text

static struct snd_seq_printk_dev *create_port( int client, int type ) {! struct snd_seq_port_info pinfo;! struct snd_seq_port_callback pcb;! struct snd_seq_printk_dev *rdev;! if ((rdev = kzalloc(sizeof(*rdev), GFP_KERNEL)) == NULL)! return NULL;! rdev->client = client;! memset(&pinfo, 0, sizeof(pinfo));! pinfo.addr.client = client;! strcpy( pinfo.name, "printk" );! pinfo.capability = SNDRV_SEQ_PORT_CAP_READ |! SNDRV_SEQ_PORT_CAP_SUBS_READ;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE |! SNDRV_SEQ_PORT_CAP_SUBS_WRITE;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;! pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC! | SNDRV_SEQ_PORT_TYPE_SOFTWARE! | SNDRV_SEQ_PORT_TYPE_PORT;! pinfo.midi_channels = 16;! memset(&pcb, 0, sizeof(pcb));! pcb.owner = THIS_MODULE;! pcb.subscribe = printk_subscribe;! pcb.unsubscribe = printk_unsubscribe;! pcb.use = printk_use;! pcb.unuse = printk_unuse;!

Slide 42

Slide 42 text

memset(&pinfo, 0, sizeof(pinfo));! pinfo.addr.client = client;! strcpy( pinfo.name, "printk" );! pinfo.capability = SNDRV_SEQ_PORT_CAP_READ |! SNDRV_SEQ_PORT_CAP_SUBS_READ;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE |! SNDRV_SEQ_PORT_CAP_SUBS_WRITE;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;! pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC! | SNDRV_SEQ_PORT_TYPE_SOFTWARE! | SNDRV_SEQ_PORT_TYPE_PORT;! pinfo.midi_channels = 16;! memset(&pcb, 0, sizeof(pcb));! pcb.owner = THIS_MODULE;! pcb.subscribe = printk_subscribe;! pcb.unsubscribe = printk_unsubscribe;! pcb.use = printk_use;! pcb.unuse = printk_unuse;! pcb.event_input = printk_input;! pcb.private_data = rdev;! pinfo.kernel = &pcb;! if ( snd_seq_kernel_client_ctl(! client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo! ) < 0 ) {! kfree(rdev);! return NULL;! ͜ͷϙʔτ͕ͲΜͳػೳΛ͍࣋ͬͯΔ͔ͱ

Slide 43

Slide 43 text

memset(&pinfo, 0, sizeof(pinfo));! pinfo.addr.client = client;! strcpy( pinfo.name, "printk" );! pinfo.capability = SNDRV_SEQ_PORT_CAP_READ |! SNDRV_SEQ_PORT_CAP_SUBS_READ;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE |! SNDRV_SEQ_PORT_CAP_SUBS_WRITE;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;! pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC! | SNDRV_SEQ_PORT_TYPE_SOFTWARE! | SNDRV_SEQ_PORT_TYPE_PORT;! pinfo.midi_channels = 16;! memset(&pcb, 0, sizeof(pcb));! pcb.owner = THIS_MODULE;! pcb.subscribe = printk_subscribe;! pcb.unsubscribe = printk_unsubscribe;! pcb.use = printk_use;! pcb.unuse = printk_unuse;! pcb.event_input = printk_input;! pcb.private_data = rdev;! pinfo.kernel = &pcb;! if ( snd_seq_kernel_client_ctl(! client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo! ) < 0 ) {! kfree(rdev);! return NULL;! ϙʔτʹଞͷϙʔτ͕઀ଓ͖ͯͨ͠Γ Πϕϯτ͕ඈΜͰ͖ͨ࣌ʹ ݺͼग़͞ΕΔؔ਺Λઃఆ

Slide 44

Slide 44 text

memset(&pinfo, 0, sizeof(pinfo));! pinfo.addr.client = client;! strcpy( pinfo.name, "printk" );! pinfo.capability = SNDRV_SEQ_PORT_CAP_READ |! SNDRV_SEQ_PORT_CAP_SUBS_READ;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE |! SNDRV_SEQ_PORT_CAP_SUBS_WRITE;! pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;! pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC! | SNDRV_SEQ_PORT_TYPE_SOFTWARE! | SNDRV_SEQ_PORT_TYPE_PORT;! pinfo.midi_channels = 16;! memset(&pcb, 0, sizeof(pcb));! pcb.owner = THIS_MODULE;! pcb.subscribe = printk_subscribe;! pcb.unsubscribe = printk_unsubscribe;! pcb.use = printk_use;! pcb.unuse = printk_unuse;! pcb.event_input = printk_input;! pcb.private_data = rdev;! pinfo.kernel = &pcb;! if ( snd_seq_kernel_client_ctl(! client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo! ) < 0 ) {! kfree(rdev);! return NULL;! snd_seq_kernel_client_ctl ʹ SND_SEQ_IOCTL_CREATE_PORT Λࢦఆͯ͠ ϙʔτΛ࡞੒

Slide 45

Slide 45 text

dev_err( &devptr->dev, "Unable to create snd_card: %d\n", err );! return err;! }! printk_ = card->private_data;! printk_->card = card;! ! /* create client */! client = snd_seq_create_kernel_client( card, 0, "printk" );! if ( client < 0 ) {! snd_card_free( card );! return client;! }! rdev = create_port( client, 0 );! if ( rdev == NULL ) {! snd_seq_delete_kernel_client( client );! snd_card_free( card );! return -ENOMEM;! }! printk_->rdev = rdev;! rdev->card = card;! rdev->chset = snd_midi_channel_alloc_set( 16 );! if ( rdev->chset == NULL ) {! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free( card );! err = -ENOMEM;!

Slide 46

Slide 46 text

if ( rdev == NULL ) {! snd_seq_delete_kernel_client( client );! snd_card_free( card );! return -ENOMEM;! }! printk_->rdev = rdev;! rdev->card = card;! rdev->chset = snd_midi_channel_alloc_set( 16 );! if ( rdev->chset == NULL ) {! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free( card );! err = -ENOMEM;! }! rdev->client = client;! rdev->chset->client = client;! rdev->chset->private_data = rdev;! ! strcpy(card->driver, "printk");! strcpy(card->shortname, "printk");! sprintf(card->longname, "printk Card %i", devptr->id + 1);! err = snd_card_register(card);! if (!err) {! platform_set_drvdata(devptr, card);! return 0;! }! MIDIεςʔτΛอ࣋͢Δߏ଄ମΛ࡞੒

Slide 47

Slide 47 text

MIDI emulation ϠϚϋͷ'.Իݯ౳͸ঢ়ଶΛຆͲ࣋ͨͣ /05&0/࣌ʹԻ৭ʹؔ͢Δ৘ใΛ ·ͱΊͯϨδελʹॻ͖ࠐΉ "-4"4FRVFODFSͷΠϕϯτ͸ $MJFOU͕ঢ়ଶΛهԱ͍ͯ͠ΔࣄΛ લఏͱͯ͠ɺঢ়ଶͷมԽΛ௨஌ͯ͘͠Δ ͜ΕΒͷσόΠεͷυϥΠόΛॻ͘ҝʹ͸ υϥΠό͕ঢ়ଶΛ͓֮͑ͯ͘ඞཁ͕͋Δ

Slide 48

Slide 48 text

MIDI emulation ͜ΕΒͷσόΠεͷυϥΠόΛॻ͘ҝʹ͸ υϥΠό͕ঢ়ଶΛ͓֮͑ͯ͘ඞཁ͕͋Δ .*%*γʔέϯαͷঢ়ଶΛ͓֮͑ͯ͘ߏ଄ମ snd_midi_channel_set struct snd_midi_channel_set {! void *private_data;! int client;! int port;! int max_channels;! struct snd_midi_channel *channels;! unsigned char midi_mode;! unsigned char gs_master_volume;! unsigned char gs_chorus_mode;! unsigned char gs_reverb_mode;! };

Slide 49

Slide 49 text

MIDI emulation ֤νϟωϧͷঢ়ଶΛ͓֮͑ͯ͘ߏ଄ମ snd_midi_channel struct snd_midi_channel *channels;! unsigned char midi_mode;! unsigned char gs_master_volume;! unsigned char gs_chorus_mode;! unsigned char gs_reverb_mode;! }; struct snd_midi_channel {! void *private;! int number;! int client;! int port;! unsigned char midi_mode;! unsigned int drum_channel:1, param_type:1;! unsigned char midi_aftertouch;! unsigned char midi_pressure;! unsigned char midi_program;! short midi_pitchbend;! unsigned char control[128];! unsigned char note[128];! short gm_rpn_pitch_bend_range;! short gm_rpn_fine_tuning;! short gm_rpn_coarse_tuning;! }; Իྔ΍ύϯϙοτ ൃԻதͷԻ֊ ϐονϕϯυͷ෯

Slide 50

Slide 50 text

MIDI emulation ͜ΕΒͷσόΠεͷυϥΠόΛॻ͘ҝʹ͸ υϥΠό͕ঢ়ଶΛ͓֮͑ͯ͘ඞཁ͕͋Δ .*%*γʔέϯαͷঢ়ଶΛ͓֮͑ͯ͘ߏ଄ମ snd_midi_channel_set snd_seq_midi_emulϞδϡʔϧ͕ ड͚औͬͨΠϕϯτʹج͍ͮͯ ͜ͷߏ଄ମͷ஋Λߋ৽͢Δ࢓૊ΈΛఏڙ

Slide 51

Slide 51 text

return client;! }! rdev = create_port( client, 0 );! if ( rdev == NULL ) {! snd_seq_delete_kernel_client( client );! snd_card_free( card );! return -ENOMEM;! }! printk_->rdev = rdev;! rdev->card = card;! rdev->chset = snd_midi_channel_alloc_set( 16 );! if ( rdev->chset == NULL ) {! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free( card );! err = -ENOMEM;! }! rdev->client = client;! rdev->chset->client = client;! rdev->chset->private_data = rdev;! ! strcpy(card->driver, "printk");! strcpy(card->shortname, "printk");! sprintf(card->longname, "printk Card %i", devptr->id + 1);! err = snd_card_register(card);! if (!err) {! platform_set_drvdata(devptr, card);! TOE@TFR@NJEJ@FNVMͷؔ਺ snd_midi_channel_alloc_set ͸ MIDIγʔέϯαͷঢ়ଶΛอ࣋͢Δߏ଄ମ snd_midi_channel_setΛ࡞੒͢Δ Ҿ਺͸MIDIͷνϟωϧ਺

Slide 52

Slide 52 text

}! printk_->rdev = rdev;! rdev->card = card;! rdev->chset = snd_midi_channel_alloc_set( 16 );! if ( rdev->chset == NULL ) {! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free( card );! err = -ENOMEM;! }! rdev->client = client;! rdev->chset->client = client;! rdev->chset->private_data = rdev;! ! strcpy(card->driver, "printk");! strcpy(card->shortname, "printk");! sprintf(card->longname, "printk Card %i", devptr->id + 1);! err = snd_card_register(card);! if (!err) {! platform_set_drvdata(devptr, card);! return 0;! }! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free(card);! return err;! α΢ϯυΧʔυΛొ࿥

Slide 53

Slide 53 text

! struct snd_midi_op printk_ops = { .note_on = snd_printk_note_on, .note_off = snd_printk_note_off, .key_press = snd_printk_key_press, .note_terminate = snd_printk_terminate_note, .control = snd_printk_control, .nrpn = snd_printk_nrpn, .sysex = snd_printk_sysex, }; static int printk_input( struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop ) { struct snd_seq_printk_dev *rdev; rdev = private_data; if (!(rdev->flags & SNDRV_PRINTKMIDI_USE)) return 0; snd_midi_process_event( &printk_ops, ev, rdev->chset ); return 0; }

Slide 54

Slide 54 text

! struct snd_midi_op printk_ops = { .note_on = snd_printk_note_on, .note_off = snd_printk_note_off, .key_press = snd_printk_key_press, .note_terminate = snd_printk_terminate_note, .control = snd_printk_control, .nrpn = snd_printk_nrpn, .sysex = snd_printk_sysex, }; static int printk_input( struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop ) { struct snd_seq_printk_dev *rdev; rdev = private_data; if (!(rdev->flags & SNDRV_PRINTKMIDI_USE)) return 0; snd_midi_process_event( &printk_ops, ev, rdev->chset ); return 0; } ϙʔτʹΠϕϯτ͕དྷͨΒ snd_seq_midi_emulͷ snd_midi_process_eventʹ౉͢

Slide 55

Slide 55 text

struct snd_midi_op printk_ops = { .note_on = snd_printk_note_on, .note_off = snd_printk_note_off, .key_press = snd_printk_key_press, .note_terminate = snd_printk_terminate_note, .control = snd_printk_control, .nrpn = snd_printk_nrpn, .sysex = snd_printk_sysex, }; static int printk_input( struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop ) { struct snd_seq_printk_dev *rdev; rdev = private_data; if (!(rdev->flags & SNDRV_PRINTKMIDI_USE)) return 0; snd_midi_process_event( &printk_ops, ev, rdev->chset ); return 0; } ! • 伴൫Λԡͨ͠ • 伴൫Λ཭ͨ͠ • ΩʔϓϨογϟʔ͕มԽͨ͠ • ࠓ͙͢ԻΛࢭΊΔඞཁ͕͋Δ • ϐον౳͕มԽͨ͠ • NRPNΛड͚औͬͨ • SysExΛड͚औͬͨ ʜ࣌ʹݺͼग़͞ΕΔؔ਺

Slide 56

Slide 56 text

void snd_printk_note_on( void *p, int note, int vel, struct snd_midi_channel *chan ) { unsigned long flags; bool send_program_change = false; struct snd_seq_printk_dev *rdev; rdev = p; if( chan->midi_program != rdev->current_program[ chan->number ] ) { rdev->current_program[ chan->number ] = chan->midi_program; send_program_change = true; } if( send_program_change ) printk( "Prog: %d %d\n", chan->number, chan->midi_program ); printk( "NoteOn: %d %d %d\n”, chan->number, note,

Slide 57

Slide 57 text

void snd_printk_note_on( void *p, int note, int vel, struct snd_midi_channel *chan ) { unsigned long flags; bool send_program_change = false; struct snd_seq_printk_dev *rdev; rdev = p; if( chan->midi_program != rdev->current_program[ chan->number ] ) { rdev->current_program[ chan->number ] = chan->midi_program; send_program_change = true; } if( send_program_change ) printk( "Prog: %d %d\n", chan->number, chan->midi_program ); printk( "NoteOn: %d %d %d\n”, chan->number, note, ୈ2Ҿ਺ ԡ͞Εͨ伴൫ͷϊʔτφϯόʔ(Ի֊) ୈ3Ҿ਺ ԡ͞Εͨ伴൫ͷϕϩγςΟ ୈ1Ҿ਺ snd_midi_channel_set ʹઃఆͨ͠Ϣʔβσʔλ ୈ4Ҿ਺ 伴൫͕ԡ͞ΕͨMIDIνϟωϧͷঢ়ଶ

Slide 58

Slide 58 text

) { unsigned long flags; bool send_program_change = false; struct snd_seq_printk_dev *rdev; rdev = p; if( chan->midi_program != rdev->current_program[ chan->number ] ) { rdev->current_program[ chan->number ] = chan->midi_program; send_program_change = true; } if( send_program_change ) printk( "Prog: %d %d\n", chan->number, chan->midi_program ); printk( "NoteOn: %d %d %d\n”, chan->number, note, vel * chan->gm_volume * chan->gm_expression / 128 / 128 ); } printkͰग़ྗ

Slide 59

Slide 59 text

# modprobe snd_printkmidi! # aplaymidi -l! Port Client name Port name! 14:0 Midi Through Midi Through Port-0! 16:0 printk printk ৽͍͠ALSA Sequencer Client printk

Slide 60

Slide 60 text

# aplaymidi --port 16:0 hoge.mid ͜ͷSequencer ClientͰద౰ͳSMFϑΝΠϧΛ࠶ੜ $ dmesg! …! [ 326.691419] NoteOn: 1 61 63! [ 326.691434] NoteOn: 1 66 63! [ 326.691436] NoteOn: 3 57 65! [ 326.691437] NoteOn: 4 49 78! [ 326.691438] NoteOn: 9 46 90! [ 326.692419] NoteOff: 9 46! [ 326.791411] NoteOff: 3 57! [ 326.791433] NoteOff: 4 49! [ 326.793413] NoteOn: 3 61 65! [ 326.793429] NoteOn: 4 49 78! $ ΧʔωϧϩάʹΠϕϯτ͕ྲྀΕͯ͘Δ

Slide 61

Slide 61 text

printk͡Όͳͯ͘ ࣮ࡍʹσόΠε͔ΒԻΛग़ͯ͠Έ͍ͨ

Slide 62

Slide 62 text

ALSA Sequencer͕αϙʔτ͍ͯ͠Δ ϋʔυ΢ΣΞ YAMAHA OPL3 YAMAHA OPL4 E-MU 8000 E-MU 10k1 1992೥ࠒ 1995೥ࠒ 1994೥ࠒ 1998೥ࠒ α΢ϯυΧʔυʹγϯηαΠβʔ͕උΘ͍ͬͯΔͷ͸ ਵ෼ੲͷ࿩ʹͳͬͯ͠·ͬͨ

Slide 63

Slide 63 text

ୈճΧʔωϧVMؔ੢ ৐ࢉ໋ྩ͕࢒೦ͳ ARM Cortex-M0+ͷϚΠίϯͰ ιϑτ΢ΣΞFMԻݯΛ࡞ͬͨ࿩

Slide 64

Slide 64 text

ϫλγ '.Իݯ νϣοτσΩϧ !ͭ͘͹

Slide 65

Slide 65 text

ϫλγ '.Իݯ ϞοτσΩϧ

Slide 66

Slide 66 text

IUUQTIUMBCOFU 1+ࢯ Arduinoͷ YM2413 shieldΛ ࡞ͬͨੌ͍ਓ ϫλγ '.Իݯ ϞοτσΩϧ

Slide 67

Slide 67 text

ίϨΛ͋͛·͠ΐ͏

Slide 68

Slide 68 text

YAMAHA YM2413 FMԻݯ

Slide 69

Slide 69 text

α΢ϯυσόΠεͩ ALSAυϥΠόΛॻ͜͏ PJ͞Μ͋Γ͕ͱ͏͍͟͝·͢ YAMAHA YM2413 FMԻݯ

Slide 70

Slide 70 text

઀ଓ D0..D7 A0 8bitύϥϨϧ ϚϧνϓϨΫεόε

Slide 71

Slide 71 text

Z80A ΞυϨεόε σʔλόε ηΨϚʔΫ*** ೥୅౰࣌ͷ઀ଓྫ

Slide 72

Slide 72 text

ͪΐ͏Ͳྑ͍ύϥϨϧόε͕֎·Ͱग़͍ͯͳ͍ ΠϚυΩͷϚΠίϯϘʔυ GPIO/I2C/SPI/PWM/ADC/LCD/etc. UART USB Ethernet Z80A ΞυϨεόε σʔλόε

Slide 73

Slide 73 text

GPIOͰ௨৴͠Α͏

Slide 74

Slide 74 text

YM2413ͷσʔλγʔτ͸طʹ YAMAHAͷެࣜαΠτ͔Βແ͘ͳ͍ͬͯΔ͕ MSX޲͚ʹॻ͔Εͨ৘ใ͕୔ࢁ࢒͍ͬͯΔ http://d4.princess.ne.jp/msx/datas/OPLL/YM2413AP.html YM2413ΞϓϦέʔγϣϯϚχϡΞϧ

Slide 75

Slide 75 text

A0 CS WE D0..D7 10nsҎ্ 25nsҎ্ nsҎ্ nsҎ্ nsҎ্ nsҎ্ nsҎ্ ஗͘ͱ΋1MHz͘Β͍ͰGPIOΛૢ࡞͍ͨ͠ όΠτʹ͖ͭ0.2µs͘Β͍ͰૹΕΔ

Slide 76

Slide 76 text

LinuxΧʔωϧͰ1MHzͰGPIOΛ͍͡Δʹ͸ ࡞ઓ1 udelay( 1 ); ࡞ઓ2 usleep_range( 1 ); ࡞ઓ3 1µsຖʹGPIOͷ஋Λॻ͖׵͑ΔϚΠίϯͱ I2CͰ઀ଓ ஗͘ͱ΋1MHz͘Β͍ͰGPIOΛૢ࡞͍ͨ͠

Slide 77

Slide 77 text

SCL SDA "3.ϚΠίϯΛ࢖ͬͯ*$ʹม׵ YM2413ͷIOిѹ͸5V͚ͩͲ 2.7V͋Ε͹HIGHʹͳΔ͔Β IO3.3VͷLPC1114ʹ௚݁

Slide 78

Slide 78 text

SCL SDA "3.ϚΠίϯΛ࢖ͬͯ*$ʹม׵ BeagleBoneBlack EXT P8 I2C2_SCL 19 I2C2_SDA 20

Slide 79

Slide 79 text

λΠϚʔׂΓࠐΈ main() I2CׂΓࠐΈ ड৴Ωϡʔ ૹ৴Ωϡʔ GPIO I2C ىಈ ίϚϯυΛड৴ όεʹྲྀ͢஋ʹ ม׵ όεͷ஋Λߋ৽

Slide 80

Slide 80 text

i2c-devΛ࢖ͬͯ֬ೝ $ modprobe i2c-dev! $ i2cdetect! 00: —-! 20: 20 -- -- $ i2cset -y 2 0x20 0x10! $ i2cset -y 2 0x20 0x60! $ i2cset -y 2 0x20 0x7F i2cdetectͰσόΠεͷଘࡏΛ֬ೝ i2csetͰԻ͕ग़Ε͹੒ޭ

Slide 81

Slide 81 text

! ! ! ! ! ! static int snd_ym2413_probe(! struct i2c_client *bus,! const struct i2c_device_id *id_! ) {! struct snd_card *card;! struct snd_ym2413 *ym2413;! struct snd_seq_ym2413_dev *rdev;! int err;! int client;! card = NULL;! err = snd_card_new(! &bus->dev, -1, NULL, THIS_MODULE,! sizeof(struct snd_ym2413 ), &card! );! if( err < 0 ) {! dev_err( &bus->dev, "Unable to create snd_card: %d\n", err );! return err;! }! ym2413 = card->private_data;! ym2413->card = card;! σόΠευϥΠό͸جຊతʹ snd_printkͱಉ͡

Slide 82

Slide 82 text

! ! ! ! ! static struct i2c_device_id snd_ym2413_idtable[] = { ! { "ym2413", 0 },! { } ! };! ! static struct i2c_driver snd_ym2413_driver = { ! .driver = { ! .name = "snd_ym2413",! }, ! .probe = snd_ym2413_probe,! .remove = snd_ym2413_remove,! .id_table = snd_ym2413_idtable,! };! ! module_i2c_driver( snd_ym2413_driver );! ! MODULE_AUTHOR("Naomasa Matsubayashi <>");! i2cʹ෺ཧతͳσόΠε͕͋ΔͨΊ platform busͰ͸ͳ͘i2cʹͿΒԼ͛Δ

Slide 83

Slide 83 text

rdev->client = client;! rdev->chset->client = client;! rdev->chset->private_data = rdev;! printk("debug2 %lx\n", (unsigned long)rdev->bus );! rdev->work_queue = create_workqueue("ym2413_queue");! INIT_WORK(! (struct work_struct *)rdev, snd_ym2413_worker! );! ! strcpy(card->driver, "ym2413");! strcpy(card->shortname, "ym2413");! sprintf(card->longname, "ym2413 Card %i", card->number);! err = snd_card_register(card);! if (!err) {! bus->dev.platform_data = card;! return 0;! }! kfree( rdev );! snd_seq_delete_kernel_client( client );! snd_card_free(card); work queueΛ࡞੒ Seuqncer ClientͷίʔϧόοΫ͸ ALSA Sequencerͷεέδϡʔϥ͕࢖͏ ׂΓࠐΈͷத͔Βݺ͹ΕΔ ׂΓࠐΈͷதͰׂΓࠐΈΛ࢖͏I2CΛୟ͘ͱ Χʔωϧ͕ࢮΜͰ͠·͏ͷͰ work queueʹI2Cͷૢ࡞Λ౤͛Δ

Slide 84

Slide 84 text

static void snd_ym2413_worker( struct work_struct *work ) {! unsigned long flags;! struct snd_seq_ym2413_dev *rdev;! unsigned char buffer[128];! unsigned int buffer_size = 0;! rdev = (struct snd_seq_ym2413_dev*)work;! raw_spin_lock_irqsave(&rdev->bus_lock, flags);! buffer_size = rdev->buffer_head - rdev->buffer;! memcpy( buffer, rdev->buffer, buffer_size );! rdev->buffer_head = rdev->buffer;! raw_spin_unlock_irqrestore(&rdev->bus_lock, flags);! i2c_master_send( rdev->bus, buffer, buffer_size );! } work queueͷதͰi2cʹॻ͖ࠐΈ

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

typedef struct snd_seq_event {! snd_seq_event_type_t type; ! unsigned char flags; ! unsigned char tag; ! unsigned char queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t source; ! snd_seq_addr_t dest; ! union {! snd_seq_ev_note_t note; ! snd_seq_ev_ctrl_t control; ! snd_seq_ev_raw8_t raw8; ! snd_seq_ev_raw32_t raw32; ! snd_seq_ev_ext_t ext; ! snd_seq_ev_queue_control_t queue; ! snd_seq_timestamp_t time; ! snd_seq_addr_t addr; ! snd_seq_connect_t connect; ! snd_seq_result_t result; ! } data; ! } snd_seq_event_t; ͜ͷΠϕϯτ͕ ૹΒΕͨ࣌ࠁ Πϕϯτ͸࣌ࠁΛݟͯॲཧ͠Α͏

Slide 87

Slide 87 text

·ͱΊ ALSA SequencerͰ Իָͷԋ૗ΠϕϯτΛ΍ΓͱΓ ΠϕϯτΛड͚औΔClient͸ ϢʔβۭؒͰ΋ΧʔωϧۭؒͰ΋࡞ΕΔ ΧʔωϧۭؒClient͕ ϋʔυ΢ΣΞΛୟ͍ͯԻ৭Λ૗ͰΔ