* Re: Unable to Detect Bluetooth Device on Macbook Pro 9,2 (Mid-2012 13")
From: Shea Levy @ 2012-07-31 16:04 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth, linux-kernel@vger.kernel.org
In-Reply-To: <1343749923.1803.68.camel@aeonflux>
On 07/31/2012 11:52 AM, Marcel Holtmann wrote:
> Hi Shea,
>
>> Please CC me on response, I am not subscribed to the list.
>>
>> hcitool is unable to detect my laptop's bluetooth device:
>>
>> $ lsusb
>> Bus 004 Device 009: ID 05ac:821d Apple, Inc.
>> Bus 004 Device 008: ID 05ac:820b Apple, Inc.
>> Bus 004 Device 007: ID 05ac:820a Apple, Inc.
>> Bus 004 Device 006: ID 05ac:0252 Apple, Inc.
>> Bus 004 Device 005: ID 05ac:8242 Apple, Inc. IR Receiver [built-in]
>> Bus 004 Device 004: ID 0a5c:4500 Broadcom Corp. BCM2046B1 USB 2.0 Hub
>> (part of BCM2046 Bluetooth)
>> Bus 004 Device 003: ID 0424:2513 Standard Microsystems Corp.
>> Bus 004 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
>> Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
>> Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
>> Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
>> Bus 003 Device 003: ID 05ac:8509 Apple, Inc.
>> Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
>> Bus 003 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
>>
>> $ dmesg
>> <snip>
>> [ 4.744248] usb 4-1.8.1.3: new full-speed USB device number 9 using
>> ehci_hcd
>> [ 4.822041] usb 4-1.8.1.3: New USB device found, idVendor=05ac,
>> idProduct=821d
>> [ 4.822830] usb 4-1.8.1.3: New USB device strings: Mfr=1, Product=2,
>> SerialNumber=0
>> [ 4.823582] usb 4-1.8.1.3: Product: Bluetooth USB Host Controller
>> [ 4.824329] usb 4-1.8.1.3: Manufacturer: Apple Inc.
>> <snip>
>>
>> $ hciconfig -a
>>
>> $ hcitool dev
>> Devices:
>>
>> $ lsmod | grep bluetooth
>> bluetooth 187731 0
>> rfkill 15546 2 bluetooth,cfg80211
>> crc16 1311 2 bluetooth,ext4
>>
>> Any ideas?
> include /sys/kernel/debug/usb/devices details for this device.
Not sure, which device it is, so here's all of bus 4:
T: Bus=04 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 2
B: Alloc= 7/800 us ( 1%), #Int= 8, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=1d6b ProdID=0002 Rev= 3.05
S: Manufacturer=Linux 3.5.0 ehci_hcd
S: Product=EHCI Host Controller
S: SerialNumber=0000:00:1d.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms
T: Bus=04 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 8
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=8087 ProdID=0024 Rev= 0.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 2 Ivl=256ms
T: Bus=04 Lev=02 Prnt=02 Port=07 Cnt=01 Dev#= 3 Spd=480 MxCh= 3
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=02 MxPS=64 #Cfgs= 1
P: Vendor=0424 ProdID=2513 Rev= b.b3
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 2mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=01 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=256ms
I:* If#= 0 Alt= 1 #EPs= 1 Cls=09(hub ) Sub=00 Prot=02 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=256ms
T: Bus=04 Lev=03 Prnt=03 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 3
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0a5c ProdID=4500 Rev= 1.00
S: Manufacturer=Apple Inc.
S: Product=BRCM20702 Hub
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 94mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
T: Bus=04 Lev=04 Prnt=04 Port=00 Cnt=01 Dev#= 7 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=05ac ProdID=820a Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=01 Driver=usbhid
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=10ms
T: Bus=04 Lev=04 Prnt=04 Port=01 Cnt=02 Dev#= 8 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=05ac ProdID=820b Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=usbhid
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=10ms
T: Bus=04 Lev=04 Prnt=04 Port=02 Cnt=03 Dev#= 9 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=05ac ProdID=821d Rev= 0.86
S: Manufacturer=Apple Inc.
S: Product=Bluetooth USB Host Controller
C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
T: Bus=04 Lev=03 Prnt=03 Port=01 Cnt=02 Dev#= 5 Spd=1.5 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=05ac ProdID=8242 Rev= 0.16
S: Manufacturer=Apple Computer, Inc.
S: Product=IR Receiver
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid
E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=10ms
T: Bus=04 Lev=03 Prnt=03 Port=02 Cnt=03 Dev#= 6 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=05ac ProdID=0252 Rev= 2.19
S: Manufacturer=Apple Inc.
S: Product=Apple Internal Keyboard / Trackpad
C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr= 40mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=01 Driver=usbhid
E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=8ms
I:* If#= 1 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid
E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=2ms
I:* If#= 2 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=bcm5974
E: Ad=84(I) Atr=03(Int.) MxPS= 8 Ivl=8ms
> Regards
>
> Marcel
>
>
Thanks,
Shea
^ permalink raw reply
* Re: Unable to Detect Bluetooth Device on Macbook Pro 9,2 (Mid-2012 13")
From: Marcel Holtmann @ 2012-07-31 16:12 UTC (permalink / raw)
To: Shea Levy; +Cc: linux-bluetooth, linux-kernel@vger.kernel.org
In-Reply-To: <50180209.1090002@shealevy.com>
Hi Shea,
> > include /sys/kernel/debug/usb/devices details for this device.
>
> Not sure, which device it is, so here's all of bus 4:
<snip>
> T: Bus=04 Lev=04 Prnt=04 Port=02 Cnt=03 Dev#= 9 Spd=12 MxCh= 0
> D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
> P: Vendor=05ac ProdID=821d Rev= 0.86
> S: Manufacturer=Apple Inc.
> S: Product=Bluetooth USB Host Controller
> C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
> E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
> E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
> E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
lets take the one that says Bluetooth USB Host Controller ;)
Regards
Marcel
^ permalink raw reply
* Re: Unable to Detect Bluetooth Device on Macbook Pro 9,2 (Mid-2012 13")
From: Shea Levy @ 2012-07-31 16:20 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth, linux-kernel@vger.kernel.org
In-Reply-To: <1343751179.1803.73.camel@aeonflux>
On 07/31/2012 12:12 PM, Marcel Holtmann wrote:
> Hi Shea,
>
>>> include /sys/kernel/debug/usb/devices details for this device.
>> Not sure, which device it is, so here's all of bus 4:
> <snip>
>
>> T: Bus=04 Lev=04 Prnt=04 Port=02 Cnt=03 Dev#= 9 Spd=12 MxCh= 0
>> D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
>> P: Vendor=05ac ProdID=821d Rev= 0.86
>> S: Manufacturer=Apple Inc.
>> S: Product=Bluetooth USB Host Controller
>> C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
>> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
>> E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
>> E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
>> E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
>> I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
>> I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
>> I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
>> I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
>> I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
>> I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
>> E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
>> E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
>> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
>> E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
>> E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
>> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
> lets take the one that says Bluetooth USB Host Controller ;)
Sorry, braindead moment. Thanks.
> Regards
>
> Marcel
>
>
~Shea
^ permalink raw reply
* Re: [PATCH 0/2] Support for reserving bandwidth on L2CAP socket
From: Mat Martineau @ 2012-07-31 16:58 UTC (permalink / raw)
To: Manoj Sharma, Luiz Augusto von Dentz
Cc: Marcel Holtmann, linux-bluetooth, Anurag Gupta
In-Reply-To: <CABBYNZ+zPxfKn--E6fSGF8gUj-jLN4MVbZqHcj=E4ZOgcft9tg@mail.gmail.com>
Manoj and Luiz -
On Tue, 31 Jul 2012, Luiz Augusto von Dentz wrote:
> Hi Manoj,
>
> On Tue, Jul 31, 2012 at 2:30 PM, Manoj Sharma <ursmanoj@gmail.com> wrote:
>> Hi Luiz,
>>
>> On 7/30/12, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
>>> Hi Manoj,
>>>
>>> On Mon, Jul 30, 2012 at 9:30 AM, Manoj Sharma <ursmanoj@gmail.com> wrote:
>>>> One problem which I have faced using SO_PRIORITY is explained below.
>>>>
>>>> Suppose we have 2 links A & B and link A has higher priority than link
>>>> B. And outgoing data transfer is active on both links. Now if device
>>>> on link A goes far, there would be lot of failures and number of
>>>> re-transmissions would increase for link A. Consequently at any time
>>>> host would have significant number of packets for link A, getting
>>>> accumulated due to poor quality of link.But since link A packets have
>>>> higher priority, link B packets would suffer infinitely as long as
>>>> link A packet queue in host is non-empty. Thus link B protocols may
>>>> fail due to timers expiring and finally disconnection at upper layers.
>>>
>>> There is a mechanism to avoid starvation, also apparently you didn't
>>> study the code since the priority is per L2CAP channel not per link so
>>> we are able to prioritize per profile.
>>>
>> I would check how starvation is avoided. But for your information I
>> did observe starvation practically. And I know that priority is per
>> L2CAP. I mentioned links based on assumption that AVDTP and OBEX are
>> connected with different devices. Hence priority would result into
>> priority of connections in such case ;).
>
> There is no such thing of prioritize a connection, the algorithm used
> always check every channel of each connection and prioritize the
> channel. Maybe you are confusing what some controllers do, the
> controller has no idea what L2CAP channel has been configured it only
> knows about the ACL connections.
The current starvation avoidance algorithm works well as long as there
is data queued for all of the L2CAP channels and the controller is
sending packets regularly. It does seem to break down when the
controller queue gets stuck (see below).
>>>> Second problem:
>>>> We have two links similar to above scenario. Say link A is being used
>>>> by AVDTP and link B is being used by OBEX. Host can come across a
>>>> situation where all controller buffers are used by OBEX and AVDTP is
>>>> waiting for a free buffer. Now due to some reason (e.g. distance) OBEX
>>>> link B goes weak. This results into delay in transmission of OBEX
>>>> packets already held by controller and consequently AVDTP packets also
>>>> get delayed which causes glitches in music streaming and user
>>>> experience goes bad.
>>>
>>> That is exactly what SO_PRIORITY has fixed, by setting SO_PRIORITY you
>>> prioritize AVDTP stream over OBEX which means AVDTP can use a bigger
>>> part of the bandwidth while OBEX uses the remaining.
>>>
>> I disagree. Please try to understand the situation I explained again.
>> There can be a scenario when host has only OBEX packets and no AVDTP,
>> here irrespective of which channel has what priority OBEX may consume
>> all ACL credits. At the same moment OBEX link goes weak (e.g.due to
>> distance), this would delay the transmission of all OBEX packets held
>> by controller. In the mean time, AVDTP packets reach Bluez but since
>> there are no credits left, host would have to delay transmission of
>> AVDTP until a OBEX packet is transferred and an NOCP is received. This
>> would definitely cause a glitch on AVDTP streaming and end user
>> experience would go bad. By reserving credits for AVDTP channel, we
>> ensure that OBEX packets doesnt eat up all credits while AVDTP packets
>> were absent.
>
> Without the use of guaranteed channels you cannot really guarantee
> anything, besides this would throttle OBEX transfer even when there is
> nothing streaming on AVDTP which I don't thing is acceptable. Also Ive
> never experience such a problem, you can start streaming while
> transferring something and that never produced any artifacts in the
> headsets I have, the only problem we have right now is paging another
> device while AVDTP stream is active may cause some audio glitches and
> even that could be avoided by tuning paging parameters while there is
> a high priority channel active.
>
> Btw, there is some lack of connection to the code, an OBEX packet
> could be quite big but that is not transmitted as it is, it is
> actually fragmented into L2CAP and then HCI frames, the HCI frames is
> the one being sent to the controller, the moment the AVDTP socket
> start producing another socket may be using some/all of the controller
> buffers e.g. 8:1021 that is at most 8K bytes of latency to startup the
> stream, in fact it is pretty common to audio to have some latency.
It's true that the amount of latency due to buffering in the
controller is minimal, and would not in itself cause streaming issues
*if* the controller is able to consume packets from the buffer.
I do see where a bad situation arises when the OBEX connection is
stalled and only queued OBEX data is available to the host stack HCI
scheduler at that instant. In that case, the controller queue could
be completely consumed by data for the stalled channel no matter what
the priorities are. This could even happen when audio data is passed
to the socket at exactly the right time.
If you're using OBEX-over-L2CAP, this could be partially addressed by
setting a flush timeout. However, it would still be possible to fill
the buffers with OBEX packets because non-flushable ERTM s-frames
would accumulate in the controller buffer.
For traditional OBEX-over-RFCOMM, an OBEX packet sizes that are
smaller than the controller buffer could help. This is a tradeoff
against throughput. It could work to send smaller OBEX packets when
an AVDTP stream is active, even if a larger OBEX MTU was negotiated.
It would be a big help if Manoj could post kernel logs showing us how
the HCI scheduler is actually behaving in the problem case.
While I'm convinced that a problem exists here, I think it can be
addressed using existing interfaces instead of adding a new one. For
example, it may be reasonable to not fully utilize the controller
buffer with data for just one ACL, or to use priority when looking at
controller buffer utilization. Maybe an ACL could use all but one
slot in the controller buffer, maybe it could only use half if there
are multiple ACLs open. I don't think it would throttle throughput
unless the system was so heavily loaded that it couldn't respond to
number-of-completed-packets in time at BR/EDR data rates, and in that
case there are bigger problems. It's pretty easy to test with
hdev->acl_pkts set to different values to see if using less of the
buffer impacts throughput.
Right now, one stalled ACL disrupts all data flow through the
controller. And that seems like a problem worth solving.
>>> The credit based algorithmic actually complicates more than solves the
>>> problems here because it should actually fail if there is no enough
>>> bandwidth as requested, so we would actually need to query how much
>>> credits are available, also any type of bandwidth reservation might be
>>> overkill with things like variable bit rate where you actually need to
>>> know what is maximum possible bandwidth you need to reserve before
>>> hand and that credits cannot be reserved by anyone else.
>>>
>> I agree, but we can provide a mechanism to allow only one channel to
>> reserve bandwidth. In most cases it would be AVDTP streaming channel.
>> Reserving at least one credit would allow preventing cases where
>> non-AVDTP channel eats all credits due to unavailability of AVDTP
>> packets. Please mind that since OBEX packets would be reaching bluez
>> much faster than AVDTP, such situation may arise very easily.
>
> That raises my suspicious that you are not really testing against
> PulseAudio and obexd, PA should be sending packets much faster than
> obexd since its IO threads are realtime so it will most likely have
> higher priority. Also the latency of OBEX packets are much greater as
> each packet is normally 32k-64k compared to AVDTP stream which send
> each packet individually (~700 bytes depending on the MTU).
>
>>>> These are the basic problems which I have faced and hence felt
>>>> necessity of a similar but different mechanism and came up with this
>>>> solution. This solution fixes both of the problems explained above.
>>>> Based on the explanation above your suggestion is required further.
>>>
>>> Could you please show us what system did you find this problem? We
>>> could possible help you trying to figure out what is going wrong,
>>> please note that SO_PRIORITY support was introduced in 3.0 and some
>>> system don't actually use it, in fact so far I think only PulseAudio
>>> make use of it.
>>>
>> Yes, but we forced Bluez AVDTP to use SO_PRIORITY on our system and
>> faced the starvation problem explained above. Though I am going to
>> study the priority patch again.
>
> Im afraid the problem is not SO_PRIORITY but your audio subsystem
> cannot keep up the socket buffer non-empty that would avoid OBEX
> taking too much bandwidth, but again that is pretty strange as you
> should be written much more frequently to the AVDTP socket to keep the
> latency of the audio constant.
I agree that SO_PRIORITY is not the problem, but I don't think this
can be fixed at the audio subsystem level either.
Regards,
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: [PATCH] please add VID/PID to ath3k (AR3012)
From: Yevgeniy Melnichuk @ 2012-07-31 17:20 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth, shafi.ath9k, gustavo
In-Reply-To: <1343750194.1803.70.camel@aeonflux>
Hi Marcel,
thank you for the hint. i hope i get it right the second time.
description:
the patch adds 0489:E036 to the blacklist in btusb and to the support
list in ath3k. The VID/PID belongs to AR3012 chips used by Sony Vaio
T-Series.
Signed-off-by: Yevgeniy Melnichuk <yevgeniy.melnichuk@googlemail.com>
patch:
diff -uprN linux-3.5-orig/drivers/bluetooth/ath3k.c
linux-3.5/drivers/bluetooth/ath3k.c
--- linux-3.5-orig/drivers/bluetooth/ath3k.c 2012-07-21 22:58:29.000000000 +0200
+++ linux-3.5/drivers/bluetooth/ath3k.c 2012-07-31 18:21:41.044493550 +0200
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[
{ USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0930, 0x0219) },
+ { USB_DEVICE(0x0489, 0xe036) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -107,6 +108,7 @@ static struct usb_device_id ath3k_blist_
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
diff -uprN linux-3.5-orig/drivers/bluetooth/btusb.c
linux-3.5/drivers/bluetooth/btusb.c
--- linux-3.5-orig/drivers/bluetooth/btusb.c 2012-07-21 22:58:29.000000000 +0200
+++ linux-3.5/drivers/bluetooth/btusb.c 2012-07-31 18:22:58.572494201 +0200
@@ -141,6 +141,7 @@ static struct usb_device_id blacklist_ta
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
content of /sys/kernel/debug/usb/devices:
T: Bus=04 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=5000 MxCh= 4
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 3.00 Cls=09(hub ) Sub=00 Prot=03 MxPS= 9 #Cfgs= 1
P: Vendor=1d6b ProdID=0003 Rev= 3.05
S: Manufacturer=Linux 3.5.0 xhci_hcd
S: Product=xHCI Host Controller
S: SerialNumber=0000:00:14.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms
T: Bus=03 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 4
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=1d6b ProdID=0002 Rev= 3.05
S: Manufacturer=Linux 3.5.0 xhci_hcd
S: Product=xHCI Host Controller
S: SerialNumber=0000:00:14.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms
T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 2
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=1d6b ProdID=0002 Rev= 3.05
S: Manufacturer=Linux 3.5.0 ehci_hcd
S: Product=EHCI Host Controller
S: SerialNumber=0000:00:1d.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 6
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=8087 ProdID=0024 Rev= 0.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=256ms
T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 2
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=1d6b ProdID=0002 Rev= 3.05
S: Manufacturer=Linux 3.5.0 ehci_hcd
S: Product=EHCI Host Controller
S: SerialNumber=0000:00:1a.0
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms
T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 6
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=8087 ProdID=0024 Rev= 0.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=256ms
T: Bus=01 Lev=02 Prnt=02 Port=01 Cnt=01 Dev#= 6 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=0489 ProdID=e036 Rev= 0.02
S: Manufacturer=Atheros Communications
S: Product=Bluetooth USB Host Controller
S: SerialNumber=Alaska Day 2006
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=04f2 ProdID=b328 Rev=29.17
S: Manufacturer=Chicony Electronics Co.,Ltd.
S: Product=USB 2.0 Camera
S: SerialNumber=0x0001
C:* #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=500mA
A: FirstIf#= 0 IfCount= 2 Cls=0e(video) Sub=03 Prot=00
I:* If#= 0 Alt= 0 #EPs= 1 Cls=0e(video) Sub=01 Prot=00 Driver=uvcvideo
E: Ad=83(I) Atr=03(Int.) MxPS= 16 Ivl=4ms
I:* If#= 1 Alt= 0 #EPs= 0 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
I: If#= 1 Alt= 1 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS= 128 Ivl=125us
I: If#= 1 Alt= 2 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS= 512 Ivl=125us
I: If#= 1 Alt= 3 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS=1024 Ivl=125us
I: If#= 1 Alt= 4 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS=1536 Ivl=125us
I: If#= 1 Alt= 5 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS=2048 Ivl=125us
I: If#= 1 Alt= 6 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS=2688 Ivl=125us
I: If#= 1 Alt= 7 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
E: Ad=81(I) Atr=05(Isoc) MxPS=3072 Ivl=125us
^ permalink raw reply
* Re: [PATCH] please add VID/PID to ath3k (AR3012)
From: Marcel Holtmann @ 2012-07-31 18:55 UTC (permalink / raw)
To: Yevgeniy Melnichuk; +Cc: linux-bluetooth, shafi.ath9k, gustavo
In-Reply-To: <CAJKEbdegKt1Pcx=QBQWWxe3=KYVr3WbH0PkBmfmDse3rF71MSA@mail.gmail.com>
Hi Yevgeniy,
> thank you for the hint. i hope i get it right the second time.
please use git format-patch and create a proper patch. This is just a
random collection of information.
Regards
Marcel
^ permalink raw reply
* l2ping Recv failed: Connection reset by peer
From: Charles Gordon @ 2012-07-31 21:12 UTC (permalink / raw)
To: linux-bluetooth
Hi,
I'm porting bluez 4.98 to an embedded system. I have it up and running, but
I notice that when I run l2ping, I get the message "Recv failed: Connection
reset by peer" after l2ping runs for 5 seconds. This is very consistent.
It doesn't matter whether I ping once a second, or do a flood ping. After 5
seconds the l2ping program closes with the message saying the connection was
reset by the peer.
This looks like some sort of timeout. Perhaps the timeout is there for
security reasons. I'd like to understand how to adjust the timeout, or at
least confirm that the system is working correctly.
I'm running Linux 2.6.35 and Bluez 4.98 on my embedded system, and Ubuntu
10.04 with Linux 2.6.32 and Bluez 4.60 on my PC.
I've looked through the Bluez configuration files and I don't see anything
that sets up security for L2CAP or sets timeouts that are relevant. I tried
increasing the PageTimeout in /etc/bluetooth/main.conf to 81920 (50 seconds)
on both systems, but that didn't make any difference. I also looked in the
configuration program hciconfig for an option to set a timeout, but I didn't
find anything.
Can anyone tell me what the relevant timeout for l2ping is and how to adjust
it, or at least why it is set for 5 seconds?
Thanks.
^ permalink raw reply
* Re: l2ping Recv failed: Connection reset by peer
From: Vinicius Costa Gomes @ 2012-07-31 22:33 UTC (permalink / raw)
To: Charles Gordon; +Cc: linux-bluetooth
In-Reply-To: <CAGjArBcwtaRoecSivEaN9FiCbGfC3JhFRwXUVqq58SmQhN07sQ@mail.gmail.com>
Hi Charles,
On 17:12 Tue 31 Jul, Charles Gordon wrote:
> Hi,
>
> I'm porting bluez 4.98 to an embedded system. I have it up and running, but
> I notice that when I run l2ping, I get the message "Recv failed: Connection
> reset by peer" after l2ping runs for 5 seconds. This is very consistent.
> It doesn't matter whether I ping once a second, or do a flood ping. After 5
> seconds the l2ping program closes with the message saying the connection was
> reset by the peer.
If I run l2ping without parameters, I get this:
l2ping - L2CAP ping
Usage:
l2ping [-i device] [-s size] [-c count] [-t timeout] [-d delay] [-f] [-r] [-v] <bdaddr>
-f Flood ping (delay = 0)
-r Reverse ping
-v Verify request and response payload
The '-t' option sounds promising.
But anyway, the default value for the timeout is 10 seconds. So I would like know
how would it behave with other values. Perhaps the remote side is disconnecting.
[snip]
Cheers,
--
Vinicius
^ permalink raw reply
* RE: [patch]Add Vendor/Device ID for AR3012
From: Chen, Peng @ 2012-08-01 1:49 UTC (permalink / raw)
To: Marcel Holtmann
Cc: gustavo@padovan.org, linux-bluetooth@vger.kernel.org,
Waller, Carolyn, Jeang, Daniel, Shanmugam Kamatchi, Bala,
Yao, Costa, Fan, Hong, Balasubramanian, Senthil Kumar, Wu, Frank
In-Reply-To: <0EC13EFF38B7C84DB595405A8233E35B099B1C02@nasanexd01b.na.qualcomm.com>
Hi Hotmann,=0A=
=0A=
How about this patch? Is there any problem?=0A=
=0A=
=0A=
Best Regards=0A=
Peng=0A=
=0A=
________________________________________=0A=
From: Chen, Peng=0A=
Sent: Monday, July 23, 2012 2:25 PM=0A=
To: Marcel Holtmann=0A=
Cc: gustavo@padovan.org; linux-bluetooth@vger.kernel.org; Waller, Carolyn; =
Jeang, Daniel; Shanmugam Kamatchi, Bala; Yao, Costa; Fan, Hong; Balasubrama=
nian, Senthil Kumar; Wu, Frank=0A=
Subject: RE: [patch]Add Vendor/Device ID for AR3012=0A=
=0A=
Hi Holtmann,=0A=
=0A=
Sorry. I am not familiar with using git to send mail right now.=0A=
_________________________=0A=
=0A=
=0A=
>From a1653337899ad56b23b52c43824445b8f23a24fd Mon Sep 17 00:00:00 2001=0A=
From: Peng Chen <pengchen@qca.qualcomm.com>=0A=
Date: Mon, 23 Jul 2012 12:56:20 +0800=0A=
Subject: [PATCH] Bluetooth: add support for atheros 0489:e057=0A=
=0A=
Add support for the AR3012 chip found on Foxconn.=0A=
=0A=
usb-devices shows:=0A=
=0A=
T: Bus=3D06 Lev=3D01 Prnt=3D01 Port=3D00 Cnt=3D01 Dev#=3D 44 Spd=3D12 =
MxCh=3D 0=0A=
D: Ver=3D 1.10 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 MxPS=3D64 #Cfgs=3D =
1=0A=
P: Vendor=3D0489 ProdID=3De057 Rev=3D 0.02=0A=
C:* #Ifs=3D 2 Cfg#=3D 1 Atr=3De0 MxPwr=3D100mA=0A=
I:* If#=3D 0 Alt=3D 0 #EPs=3D 3 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D81(I) Atr=3D03(Int.) MxPS=3D 16 Ivl=3D1ms=0A=
E: Ad=3D82(I) Atr=3D02(Bulk) MxPS=3D 64 Ivl=3D0ms=0A=
E: Ad=3D02(O) Atr=3D02(Bulk) MxPS=3D 64 Ivl=3D0ms=0A=
I:* If#=3D 1 Alt=3D 0 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 0 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 0 Ivl=3D1ms=0A=
I: If#=3D 1 Alt=3D 1 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 9 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 9 Ivl=3D1ms=0A=
I: If#=3D 1 Alt=3D 2 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 17 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 17 Ivl=3D1ms=0A=
I: If#=3D 1 Alt=3D 3 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 25 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 25 Ivl=3D1ms=0A=
I: If#=3D 1 Alt=3D 4 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 33 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 33 Ivl=3D1ms=0A=
I: If#=3D 1 Alt=3D 5 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driv=
er=3Dbtusb=0A=
E: Ad=3D83(I) Atr=3D01(Isoc) MxPS=3D 49 Ivl=3D1ms=0A=
E: Ad=3D03(O) Atr=3D01(Isoc) MxPS=3D 49 Ivl=3D1ms=0A=
=0A=
Signed-off-by: Peng Chen <pengchen@qca.qualcomm.com>=0A=
---=0A=
drivers/bluetooth/ath3k.c | 2 ++=0A=
drivers/bluetooth/btusb.c | 1 +=0A=
2 files changed, 3 insertions(+)=0A=
=0A=
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c=0A=
index 10308cd..11f36e5 100644=0A=
--- a/drivers/bluetooth/ath3k.c=0A=
+++ b/drivers/bluetooth/ath3k.c=0A=
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[] =3D {=0A=
{ USB_DEVICE(0x13d3, 0x3362) },=0A=
{ USB_DEVICE(0x0CF3, 0xE004) },=0A=
{ USB_DEVICE(0x0930, 0x0219) },=0A=
+ { USB_DEVICE(0x0489, 0xe057) },=0A=
=0A=
/* Atheros AR5BBU12 with sflash firmware */=0A=
{ USB_DEVICE(0x0489, 0xE02C) },=0A=
@@ -104,6 +105,7 @@ static struct usb_device_id ath3k_blist_tbl[] =3D {=0A=
{ USB_DEVICE(0x13d3, 0x3362), .driver_info =3D BTUSB_ATH3012 },=0A=
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info =3D BTUSB_ATH3012 },=0A=
{ USB_DEVICE(0x0930, 0x0219), .driver_info =3D BTUSB_ATH3012 },=0A=
+ { USB_DEVICE(0x0489, 0xe057), .driver_info =3D BTUSB_ATH3012 },=0A=
=0A=
/* Atheros AR5BBU22 with sflash firmware */=0A=
{ USB_DEVICE(0x0489, 0xE03C), .driver_info =3D BTUSB_ATH3012 },=0A=
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c=0A=
index e272214..4e007ac 100644=0A=
--- a/drivers/bluetooth/btusb.c=0A=
+++ b/drivers/bluetooth/btusb.c=0A=
@@ -133,6 +133,7 @@ static struct usb_device_id blacklist_table[] =3D {=0A=
{ USB_DEVICE(0x13d3, 0x3362), .driver_info =3D BTUSB_ATH3012 },=0A=
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info =3D BTUSB_ATH3012 },=0A=
{ USB_DEVICE(0x0930, 0x0219), .driver_info =3D BTUSB_ATH3012 },=0A=
+ { USB_DEVICE(0x0489, 0xe057), .driver_info =3D BTUSB_ATH3012 },=0A=
=0A=
/* Atheros AR5BBU12 with sflash firmware */=0A=
{ USB_DEVICE(0x0489, 0xe02c), .driver_info =3D BTUSB_IGNORE },=0A=
--=0A=
1.7.9.5=0A=
=0A=
^ permalink raw reply related
* Re: [patch]Add Vendor/Device ID for AR3012
From: Marcel Holtmann @ 2012-08-01 1:52 UTC (permalink / raw)
To: Chen, Peng
Cc: gustavo@padovan.org, linux-bluetooth@vger.kernel.org,
Waller, Carolyn, Jeang, Daniel, Shanmugam Kamatchi, Bala,
Yao, Costa, Fan, Hong, Balasubramanian, Senthil Kumar, Wu, Frank
In-Reply-To: <0EC13EFF38B7C84DB595405A8233E35B099B2EF2@nasanexd01b.na.qualcomm.com>
Hi Peng,
> How about this patch? Is there any problem?
please use git send-email so we can just use git am to apply them. You
need to submit patches the right way.
Regards
Marcel
^ permalink raw reply
* [PATCH] Bluetooth: add support for atheros 0489:e057
From: Peng Chen @ 2012-08-01 2:11 UTC (permalink / raw)
To: marcel; +Cc: linux-bluetooth, gustavo, Peng Chen
Add support for the AR3012 chip found on Fioxconn.
usb-devices shows:
T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 44 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=0489 ProdID=e057 Rev= 0.02
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
Signed-off-by: Peng Chen <pengchen@qca.qualcomm.com>
---
drivers/bluetooth/ath3k.c | 2 ++
drivers/bluetooth/btusb.c | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 10308cd..11f36e5 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0930, 0x0219) },
+ { USB_DEVICE(0x0489, 0xe057) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -104,6 +105,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e272214..4e007ac 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -133,6 +133,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
--
1.7.9.5
^ permalink raw reply related
* [PATCH] Add support for downloading binary patch.
From: Peng Chen @ 2012-08-01 2:42 UTC (permalink / raw)
To: marcel; +Cc: linux-bluetooth, Peng Chen
---
tools/hciattach_ath3k.c | 133 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 115 insertions(+), 18 deletions(-)
diff --git a/tools/hciattach_ath3k.c b/tools/hciattach_ath3k.c
index 23208c6..ec39f5e 100644
--- a/tools/hciattach_ath3k.c
+++ b/tools/hciattach_ath3k.c
@@ -498,6 +498,31 @@ static int set_patch_ram(int dev, char *patch_loc, int len)
return err;
}
+static int set_patch_ram_dfu(int dev, unsigned int addr)
+{
+ int err;
+ uint8_t cmd[20];
+ uint8_t *event;
+ uint8_t *loc_ptr = &cmd[7];
+
+ load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
+
+ loc_ptr[0] = (unsigned char)(addr & 0xff);
+ loc_ptr[1] = (unsigned char)((addr >> 8) & 0xff);
+ loc_ptr[2] = (unsigned char)((addr >> 16) & 0xff);
+ loc_ptr[3] = (unsigned char)((addr >> 24) & 0xff);
+
+ err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ free(event);
+
+ return err;
+}
+
#define PATCH_LOC_KEY "DA:"
#define PATCH_LOC_STRING_LEN 8
static int ps_patch_download(int fd, FILE *stream)
@@ -559,6 +584,60 @@ static int ps_patch_download(int fd, FILE *stream)
return patch_count;
}
+struct ATHDFU_FILEHDR {
+ uint32_t AF_WriteAddr; /* download the file to af_write_addr */
+ uint32_t AF_EntryAddr; /* the application program's entry address */
+ uint32_t AF_FileLength; /* the application program's length */
+ uint32_t AF_FileCRC; /* crc the application */
+ uint32_t AF_FileType; /* the file type */
+};
+
+#define DFU_GAP 12
+
+static int ps_patch_download_dfu(int fd, FILE *stream)
+{
+ struct ATHDFU_FILEHDR dfu_hdr;
+ uint8_t dfu_gap[DFU_GAP];
+ int byte_cnt = 0;
+ int patch_count = 0;
+
+ if ((fread((uint8_t *)&dfu_hdr, 1, sizeof(dfu_hdr), stream))
+ < sizeof(dfu_hdr))
+ return -1;
+ set_patch_ram_dfu(fd, dfu_hdr.AF_WriteAddr);
+
+ if ((fread(dfu_gap, 1, DFU_GAP, stream)) < DFU_GAP)
+ return -1;
+
+ byte_cnt = dfu_hdr.AF_FileLength - DFU_GAP;
+
+ while (byte_cnt > 0) {
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ struct patch_entry patch;
+
+ if (byte_cnt > MAX_PATCH_CMD)
+ patch.len = MAX_PATCH_CMD;
+ else
+ patch.len = byte_cnt;
+
+ if ((fread(patch.data, 1, patch.len, stream))
+ < (uint16_t)patch.len)
+ return -1;
+
+ load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
+
+ if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
+ return -1;
+
+ patch_count++;
+ byte_cnt = byte_cnt - patch.len;
+ }
+
+ if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
+ return -1;
+ return 1;
+}
#define PS_RAM_SIZE 2048
static int ps_config_download(int fd, int tag_count)
@@ -588,19 +667,31 @@ static void get_ps_file_name(uint32_t devtype, uint32_t rom_version,
snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
}
-#define PATCH_FILE "RamPatch.txt"
+#define TXT_PATCH_FILE "RamPatch.txt"
+#define DFU_PATCH_FILE "AthrBT_0x0"
#define FPGA_ROM_VERSION 0x99999999
#define ROM_DEV_TYPE 0xdeadc0de
-static void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
- uint32_t build_version, char *path)
+static void get_file_name_of_patch_in_txt_format(uint32_t dev_type,
+ uint32_t rom_version, uint32_t build_version, char *path)
{
if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
dev_type != 0 && build_version == 1)
path[0] = '\0';
else
snprintf(path, MAXPATHLEN, "%s%x/%s",
- FW_PATH, rom_version, PATCH_FILE);
+ FW_PATH, rom_version, TXT_PATCH_FILE);
+}
+
+static void get_file_name_of_patch_in_dfu_format(uint32_t dev_type,
+ uint32_t rom_version, uint32_t build_version, char *path)
+{
+ if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
+ dev_type != 0 && build_version == 1)
+ path[0] = '\0';
+ else
+ snprintf(path, MAXPATHLEN, "%s%s%x.dfu",
+ FW_PATH, DFU_PATCH_FILE, rom_version);
}
#define VERIFY_CRC 9
@@ -798,7 +889,8 @@ static int ath_ps_download(int fd)
uint32_t rom_version = 0;
uint32_t build_version = 0;
uint32_t dev_type = 0;
- char patch_file[PATH_MAX];
+ char patch_file_in_txt_fmt[PATH_MAX];
+ char patch_file_in_dfu_fmt[PATH_MAX];
char ps_file[PATH_MAX];
FILE *stream;
@@ -823,7 +915,10 @@ static int ath_ps_download(int fd)
}
get_ps_file_name(dev_type, rom_version, ps_file);
- get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+ get_file_name_of_patch_in_txt_format(dev_type, rom_version,
+ build_version, patch_file_in_txt_fmt);
+ get_file_name_of_patch_in_dfu_format(dev_type, rom_version,
+ build_version, patch_file_in_dfu_fmt);
stream = fopen(ps_file, "r");
if (!stream) {
@@ -844,20 +939,22 @@ static int ath_ps_download(int fd)
* It is not necessary that Patch file be available,
* continue with PS Operations if patch file is not available.
*/
- if (patch_file[0] == '\0')
- err = 0;
-
- stream = fopen(patch_file, "r");
- if (!stream)
- err = 0;
- else {
- patch_count = ps_patch_download(fd, stream);
+ stream = fopen(patch_file_in_dfu_fmt, "r");
+ if (patch_file_in_dfu_fmt[0] != '\0' && stream) {
+ patch_count = ps_patch_download_dfu(fd, stream);
fclose(stream);
-
- if (patch_count < 0) {
- err = -EILSEQ;
- goto download_cmplete;
+ } else if (patch_file_in_txt_fmt[0] != '\0') {
+ stream = fopen(patch_file_in_txt_fmt, "r");
+ if (stream) {
+ patch_count = ps_patch_download(fd, stream);
+ fclose(stream);
}
+ } else
+ err = 0;
+
+ if (patch_count < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
}
err = ps_config_download(fd, tag_count);
--
1.7.9.5
^ permalink raw reply related
* [PATCH] input: Implement idle timeout for fakehid
From: Jeff Hansen @ 2012-08-01 4:55 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 75 bytes --]
The batteries on my BD remote would die in a few days without this patch.
[-- Attachment #2: 0001-input-Implement-idle-timeout-for-fakehid.patch --]
[-- Type: text/x-patch, Size: 2949 bytes --]
>From a96f67cb6268e34e677e5d288f2c3b89acfca7fe Mon Sep 17 00:00:00 2001
From: Jeff Hansen <x@jeffhansen.com>
Date: Tue, 31 Jul 2012 22:45:23 -0600
Subject: [PATCH] input: Implement idle timeout for fakehid.
The batteries on my BD remote would die in a few days without this patch.
Signed-off-by: Jeff Hansen <x@jeffhansen.com>
---
input/device.c | 6 ++++++
input/device.h | 4 ++++
input/fakehid.c | 18 ++++++++++++++++++
3 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/input/device.c b/input/device.c
index 0ab63c0..ae11a13 100644
--- a/input/device.c
+++ b/input/device.c
@@ -609,6 +609,7 @@ static int hidp_add_connection(const struct input_device *idev,
fake->disconnect = fake_hid_disconnect;
fake->priv = fake_hid;
fake->idev = idev;
+ fake->timeout = iconn->timeout * 1000;
fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
if (fake == NULL)
err = -ENOMEM;
@@ -1257,3 +1258,8 @@ int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
return 0;
}
+
+void input_device_request_disconnect(const struct input_device *idev)
+{
+ device_request_disconnect(idev->device, NULL);
+}
diff --git a/input/device.h b/input/device.h
index 14c0f97..416cc9c 100644
--- a/input/device.h
+++ b/input/device.h
@@ -40,6 +40,8 @@ struct fake_input {
int (*disconnect) (struct input_conn *iconn);
void *priv;
const struct input_device *idev;
+ guint idle_timeout;
+ uint32_t timeout;
};
int fake_input_register(DBusConnection *conn, struct btd_device *device,
@@ -54,3 +56,5 @@ int input_device_unregister(const char *path, const char *uuid);
int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
GIOChannel *io);
int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
+
+void input_device_request_disconnect(const struct input_device *idev);
diff --git a/input/fakehid.c b/input/fakehid.c
index b809870..0407ae3 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -208,6 +208,13 @@ error:
return -1;
}
+static gboolean ps3remote_idle(gpointer data)
+{
+ struct fake_input *fake = data;
+ input_device_request_disconnect(fake->idev);
+ return FALSE;
+}
+
static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
@@ -218,6 +225,13 @@ static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
char buff[50];
int fd;
+ if (fake->idle_timeout) {
+ g_source_remove(fake->idle_timeout);
+ fake->idle_timeout = 0;
+ }
+ if (fake->timeout)
+ fake->idle_timeout = g_timeout_add(fake->timeout, ps3remote_idle, fake);
+
if (cond & G_IO_NVAL)
return FALSE;
@@ -337,6 +351,10 @@ static gboolean fake_hid_common_connect(struct fake_input *fake, GError **err)
static int fake_hid_common_disconnect(struct fake_input *fake)
{
+ if (fake->idle_timeout) {
+ g_source_remove(fake->idle_timeout);
+ fake->idle_timeout = 0;
+ }
return 0;
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 1/1] build: Remove gstreamer pkg config warning
From: chanyeol.park @ 2012-08-01 5:00 UTC (permalink / raw)
To: linux-bluetooth
From: Chan-yeol Park <chanyeol.park@samsung.com>
GSTREAMER is not mandatory option when bluez build.
---
acinclude.m4 | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/acinclude.m4 b/acinclude.m4
index 6505ad3..6e3eb83 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -106,8 +106,9 @@ AC_DEFUN([AC_PATH_GLIB], [
])
AC_DEFUN([AC_PATH_GSTREAMER], [
- PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10, gstreamer_found=yes,
- AC_MSG_WARN(GStreamer library version 0.10.30 or later is required);gstreamer_found=no)
+ PKG_CHECK_MODULES(GSTREAMER,
+ gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10,
+ gstreamer_found=yes, gstreamer_found=no)
AC_SUBST(GSTREAMER_CFLAGS)
AC_SUBST(GSTREAMER_LIBS)
GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 1/1] build: Remove gstreamer pkg config warning
From: Marcel Holtmann @ 2012-08-01 5:01 UTC (permalink / raw)
To: chanyeol.park; +Cc: linux-bluetooth
In-Reply-To: <1343797204-1202-1-git-send-email-chanyeol.park@samsung.com>
Hi Chan-yeol,
> From: Chan-yeol Park <chanyeol.park@samsung.com>
>
> GSTREAMER is not mandatory option when bluez build.
> ---
> acinclude.m4 | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/acinclude.m4 b/acinclude.m4
> index 6505ad3..6e3eb83 100644
> --- a/acinclude.m4
> +++ b/acinclude.m4
> @@ -106,8 +106,9 @@ AC_DEFUN([AC_PATH_GLIB], [
> ])
>
> AC_DEFUN([AC_PATH_GSTREAMER], [
> - PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10, gstreamer_found=yes,
> - AC_MSG_WARN(GStreamer library version 0.10.30 or later is required);gstreamer_found=no)
> + PKG_CHECK_MODULES(GSTREAMER,
> + gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10,
> + gstreamer_found=yes, gstreamer_found=no)
> AC_SUBST(GSTREAMER_CFLAGS)
> AC_SUBST(GSTREAMER_LIBS)
> GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
as discussed during the BlueZ meeting, we will be removing GStreamer
support for BlueZ and submit it GStreamer. The prerequisite of the
standalone SBC library has been released yesterday.
So NAK on this patch since soon it will not be needed anymore.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 1/1] build: Remove gstreamer pkg config warning
From: Chanyeol Park @ 2012-08-01 5:14 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1343797305.1803.80.camel@aeonflux>
Hi Marcel
On 2012년 08월 01일 14:01, Marcel Holtmann wrote:
>
> as discussed during the BlueZ meeting, we will be removing GStreamer
> support for BlueZ and submit it GStreamer. The prerequisite of the
> standalone SBC library has been released yesterday.
>
> So NAK on this patch since soon it will not be needed anymore.
>
> Regards
>
> Marcel
Understood.
Thanks for explanation.
Yesterday I saw your SBC announce.
If I want to send a patch about SBC,
could we use the same account(linux-bluetooth account)?
As far as I expect,
it's not easy to recognize patches on the same account.
Regards
Chanyeol
^ permalink raw reply
* [PATCH SBC 1/1] COPYING.LIB: Remove unnecessary whitespace from empty line
From: chanyeol.park @ 2012-08-01 6:27 UTC (permalink / raw)
To: linux-bluetooth
From: Chan-yeol Park <chanyeol.park@samsung.com>
---
COPYING.LIB | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/COPYING.LIB b/COPYING.LIB
index 1f7c8cc..148d531 100644
--- a/COPYING.LIB
+++ b/COPYING.LIB
@@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
-
+
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH SBC 1/1] COPYING.LIB: Remove unnecessary whitespace from empty line
From: Marcel Holtmann @ 2012-08-01 6:29 UTC (permalink / raw)
To: chanyeol.park; +Cc: linux-bluetooth
In-Reply-To: <1343802455-2760-1-git-send-email-chanyeol.park@samsung.com>
Hi Chanyeol,
> COPYING.LIB | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/COPYING.LIB b/COPYING.LIB
> index 1f7c8cc..148d531 100644
> --- a/COPYING.LIB
> +++ b/COPYING.LIB
> @@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
> on the Library (independent of the use of the Library in a tool for
> writing it). Whether that is true depends on what the Library does
> and what the program that uses the Library does.
> -
> +
> 1. You may copy and distribute verbatim copies of the Library's
> complete source code as you receive it, in any medium, provided that
> you conspicuously and appropriately publish on each copy an
this file is a literal copy of what the FSF provides. I rather not do
some whitespace changes here and keep it close to the original. And it
is the exact copy we have in BlueZ and also ELL.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH v2 0/9] Add GATT Client Battery Service
From: Chen Ganir @ 2012-08-01 6:40 UTC (permalink / raw)
To: Chen Ganir, linux-bluetooth
In-Reply-To: <1343194947-13659-1-git-send-email-chen.ganir@ti.com>
On 07/25/2012 08:42 AM, Chen Ganir wrote:
> Add suupport for LE GATT Client Battery Service.
>
> This plugin adds battery list to the btd_device, exposes DBUS API to list the
> device batteries, and allows querying for battery information. In addition this
> patch allows getting notifications for battery level changes.
>
> Look at doc/device-api.txt and doc/battery-api.txt for more information.
>
> This is version 2 of this patch set, rebased on top of the latest sources and
> fixes some issues found during testing and in the ML comments.
>
> Chen Ganir (9):
> Battery: Add Battery Service GATT Client
> Battery: Add connection logic
> Battery: Discover Characteristic Descriptors
> Battery: Get Battery ID
> Battery: Add Battery list to btd_device
> Battery: Add Battery D-BUS API
> Battery: Read Battery level characteristic
> Battery: Add support for notifications
> Battery: Emit property changed on first read
>
> Makefile.am | 10 +-
> doc/battery-api.txt | 38 +++
> doc/device-api.txt | 5 +
> profiles/batterystate/batterystate.c | 518 ++++++++++++++++++++++++++++++++++
> profiles/batterystate/batterystate.h | 24 ++
> profiles/batterystate/main.c | 67 +++++
> profiles/batterystate/manager.c | 93 ++++++
> profiles/batterystate/manager.h | 24 ++
> src/device.c | 66 +++++
> src/device.h | 3 +
> 10 files changed, 846 insertions(+), 2 deletions(-)
> create mode 100644 doc/battery-api.txt
> create mode 100644 profiles/batterystate/batterystate.c
> create mode 100644 profiles/batterystate/batterystate.h
> create mode 100644 profiles/batterystate/main.c
> create mode 100644 profiles/batterystate/manager.c
> create mode 100644 profiles/batterystate/manager.h
>
Ping anyone ? Did anyone get to review this ?
Thanks,
Chen Ganir
^ permalink raw reply
* [PATCH v16 00/14] Add org.bluez.Telephony interface
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
Hello,
This set of patches replaces telephony drivers for HeadSet, HandsFree,
DUN and SAP Profiles by a new DBus interface (org.bluez.Telephony).
This will simplify BlueZ code by focusing on the Bluetooth
communication part and by letting the external application (i.e. oFono)
take charge of the Telephony tasks (AT parsing and modem specific code,
which can be removed from BlueZ code). So, it becomes simpler, easier
to maintain and debug.
External applications, which should implement AT parsing and telephony
part of HeadSet or HandsFree Profiles, will have to register a telephony
agent using this new interface.
Any comments appreciated.
Regards
PS: Since latest Patch set:
- patch 1 and 2: remove UUID property from NewConnection method of TelephonyAgent
- patch 2:
- rename headset_slc_complete() to headset_profile_connection_complete()
- rename telephony_get_ready_state() to telephony_is_ready()
- change return type of parse_properties() to gboolean
- ref/unref GIOChannel used in telephony_device structure
- fix parameter type of hs_dev_disconnect_cb()
- manage dbus error first in hs_newconnection_reply()
- use sdp_uuid_cmp() instead of sdp_uuid16_cmp() in get_record_cb()
- if sdp service search is in progress, cancel it in telephony_device_disconnect()
- merge register_interface() into telephony_adapter_init()
- merge unregister_interface() into telephony_adapter_exit()
- set connecting_uuid to NULL when going to disconnected state in headset_set_state()
- patch 3: remove rfcomm in headset structure as it is now managed in telephony.c
this imply to unref tmp_rfcomm after call of telephony_device_connecting()
- patch 9:
- rename connecting_path to connecting_transport_path in headset structure
- set connecting_transport_path to NULL when going to disconnected state in
headset_set_state()
- patch 10:
- rename rfcomm to tmp_rfcomm in gateway structure as it is now managed
in telephony.c
this imply to unref tmp_rfcomm after call of telephony_device_connecting()
- rename connecting_path to connecting_transport_path in gateway structure
- set connecting_uuid and connecting_transport_path to NULL when going to
disconnected state in gateway_close()
- fix parameter type of ag_dev_disconnect_cb()
- manage dbus error first in ag_newconnection_reply()
- patch 11:
- rename rfcomm to tmp_rfcomm in connecting_device structure
this tmp_rfcomm should be unrefed after call of telephony_device_connecting()
- fix parameter type of client_dev_disconnect_cb()
- manage dbus error first in client_newconnection_reply()
Frédéric Danis (14):
doc: Add telephony interface documents
audio: Move telephony drivers to D-Bus interface
audio: Simplify org.bluez.Headset
audio: Remove dummy telephony driver
audio: Remove maemo5 telephony driver
audio: Remove maemo6 telephony driver
audio: Remove oFono telephony driver
audio: Move HFP/HSP AG servers to telephony.c
audio: Send transport path to telephony agent
audio: Move HFP HF server to telephony.c
audio: Add DUN GW to org.bluez.Telephony
audio: Add SAP GW to org.bluez.Telephony
adapter: Add API to get fast connectable mode
audio: Add fast connectable to telephony interface
Makefile.am | 19 +-
audio/audio.conf | 7 -
audio/device.h | 1 +
audio/gateway.c | 436 +++-----
audio/gateway.h | 8 +
audio/headset.c | 1844 ++++-----------------------------
audio/headset.h | 16 +-
audio/manager.c | 628 +-----------
audio/manager.h | 4 -
audio/media.c | 34 +
audio/telephony-dummy.c | 447 --------
audio/telephony-maemo5.c | 2105 --------------------------------------
audio/telephony-maemo6.c | 2200 ----------------------------------------
audio/telephony-ofono.c | 1637 ------------------------------
audio/telephony.c | 1634 +++++++++++++++++++++++++++++
audio/telephony.h | 205 +---
audio/transport.c | 117 ++-
doc/assigned-numbers.txt | 2 +
doc/audio-api.txt | 232 ++---
doc/audio-telephony-design.txt | 106 ++
doc/hfp-api.txt | 46 -
doc/media-api.txt | 19 +-
src/adapter.c | 15 +-
src/adapter.h | 1 +
24 files changed, 2349 insertions(+), 9414 deletions(-)
delete mode 100644 audio/telephony-dummy.c
delete mode 100644 audio/telephony-maemo5.c
delete mode 100644 audio/telephony-maemo6.c
delete mode 100644 audio/telephony-ofono.c
create mode 100644 audio/telephony.c
create mode 100644 doc/audio-telephony-design.txt
--
1.7.9.5
^ permalink raw reply
* [PATCH v16 01/14] doc: Add telephony interface documents
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1343812131-19395-1-git-send-email-frederic.danis@linux.intel.com>
---
Makefile.am | 2 +-
doc/assigned-numbers.txt | 1 +
doc/audio-api.txt | 87 +++++++++++++++++++++++++++++++++
doc/audio-telephony-design.txt | 106 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 195 insertions(+), 1 deletion(-)
create mode 100644 doc/audio-telephony-design.txt
diff --git a/Makefile.am b/Makefile.am
index 45a811c..1aa302c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -381,7 +381,7 @@ EXTRA_DIST += doc/manager-api.txt \
doc/network-api.txt doc/input-api.txt doc/audio-api.txt \
doc/control-api.txt doc/hfp-api.txt doc/health-api.txt \
doc/sap-api.txt doc/media-api.txt doc/assigned-numbers.txt \
- doc/supported-features.txt
+ doc/supported-features.txt doc/audio-telephony-design.txt
AM_YFLAGS = -d
diff --git a/doc/assigned-numbers.txt b/doc/assigned-numbers.txt
index cda934c..120d7ea 100644
--- a/doc/assigned-numbers.txt
+++ b/doc/assigned-numbers.txt
@@ -8,6 +8,7 @@ avoid conflicts.
Profile Channel
-----------------------
DUN 1
+HSP HS 6
HFP HF 7
OPP 9
FTP 10
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index ca430fc..c620a7d 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -423,3 +423,90 @@ properties boolean Connected [readonly]
uint16 MicrophoneGain [readonly]
The speaker gain when available.
+
+
+Telephony hierarchy
+===================
+
+Service org.bluez
+Interface org.bluez.Telephony
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods void RegisterAgent(object path, dict properties)
+
+ Register a TelephonyAgent to sender, the sender can
+ register as many agents as it likes.
+ Object path should be unique for an agent and a UUID.
+
+ Note: If the sender disconnects its agents are
+ automatically unregistered.
+
+ possible properties:
+
+ string UUID:
+
+ UUID of the profile which the agent is
+ for.
+
+ uint16 Version:
+
+ Version of the profile which the agent
+ implements.
+
+ uint16 Features:
+
+ Agent supported features as defined in
+ profile spec e.g. HFP.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void UnregisterAgent(object path)
+
+ Unregister sender agent.
+
+TelephonyAgent hierarchy
+========================
+
+Service unique name
+Interface org.bluez.TelephonyAgent
+Object path freely definable
+
+Methods void NewConnection(filedescriptor fd, dict properties)
+
+ This method gets called whenever a new connection
+ has been established. This method assumes that D-Bus
+ daemon with file descriptor passing capability is
+ being used.
+
+ The agent should only return successfully once the
+ establishment of the service level connection (SLC)
+ has been completed. In the case of Handsfree this
+ means that BRSF exchange has been performed and
+ necessary initialization has been done.
+
+ possible properties:
+
+ object Device:
+
+ BlueZ remote device object.
+
+ uint16 Version:
+
+ Remote profile version.
+
+ uint16 Features:
+
+ Remote profile features.
+
+ object Transport:
+
+ Optional. MediaTransport object path.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void Release()
+
+ This method gets called whenever the service daemon
+ unregisters the agent or whenever the Adapter where
+ the TelephonyAgent registers itself is removed.
diff --git a/doc/audio-telephony-design.txt b/doc/audio-telephony-design.txt
new file mode 100644
index 0000000..a5936f6
--- /dev/null
+++ b/doc/audio-telephony-design.txt
@@ -0,0 +1,106 @@
+The org.bluez.Telephony interface will simplify BlueZ code by focusing on
+the Bluetooth communication part and by letting the external application (i.e.
+oFono) take charge of the Telephony tasks (AT parsing and modem specific code).
+So, it becomes simpler, easier to maintain and debug.
+
+External applications, which should implement AT parsing and telephony
+part of HeadSet or HandsFree Profiles, will have to register an
+org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
+for the profile and a RFCOMM server listening for incoming connection.
+
+When a new device is connected, NewConnection method of TelephonyAgent is
+called. The telephony agent should reply to it after proper communication
+establishment (directly for HSP or after SLC setup completes for HFP).
+
+Interaction with the audio component (i.e. PulseAudio) will be done through the
+MediaTransport object (passed to telephony agent during NewConnection call).
+
+Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
+and audio component (PulseAudio):
+
+ .....> Bluetooth communication between headset and phone
+ -----> Dbus messages and signals
+
+SCO connection - AG initiated
+
+ PulseAudio BlueZ HF
+ | | |
+ | transport acquire | |
+ |------------------------>| |
+ | | connect SCO |
+ | |<.............>|
+ | return SCO fd | |
+ |<------------------------| |
+ | | |
+
+SCO connection - HF initiated
+
+ PulseAudio BlueZ HF
+ | | |
+ | | connect SCO |
+ | |<.............>|
+ | state changed signal | |
+ |<------------------------| |
+ | | |
+ | transport acquire | |
+ |------------------------>| |
+ | | |
+ | return SCO fd | |
+ |<------------------------| |
+ | | |
+
+AT+NREC
+
+ HF oFono BlueZ PulseAudio
+ | AT+NREC | | |
+ |................>| | |
+ | | SetProperty | |
+ | |-------------->| |
+ | | | property changed |
+ | | | signal |
+ | | |----------------->|
+
+
++BSIR
+
+ HF oFono BlueZ PulseAudio app
+ | | | | |
+ | | | |<------------|
+ | | | SetProperty | |
+ | | |<--------------| |
+ | | | | |
+ | | property changed signal | |
+ | |<------------*-------------->| |
+ | +BSIR:x | | | |
+ |<............| | | |
+ | | | | |
+
+
+AT+VGS,AT+VGM
+
+ HF oFono BlueZ PulseAudio app
+ | | | | |
+ | AT+VGS=xx | | | |
+ |............>| | | |
+ | | SetProperty | | |
+ | |------------>| | |
+ | | | | |
+ | | property changed signal | |
+ | |<------------*-------------->| |
+ | | | |------------>|
+ | | | | |
+
+
++VGS,+VGM
+
+ HF oFono BlueZ PulseAudio app
+ | | | | |
+ | | | |<------------|
+ | | | SetProperty | |
+ | | |<--------------| |
+ | | | | |
+ | | property changed signal | |
+ | |<------------*-------------->| |
+ | +VGS:xx | | | |
+ |<............| | |------------>|
+ | | | | |
--
1.7.9.5
^ permalink raw reply related
* [PATCH v16 02/14] audio: Move telephony drivers to D-Bus interface
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1343812131-19395-1-git-send-email-frederic.danis@linux.intel.com>
Add a D-Bus interface called org.bluez.Telephony to replace current
telephony drivers for HeadSet/HandsFree Profiles.
This will simplify BlueZ code by focusing on the Bluetooth
communication part and by letting the external application (i.e. oFono)
take charge of the Telephony tasks (AT parsing and modem specific code,
which can be removed from BlueZ code). So, it becomes simpler, easier
to maintain and debug.
Telephony application will have to register an agent using this new
interface.
Remove functions related to AT parsing from audio/headset.c.
Remove current telephony drivers (dummy, maemo 5, maemo 6 and oFono)
from the build as they have been replaced and are no longer needed.
---
Makefile.am | 13 +-
audio/headset.c | 694 +++++------------------------------------------------
audio/headset.h | 3 +
audio/manager.c | 13 +-
audio/telephony.c | 633 ++++++++++++++++++++++++++++++++++++++++++++++++
audio/telephony.h | 35 +--
6 files changed, 719 insertions(+), 672 deletions(-)
create mode 100644 audio/telephony.c
diff --git a/Makefile.am b/Makefile.am
index 1aa302c..2a8b903 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -148,14 +148,8 @@ builtin_sources += audio/main.c \
audio/avdtp.h audio/avdtp.c \
audio/media.h audio/media.c \
audio/transport.h audio/transport.c \
- audio/telephony.h audio/a2dp-codecs.h
-builtin_nodist += audio/telephony.c
-
-noinst_LIBRARIES += audio/libtelephony.a
-
-audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
- audio/telephony-maemo5.c audio/telephony-ofono.c \
- audio/telephony-maemo6.c
+ audio/telephony.h audio/telephony.c \
+ audio/a2dp-codecs.h
endif
if SAPPLUGIN
@@ -428,9 +422,6 @@ MAINTAINERCLEANFILES = Makefile.in \
src/builtin.h: src/genbuiltin $(builtin_sources)
$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
-audio/telephony.c: audio/@TELEPHONY_DRIVER@
- $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
-
profiles/sap/sap.c: profiles/sap/@SAP_DRIVER@
$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
diff --git a/audio/headset.c b/audio/headset.c
index 1014c59..668e9f1 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -42,11 +42,16 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus.h>
+#include "btio.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
#include "log.h"
#include "device.h"
#include "manager.h"
@@ -54,10 +59,7 @@
#include "telephony.h"
#include "headset.h"
#include "sdp-client.h"
-#include "btio.h"
#include "dbus-common.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
#define DC_TIMEOUT 3
@@ -69,8 +71,6 @@
#define HEADSET_GAIN_MICROPHONE 'M'
static struct {
- gboolean telephony_ready; /* Telephony plugin initialized */
- uint32_t features; /* HFP AG features */
const struct indicator *indicators; /* Available HFP indicators */
int er_mode; /* Event reporting mode */
int er_ind; /* Event reporting for indicators */
@@ -80,8 +80,6 @@ static struct {
guint ring_timer; /* For incoming call indication */
const char *chld; /* Response to AT+CHLD=? */
} ag = {
- .telephony_ready = FALSE,
- .features = 0,
.er_mode = 3,
.er_ind = 0,
.rh = BTRH_NOT_SUPPORTED,
@@ -132,9 +130,7 @@ struct pending_connect {
};
struct headset_slc {
- char buf[BUF_SIZE];
- int data_start;
- int data_length;
+ struct telephony_device *tel_dev;
gboolean cli_active;
gboolean cme_enabled;
@@ -158,6 +154,7 @@ struct headset {
GIOChannel *rfcomm;
GIOChannel *tmp_rfcomm;
+ const char *connecting_uuid;
GIOChannel *sco;
guint sco_id;
@@ -235,40 +232,6 @@ static void print_ag_features(uint32_t features)
g_free(str);
}
-static void print_hf_features(uint32_t features)
-{
- GString *gstr;
- char *str;
-
- if (features == 0) {
- DBG("HFP HF features: (none)");
- return;
- }
-
- gstr = g_string_new("HFP HF features: ");
-
- if (features & HF_FEATURE_EC_ANDOR_NR)
- g_string_append(gstr, "\"EC and/or NR function\" ");
- if (features & HF_FEATURE_CALL_WAITING_AND_3WAY)
- g_string_append(gstr, "\"Call waiting and 3-way calling\" ");
- if (features & HF_FEATURE_CLI_PRESENTATION)
- g_string_append(gstr, "\"CLI presentation capability\" ");
- if (features & HF_FEATURE_VOICE_RECOGNITION)
- g_string_append(gstr, "\"Voice recognition activation\" ");
- if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL)
- g_string_append(gstr, "\"Remote volume control\" ");
- if (features & HF_FEATURE_ENHANCED_CALL_STATUS)
- g_string_append(gstr, "\"Enhanced call status\" ");
- if (features & HF_FEATURE_ENHANCED_CALL_CONTROL)
- g_string_append(gstr, "\"Enhanced call control\" ");
-
- str = g_string_free(gstr, FALSE);
-
- DBG("%s", str);
-
- g_free(str);
-}
-
static const char *state2str(headset_state_t state)
{
switch (state) {
@@ -332,97 +295,6 @@ static int __attribute__((format(printf, 2, 3)))
return ret;
}
-static int supported_features(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- int err;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- slc->hf_features = strtoul(&buf[8], NULL, 10);
-
- print_hf_features(slc->hf_features);
-
- err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
- if (err < 0)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-static char *indicator_ranges(const struct indicator *indicators)
-{
- int i;
- GString *gstr;
-
- gstr = g_string_new("\r\n+CIND: ");
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (i == 0)
- g_string_append_printf(gstr, "(\"%s\",(%s))",
- indicators[i].desc,
- indicators[i].range);
- else
- g_string_append_printf(gstr, ",(\"%s\",(%s))",
- indicators[i].desc,
- indicators[i].range);
- }
-
- g_string_append(gstr, "\r\n");
-
- return g_string_free(gstr, FALSE);
-}
-
-static char *indicator_values(const struct indicator *indicators)
-{
- int i;
- GString *gstr;
-
- gstr = g_string_new("\r\n+CIND: ");
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (i == 0)
- g_string_append_printf(gstr, "%d", indicators[i].val);
- else
- g_string_append_printf(gstr, ",%d", indicators[i].val);
- }
-
- g_string_append(gstr, "\r\n");
-
- return g_string_free(gstr, FALSE);
-}
-
-static int report_indicators(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- int err;
- char *str;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- if (ag.indicators == NULL) {
- error("HFP AG indicators not initialized");
- return headset_send(hs, "\r\nERROR\r\n");
- }
-
- if (buf[7] == '=')
- str = indicator_ranges(ag.indicators);
- else
- str = indicator_values(ag.indicators);
-
- err = headset_send(hs, "%s", str);
-
- g_free(str);
-
- if (err < 0)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -655,12 +527,12 @@ static int hfp_cmp(struct headset *hs)
return -1;
}
-static void hfp_slc_complete(struct audio_device *dev)
+void headset_profile_connection_complete(struct audio_device *dev)
{
struct headset *hs = dev->headset;
struct pending_connect *p = hs->pending;
- DBG("HFP Service Level Connection established");
+ DBG("Profile connection established");
headset_set_state(dev, HEADSET_STATE_CONNECTED);
@@ -707,6 +579,7 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
struct audio_device *device = telephony_device;
struct headset *hs = device->headset;
struct headset_slc *slc = hs->slc;
+ uint32_t ag_features;
int ret;
if (err != CME_ERROR_NONE)
@@ -719,74 +592,12 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
if (hs->state != HEADSET_STATE_CONNECTING)
return 0;
+ ag_features = telephony_get_ag_features();
if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
- ag.features & AG_FEATURE_THREE_WAY_CALLING)
+ ag_features & AG_FEATURE_THREE_WAY_CALLING)
return 0;
- hfp_slc_complete(device);
-
- return 0;
-}
-
-static int event_reporting(struct audio_device *dev, const char *buf)
-{
- char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */
-
- if (strlen(buf) < 13)
- return -EINVAL;
-
- tokens = g_strsplit(&buf[8], ",", 5);
- if (g_strv_length(tokens) < 4) {
- g_strfreev(tokens);
- return -EINVAL;
- }
-
- ag.er_mode = atoi(tokens[0]);
- ag.er_ind = atoi(tokens[3]);
-
- g_strfreev(tokens);
- tokens = NULL;
-
- DBG("Event reporting (CMER): mode=%d, ind=%d",
- ag.er_mode, ag.er_ind);
-
- switch (ag.er_ind) {
- case 0:
- case 1:
- telephony_event_reporting_req(dev, ag.er_ind);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int call_hold(struct audio_device *dev, const char *buf)
-{
- struct headset *hs = dev->headset;
- int err;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] != '?') {
- telephony_call_hold_req(dev, &buf[8]);
- return 0;
- }
-
- err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
- if (err < 0)
- return err;
-
- err = headset_send(hs, "\r\nOK\r\n");
- if (err < 0)
- return err;
-
- if (hs->state != HEADSET_STATE_CONNECTING)
- return 0;
-
- hfp_slc_complete(dev);
+ headset_profile_connection_complete(device);
return 0;
}
@@ -796,47 +607,11 @@ int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
return telephony_generic_rsp(telephony_device, err);
}
-static int key_press(struct audio_device *device, const char *buf)
-{
- if (strlen(buf) < 9)
- return -EINVAL;
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, "AnswerRequested",
- DBUS_TYPE_INVALID);
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- telephony_key_press_req(device, &buf[8]);
-
- return 0;
-}
-
int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int answer_call(struct audio_device *device, const char *buf)
-{
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- if (ag.number) {
- g_free(ag.number);
- ag.number = NULL;
- }
-
- telephony_answer_call_req(device);
-
- return 0;
-}
-
int telephony_terminate_call_rsp(void *telephony_device,
cme_error_t err)
{
@@ -853,99 +628,21 @@ int telephony_terminate_call_rsp(void *telephony_device,
return headset_send(hs, "\r\nOK\r\n");
}
-static int terminate_call(struct audio_device *device, const char *buf)
-{
- if (ag.number) {
- g_free(ag.number);
- ag.number = NULL;
- }
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- telephony_terminate_call_req(device);
-
- return 0;
-}
-
-static int cli_notification(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int response_and_hold(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- if (ag.rh == BTRH_NOT_SUPPORTED)
- return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED);
-
- if (buf[7] == '=') {
- telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);
- return 0;
- }
-
- if (ag.rh >= 0)
- headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int last_dialed_number(struct audio_device *device, const char *buf)
-{
- telephony_last_dialed_number_req(device);
-
- return 0;
-}
-
int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int dial_number(struct audio_device *device, const char *buf)
-{
- char number[BUF_SIZE];
- size_t buf_len;
-
- buf_len = strlen(buf);
-
- if (buf[buf_len - 1] != ';') {
- DBG("Rejecting non-voice call dial request");
- return -EINVAL;
- }
-
- memset(number, 0, sizeof(number));
- strncpy(number, &buf[3], buf_len - 4);
-
- telephony_dial_number_req(device, number);
-
- return 0;
-}
-
static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
{
struct headset *hs = device->headset;
@@ -993,111 +690,21 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
return 0;
}
-static int signal_gain_setting(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- dbus_uint16_t gain;
- int err;
-
- if (strlen(buf) < 8) {
- error("Too short string for Gain setting");
- return -EINVAL;
- }
-
- gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
-
- err = headset_set_gain(device, gain, buf[5]);
- if (err < 0 && err != -EALREADY)
- return err;
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int dtmf_tone(struct audio_device *device, const char *buf)
-{
- char tone;
-
- if (strlen(buf) < 8) {
- error("Too short string for DTMF tone");
- return -EINVAL;
- }
-
- tone = buf[7];
- if (tone >= '#' && tone <= 'D')
- telephony_transmit_dtmf_req(device, tone);
- else
- return -EINVAL;
-
- return 0;
-}
-
int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int subscriber_number(struct audio_device *device, const char *buf)
-{
- telephony_subscriber_number_req(device);
-
- return 0;
-}
-
int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
}
-static int list_current_calls(struct audio_device *device, const char *buf)
-{
- telephony_list_current_calls_req(device);
-
- return 0;
-}
-
-static int extended_errors(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '1') {
- slc->cme_enabled = TRUE;
- DBG("CME errors enabled for headset %p", hs);
- } else {
- slc->cme_enabled = FALSE;
- DBG("CME errors disabled for headset %p", hs);
- }
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-static int call_waiting_notify(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '1') {
- slc->cwa_enabled = TRUE;
- DBG("Call waiting notification enabled for headset %p", hs);
- } else {
- slc->cwa_enabled = FALSE;
- DBG("Call waiting notification disabled for headset %p", hs);
- }
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
{
return telephony_generic_rsp(telephony_device, err);
@@ -1145,108 +752,6 @@ int telephony_operator_selection_ind(int mode, const char *oper)
return 0;
}
-static int operator_selection(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
-
- if (strlen(buf) < 8)
- return -EINVAL;
-
- switch (buf[7]) {
- case '?':
- telephony_operator_selection_req(device);
- break;
- case '=':
- return headset_send(hs, "\r\nOK\r\n");
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int nr_and_ec(struct audio_device *device, const char *buf)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '0')
- slc->nrec_req = FALSE;
- else
- slc->nrec_req = TRUE;
-
- telephony_nr_and_ec_req(device, slc->nrec_req);
-
- return 0;
-}
-
-static int voice_dial(struct audio_device *device, const char *buf)
-{
- gboolean enable;
-
- if (strlen(buf) < 9)
- return -EINVAL;
-
- if (buf[8] == '0')
- enable = FALSE;
- else
- enable = TRUE;
-
- telephony_voice_dial_req(device, enable);
-
- return 0;
-}
-
-static int apple_command(struct audio_device *device, const char *buf)
-{
- DBG("Got Apple command: %s", buf);
-
- return telephony_generic_rsp(device, CME_ERROR_NONE);
-}
-
-static struct event event_callbacks[] = {
- { "ATA", answer_call },
- { "ATD", dial_number },
- { "AT+VG", signal_gain_setting },
- { "AT+BRSF", supported_features },
- { "AT+CIND", report_indicators },
- { "AT+CMER", event_reporting },
- { "AT+CHLD", call_hold },
- { "AT+CHUP", terminate_call },
- { "AT+CKPD", key_press },
- { "AT+CLIP", cli_notification },
- { "AT+BTRH", response_and_hold },
- { "AT+BLDN", last_dialed_number },
- { "AT+VTS", dtmf_tone },
- { "AT+CNUM", subscriber_number },
- { "AT+CLCC", list_current_calls },
- { "AT+CMEE", extended_errors },
- { "AT+CCWA", call_waiting_notify },
- { "AT+COPS", operator_selection },
- { "AT+NREC", nr_and_ec },
- { "AT+BVRA", voice_dial },
- { "AT+XAPL", apple_command },
- { "AT+IPHONEACCEV", apple_command },
- { 0 }
-};
-
-static int handle_event(struct audio_device *device, const char *buf)
-{
- struct event *ev;
-
- DBG("Received %s", buf);
-
- for (ev = event_callbacks; ev->cmd; ev++) {
- if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
- return ev->callback(device, buf);
- }
-
- return -EINVAL;
-}
-
static void close_sco(struct audio_device *device)
{
struct headset *hs = device->headset;
@@ -1265,95 +770,6 @@ static void close_sco(struct audio_device *device)
}
}
-static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
- struct audio_device *device)
-{
- struct headset *hs;
- struct headset_slc *slc;
- unsigned char buf[BUF_SIZE];
- ssize_t bytes_read;
- size_t free_space;
- int fd;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- hs = device->headset;
- slc = hs->slc;
-
- if (cond & (G_IO_ERR | G_IO_HUP)) {
- DBG("ERR or HUP on RFCOMM socket");
- goto failed;
- }
-
- fd = g_io_channel_unix_get_fd(chan);
-
- bytes_read = read(fd, buf, sizeof(buf) - 1);
- if (bytes_read < 0)
- return TRUE;
-
- free_space = sizeof(slc->buf) - slc->data_start -
- slc->data_length - 1;
-
- if (free_space < (size_t) bytes_read) {
- /* Very likely that the HS is sending us garbage so
- * just ignore the data and disconnect */
- error("Too much data to fit incoming buffer");
- goto failed;
- }
-
- memcpy(&slc->buf[slc->data_start], buf, bytes_read);
- slc->data_length += bytes_read;
-
- /* Make sure the data is null terminated so we can use string
- * functions */
- slc->buf[slc->data_start + slc->data_length] = '\0';
-
- while (slc->data_length > 0) {
- char *cr;
- int err;
- off_t cmd_len;
-
- cr = strchr(&slc->buf[slc->data_start], '\r');
- if (!cr)
- break;
-
- cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
- *cr = '\0';
-
- if (cmd_len > 1)
- err = handle_event(device, &slc->buf[slc->data_start]);
- else
- /* Silently skip empty commands */
- err = 0;
-
- if (err == -EINVAL) {
- error("Badly formated or unrecognized command: %s",
- &slc->buf[slc->data_start]);
- err = telephony_generic_rsp(device,
- CME_ERROR_NOT_SUPPORTED);
- if (err < 0)
- goto failed;
- } else if (err < 0)
- error("Error handling command %s: %s (%d)",
- &slc->buf[slc->data_start],
- strerror(-err), -err);
-
- slc->data_start += cmd_len;
- slc->data_length -= cmd_len;
-
- if (!slc->data_length)
- slc->data_start = 0;
- }
-
- return TRUE;
-
-failed:
- headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
- return FALSE;
-}
-
static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
struct audio_device *device)
{
@@ -1372,21 +788,33 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
struct audio_device *dev = user_data;
struct headset *hs = dev->headset;
+ struct btd_device *btd_dev = dev->btd_dev;
+ struct btd_adapter *adapter;
struct pending_connect *p = hs->pending;
char hs_address[18];
+ struct telephony_device *tel_dev;
if (err) {
error("%s", err->message);
goto failed;
}
+ adapter = device_get_adapter(btd_dev);
+
/* For HFP telephony isn't ready just disconnect */
- if (hs->hfp_active && !ag.telephony_ready) {
+ if (hs->hfp_active && !telephony_is_ready(adapter)) {
error("Unable to accept HFP connection since the telephony "
"subsystem isn't initialized");
goto failed;
}
+ tel_dev = telephony_device_connecting(chan, btd_dev, dev,
+ hs->connecting_uuid);
+ if (tel_dev == NULL)
+ goto failed;
+
+ hs->connecting_uuid = NULL;
+
hs->rfcomm = hs->tmp_rfcomm;
hs->tmp_rfcomm = NULL;
@@ -1397,42 +825,21 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
else
hs->auto_dc = FALSE;
- g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, dev);
-
DBG("%s: Connected to %s", dev->path, hs_address);
hs->slc = g_new0(struct headset_slc, 1);
+ hs->slc->tel_dev = tel_dev;
hs->slc->sp_gain = 15;
hs->slc->mic_gain = 15;
hs->slc->nrec = TRUE;
- /* In HFP mode wait for Service Level Connection */
- if (hs->hfp_active)
- return;
-
- headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
- if (p && p->target_state == HEADSET_STATE_PLAYING) {
- p->err = sco_connect(dev, NULL, NULL, NULL);
- if (p->err < 0)
- goto failed;
- return;
- }
-
- if (p && p->msg) {
- DBusMessage *reply = dbus_message_new_method_return(p->msg);
- g_dbus_send_message(dev->conn, reply);
- }
-
- pending_connect_finalize(dev);
-
return;
failed:
if (p && p->msg)
error_connect_failed(dev->conn, p->msg, p->err);
pending_connect_finalize(dev);
+
if (hs->rfcomm)
headset_set_state(dev, HEADSET_STATE_CONNECTED);
else
@@ -1574,12 +981,19 @@ static int get_records(struct audio_device *device, headset_stream_cb_t cb,
svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
HEADSET_SVCLASS_ID;
+ if (svclass == HANDSFREE_SVCLASS_ID)
+ hs->connecting_uuid = HFP_AG_UUID;
+ else
+ hs->connecting_uuid = HSP_AG_UUID;
+
sdp_uuid16_create(&uuid, svclass);
err = bt_search_service(&device->src, &device->dst, &uuid,
get_record_cb, device, NULL);
- if (err < 0)
+ if (err < 0) {
+ hs->connecting_uuid = NULL;
return err;
+ }
if (hs->pending) {
hs->pending->svclass = svclass;
@@ -1716,6 +1130,7 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
{
struct audio_device *device = data;
struct headset *hs = device->headset;
+ struct btd_adapter *adapter;
int err;
if (hs->state == HEADSET_STATE_CONNECTING)
@@ -1723,7 +1138,9 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
else if (hs->state > HEADSET_STATE_CONNECTING)
return btd_error_already_connected(msg);
- if (hs->hfp_handle && !ag.telephony_ready)
+ adapter = device_get_adapter(device->btd_dev);
+
+ if (hs->hfp_handle && !telephony_is_ready(adapter))
return btd_error_not_ready(msg);
device->auto_connect = FALSE;
@@ -2010,9 +1427,6 @@ static int headset_close_rfcomm(struct audio_device *dev)
hs->rfcomm = NULL;
}
- g_free(hs->slc);
- hs->slc = NULL;
-
return 0;
}
@@ -2108,7 +1522,7 @@ uint32_t headset_config_init(GKeyFile *config)
/* Use the default values if there is no config file */
if (config == NULL)
- return ag.features;
+ return telephony_get_ag_features();
str = g_key_file_get_string(config, "General", "SCORouting",
&err);
@@ -2138,7 +1552,7 @@ uint32_t headset_config_init(GKeyFile *config)
g_free(str);
}
- return ag.features;
+ return telephony_get_ag_features();
}
static gboolean hs_dc_timeout(struct audio_device *dev)
@@ -2330,6 +1744,13 @@ GIOChannel *headset_get_rfcomm(struct audio_device *dev)
return hs->tmp_rfcomm;
}
+void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid)
+{
+ struct headset *hs = dev->headset;
+
+ hs->connecting_uuid = uuid;
+}
+
int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
{
struct headset *hs = dev->headset;
@@ -2381,6 +1802,14 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
case HEADSET_STATE_DISCONNECTED:
value = FALSE;
close_sco(dev);
+
+ if (dev->headset->slc) {
+ telephony_device_disconnect(slc->tel_dev);
+ slc->tel_dev = NULL;
+ }
+
+ dev->headset->connecting_uuid = NULL;
+
headset_close_rfcomm(dev);
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
@@ -2393,7 +1822,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "Connected",
DBUS_TYPE_BOOLEAN, &value);
- telephony_device_disconnected(dev);
}
active_devices = g_slist_remove(active_devices, dev);
break;
@@ -2409,7 +1837,8 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
if (hs->state < state) {
- if (ag.features & AG_FEATURE_INBAND_RINGTONE)
+ if (telephony_get_ag_features() &
+ AG_FEATURE_INBAND_RINGTONE)
slc->inband_ring = TRUE;
else
slc->inband_ring = FALSE;
@@ -2423,7 +1852,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
"Connected",
DBUS_TYPE_BOOLEAN, &value);
active_devices = g_slist_append(active_devices, dev);
- telephony_device_connected(dev);
} else if (hs->state == HEADSET_STATE_PLAYING) {
value = FALSE;
g_dbus_emit_signal(dev->conn, dev->path,
@@ -2743,15 +2171,13 @@ int telephony_ready_ind(uint32_t features,
const struct indicator *indicators, int rh,
const char *chld)
{
- ag.telephony_ready = TRUE;
- ag.features = features;
ag.indicators = indicators;
ag.rh = rh;
ag.chld = chld;
DBG("Telephony plugin initialized");
- print_ag_features(ag.features);
+ print_ag_features(telephony_get_ag_features());
return 0;
}
diff --git a/audio/headset.h b/audio/headset.h
index 465c2d6..d877eef 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -110,3 +110,6 @@ gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
gboolean headset_suspend(struct audio_device *dev, void *data);
gboolean headset_play(struct audio_device *dev, void *data);
void headset_shutdown(struct audio_device *dev);
+
+void headset_profile_connection_complete(struct audio_device *dev);
+void headset_set_connecting_uuid(struct audio_device *dev, const char *uuid);
diff --git a/audio/manager.c b/audio/manager.c
index 999124d..67193da 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -873,11 +873,12 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
adp->powered = powered;
if (powered) {
- /* telephony driver already initialized*/
- if (telephony == TRUE)
- return;
- telephony_init();
- telephony = TRUE;
+ if (telephony == FALSE) {
+ telephony_init();
+ telephony = TRUE;
+ }
+
+ telephony_adapter_init(adapter);
return;
}
@@ -885,6 +886,8 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
if (telephony == FALSE)
return;
+ telephony_adapter_exit(adapter);
+
for (l = adapters; l; l = l->next) {
adp = l->data;
diff --git a/audio/telephony.c b/audio/telephony.c
new file mode 100644
index 0000000..49ccafd
--- /dev/null
+++ b/audio/telephony.c
@@ -0,0 +1,633 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2011 Frederic Danis <frederic.danis@intel.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
+
+#include "btio.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#include "log.h"
+#include "device.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "sdp-client.h"
+#include "headset.h"
+#include "telephony.h"
+#include "dbus-common.h"
+
+#define AUDIO_TELEPHONY_INTERFACE "org.bluez.Telephony"
+#define AUDIO_TELEPHONY_AGENT_INTERFACE "org.bluez.TelephonyAgent"
+
+#define DEFAULT_HS_HS_CHANNEL 6
+#define DEFAULT_HF_HS_CHANNEL 7
+
+/*
+ * Profile configuration
+ *
+ * It describes for each supported profile:
+ * - UUID, RFCOMM channel and security level
+ * - remote UUID, service class and profile descriptor if they exist
+ * - profile connection complete callback called when agent replied to
+ * NewConnection method call
+ */
+struct profile_config {
+ const char *uuid; /* agent property UUID */
+ uint8_t channel;
+ const char *r_uuid;
+ uint16_t r_class;
+ uint16_t r_profile;
+ DBusPendingCallNotifyFunction connection_reply;
+};
+
+/*
+ * Telephony agent
+ *
+ * It represents the telephony agent with provided version and features.
+ *
+ * This is done by adapter.
+ */
+struct telephony_agent {
+ struct btd_adapter *btd_adapter;
+ struct profile_config *config; /* default configuration */
+ char *name; /* agent DBus bus id */
+ char *path; /* agent object path */
+ uint16_t version; /* agent profile version */
+ uint16_t features; /* agent supported features */
+ guint watch; /* agent disconnect watcher */
+};
+
+/*
+ * Telephony device
+ *
+ * It represents the connection between telephony agent (name, path and config)
+ * and remote device (with its profile version and supported features if they
+ * can be retrieved).
+ *
+ * This is used after authentication completion and remote SDP record retrieval
+ * (if supported by profile, i.e. HFP/HSP) until disconnection.
+ */
+struct telephony_device {
+ struct btd_device *btd_dev;
+ struct profile_config *config; /* default configuration */
+ char *name; /* agent DBus bus id */
+ char *path; /* agent object path */
+ struct audio_device *au_dev; /* Audio device for HSP/HFP */
+ uint16_t version; /* remote profile version */
+ uint16_t features; /* remote supported features */
+ GIOChannel *rfcomm; /* connected RFCOMM channel */
+ gboolean pending_sdp; /* SDP request is pending */
+ DBusPendingCall *call; /* D-Bus pending call */
+};
+
+static DBusConnection *connection = NULL;
+
+static GSList *agents = NULL; /* server list */
+
+static struct telephony_agent *find_agent(struct btd_adapter *adapter,
+ const char *sender, const char *path,
+ const char *uuid)
+{
+ GSList *l;
+
+ for (l = agents; l; l = l->next) {
+ struct telephony_agent *agent = l->data;
+
+ if (agent->btd_adapter != adapter)
+ continue;
+
+ if (sender && g_strcmp0(agent->name, sender) != 0)
+ continue;
+
+ if (path && g_strcmp0(agent->path, path) != 0)
+ continue;
+
+ if (uuid && g_strcmp0(agent->config->uuid, uuid) != 0)
+ continue;
+
+ return agent;
+ }
+
+ return NULL;
+}
+
+static void free_agent(struct telephony_agent *agent)
+{
+ DBusMessage *msg;
+
+ if (agent->watch) {
+ msg = dbus_message_new_method_call(agent->name, agent->path,
+ AUDIO_TELEPHONY_AGENT_INTERFACE, "Release");
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(connection, msg);
+
+ g_dbus_remove_watch(connection, agent->watch);
+ agent->watch = 0;
+ }
+
+ btd_adapter_unref(agent->btd_adapter);
+ g_free(agent->name);
+ g_free(agent->path);
+ g_free(agent);
+}
+
+gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
+ const char *uuid)
+{
+ return find_agent(adapter, NULL, NULL, uuid) != NULL;
+}
+
+static gboolean parse_properties(DBusMessageIter *props, const char **uuid,
+ uint16_t *version, uint16_t *features)
+{
+ gboolean has_uuid = FALSE;
+
+ while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(props, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+ if (strcasecmp(key, "UUID") == 0) {
+ if (var != DBUS_TYPE_STRING)
+ return FALSE;
+ dbus_message_iter_get_basic(&value, uuid);
+ has_uuid = TRUE;
+ } else if (strcasecmp(key, "Version") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return FALSE;
+ dbus_message_iter_get_basic(&value, version);
+ } else if (strcasecmp(key, "Features") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return FALSE;
+ dbus_message_iter_get_basic(&value, features);
+ }
+
+ dbus_message_iter_next(props);
+ }
+
+ return has_uuid;
+}
+
+static int dev_close(struct telephony_device *tel_dev)
+{
+ int sock;
+
+ if (tel_dev->rfcomm) {
+ sock = g_io_channel_unix_get_fd(tel_dev->rfcomm);
+ shutdown(sock, SHUT_RDWR);
+
+ g_io_channel_shutdown(tel_dev->rfcomm, TRUE, NULL);
+ g_io_channel_unref(tel_dev->rfcomm);
+
+ tel_dev->rfcomm = NULL;
+ }
+
+ return 0;
+}
+
+static gboolean agent_sendfd(struct telephony_device *tel_dev, int fd,
+ DBusPendingCallNotifyFunction notify)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict;
+ const char *path;
+
+ msg = dbus_message_new_method_call(tel_dev->name, tel_dev->path,
+ AUDIO_TELEPHONY_AGENT_INTERFACE, "NewConnection");
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ path = device_get_path(tel_dev->btd_dev);
+ dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path);
+ dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
+ &tel_dev->version);
+
+ if (tel_dev->features != 0xFFFF)
+ dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
+ &tel_dev->features);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (!dbus_connection_send_with_reply(connection, msg,
+ &tel_dev->call, -1)) {
+ dbus_message_unref(msg);
+ return FALSE;
+ }
+
+ dbus_pending_call_set_notify(tel_dev->call, notify, tel_dev, NULL);
+ dbus_message_unref(msg);
+
+ return TRUE;
+}
+
+static gboolean hs_dev_disconnect_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct telephony_device *tel_dev = data;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+
+static void hs_newconnection_reply(DBusPendingCall *call, void *user_data)
+{
+ struct telephony_device *tel_dev = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ DBG("Agent reply: %s", derr.message);
+ dbus_error_free(&derr);
+ headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+ goto done;
+ }
+
+ DBG("Agent reply: file descriptor passed successfully");
+ g_io_add_watch(tel_dev->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ hs_dev_disconnect_cb, tel_dev);
+ headset_profile_connection_complete(tel_dev->au_dev);
+
+done:
+ dbus_pending_call_unref(tel_dev->call);
+ tel_dev->call = NULL;
+ dbus_message_unref(reply);
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct telephony_device *tel_dev = user_data;
+ sdp_data_t *sdpdata;
+ uuid_t uuid;
+ sdp_list_t *profiles;
+ sdp_profile_desc_t *desc;
+ int sk;
+
+ tel_dev->pending_sdp = FALSE;
+
+ if (err < 0) {
+ error("Unable to get service record: %s (%d)", strerror(-err),
+ -err);
+ goto failed;
+ }
+
+ if (!recs || !recs->data) {
+ error("No records found");
+ goto failed;
+ }
+
+ if (!tel_dev->rfcomm) {
+ DBG("RFCOMM disconnected from server before sdp reply");
+ goto failed;
+ }
+
+ sdpdata = sdp_data_get(recs->data, SDP_ATTR_SUPPORTED_FEATURES);
+ if (sdpdata && sdpdata->dtd == SDP_UINT16)
+ tel_dev->features = sdpdata->val.uint16;
+
+ sdp_uuid16_create(&uuid, tel_dev->config->r_profile);
+
+ if (sdp_get_profile_descs(recs->data, &profiles) < 0)
+ goto failed;
+
+ desc = profiles->data;
+
+ if (sdp_uuid_cmp(&desc->uuid, &uuid) == 0)
+ tel_dev->version = desc->version;
+
+ sdp_list_free(profiles, free);
+
+ sk = g_io_channel_unix_get_fd(tel_dev->rfcomm);
+
+ if (agent_sendfd(tel_dev, sk, tel_dev->config->connection_reply) ==
+ FALSE) {
+ error("Failed to send RFCOMM socket to agent %s, path %s",
+ tel_dev->name, tel_dev->path);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ headset_set_state(tel_dev->au_dev, HEADSET_STATE_DISCONNECTED);
+}
+
+struct telephony_device *telephony_device_connecting(GIOChannel *io,
+ struct btd_device *btd_dev,
+ struct audio_device *au_dev,
+ const char *uuid)
+{
+ struct btd_adapter *adapter;
+ struct telephony_agent *agent;
+ struct telephony_device *tel_dev;
+ uuid_t r_uuid;
+ int err;
+
+ adapter = device_get_adapter(btd_dev);
+ agent = find_agent(adapter, NULL, NULL, uuid);
+ if (agent == NULL)
+ return NULL;
+
+ tel_dev = g_new0(struct telephony_device, 1);
+ tel_dev->btd_dev = btd_device_ref(btd_dev);
+ tel_dev->name = g_strdup(agent->name);
+ tel_dev->path = g_strdup(agent->path);
+ tel_dev->config = agent->config;
+ tel_dev->au_dev = au_dev;
+ tel_dev->rfcomm = g_io_channel_ref(io);
+ tel_dev->features = 0xFFFF;
+
+ sdp_uuid16_create(&r_uuid, tel_dev->config->r_class);
+
+ err = bt_search_service(&au_dev->src, &au_dev->dst, &r_uuid,
+ get_record_cb, tel_dev, NULL);
+ if (err < 0) {
+ telephony_device_disconnect(tel_dev);
+ return NULL;
+ }
+
+ tel_dev->pending_sdp = TRUE;
+
+ return tel_dev;
+}
+
+void telephony_device_disconnect(struct telephony_device *device)
+{
+ dev_close(device);
+
+ if (device->pending_sdp) {
+ struct btd_adapter *adapter;
+ bdaddr_t src, dst;
+
+ adapter = device_get_adapter(device->btd_dev);
+ adapter_get_address(adapter, &src);
+ device_get_address(device->btd_dev, &dst, NULL);
+ bt_cancel_discovery(&src, &dst);
+ }
+
+ if (device->call) {
+ dbus_pending_call_cancel(device->call);
+ dbus_pending_call_unref(device->call);
+ }
+
+ btd_device_unref(device->btd_dev);
+ g_free(device->name);
+ g_free(device->path);
+ g_free(device);
+}
+
+gboolean telephony_is_ready(struct btd_adapter *adapter)
+{
+ return find_agent(adapter, NULL, NULL, HFP_AG_UUID) ? TRUE : FALSE;
+}
+
+uint32_t telephony_get_ag_features(void)
+{
+ return 0;
+}
+
+static struct profile_config default_configs[] = {
+ { HSP_AG_UUID,
+ DEFAULT_HS_AG_CHANNEL,
+ HSP_HS_UUID,
+ HEADSET_SVCLASS_ID,
+ HEADSET_PROFILE_ID,
+ hs_newconnection_reply },
+ { HFP_AG_UUID,
+ DEFAULT_HF_AG_CHANNEL,
+ HFP_HS_UUID,
+ HANDSFREE_SVCLASS_ID,
+ HANDSFREE_PROFILE_ID,
+ hs_newconnection_reply },
+};
+
+static void agent_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+ struct telephony_agent *agent = user_data;
+
+ DBG("Agent exited without calling Unregister");
+
+ agent->watch = 0;
+ agents = g_slist_remove(agents, agent);
+ free_agent(agent);
+}
+
+static struct telephony_agent *agent_new(struct btd_adapter *adapter,
+ const char *sender, const char *path,
+ const char *uuid, uint16_t version,
+ uint16_t features)
+{
+ unsigned int i;
+
+ for (i = 0; i < G_N_ELEMENTS(default_configs) ; i++) {
+ if (strcasecmp(uuid, default_configs[i].uuid) == 0) {
+ struct telephony_agent *agent;
+
+ agent = g_new0(struct telephony_agent, 1);
+ agent->btd_adapter = btd_adapter_ref(adapter);
+ agent->config = &default_configs[i];
+ agent->name = g_strdup(sender);
+ agent->path = g_strdup(path);
+ agent->version = version;
+ agent->features = features;
+
+ return agent;
+ }
+ }
+
+ return NULL;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_adapter *adapter = data;
+ DBusMessageIter args, props;
+ const char *sender, *path, *uuid;
+ uint16_t version = 0;
+ uint16_t features = 0xFFFF;
+ struct telephony_agent *agent;
+
+ sender = dbus_message_get_sender(msg);
+
+ dbus_message_iter_init(msg, &args);
+
+ dbus_message_iter_get_basic(&args, &path);
+ dbus_message_iter_next(&args);
+
+ if (find_agent(adapter, sender, path, NULL) != NULL)
+ return btd_error_already_exists(msg);
+
+ dbus_message_iter_recurse(&args, &props);
+ if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
+ return btd_error_invalid_args(msg);
+
+ if (!parse_properties(&props, &uuid, &version, &features))
+ return btd_error_invalid_args(msg);
+
+ if (find_agent(adapter, NULL, NULL, uuid) != NULL)
+ return btd_error_already_exists(msg);
+
+ /* initialize agent properties */
+ agent = agent_new(adapter, sender, path, uuid, version, features);
+ if (agent == NULL)
+ return btd_error_invalid_args(msg);
+
+ agent->watch = g_dbus_add_disconnect_watch(conn, sender,
+ agent_disconnect_cb,
+ agent, NULL);
+
+ DBG("Register agent : %s%s for %s version 0x%04X with features 0x%02X",
+ sender, path, uuid, version, features);
+
+ agents = g_slist_append(agents, agent);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_adapter *adapter = data;
+ const char *sender, *path;
+ struct telephony_agent *agent;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ agent = find_agent(adapter, sender, path, NULL);
+ if (agent == NULL)
+ return btd_error_does_not_exist(msg);
+
+ agents = g_slist_remove(agents, agent);
+
+ DBG("Unregister agent : %s%s", sender, path);
+
+ free_agent(agent);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable telsrv_methods[] = {
+ { GDBUS_METHOD("RegisterAgent",
+ GDBUS_ARGS({ "agent", "o" }, { "properties", "a{sv}" }),
+ NULL, register_agent) },
+ { GDBUS_METHOD("UnregisterAgent",
+ GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
+ { }
+};
+
+static void path_unregister(void *data)
+{
+ DBG("Unregistered interface %s", AUDIO_TELEPHONY_INTERFACE);
+}
+
+int telephony_adapter_init(struct btd_adapter *adapter)
+{
+ const char *path;
+
+ DBG("adapter: %p", adapter);
+
+ path = adapter_get_path(adapter);
+
+ if (!g_dbus_register_interface(connection, path,
+ AUDIO_TELEPHONY_INTERFACE,
+ telsrv_methods, NULL,
+ NULL, adapter, path_unregister)) {
+ error("D-Bus failed to register %s interface",
+ AUDIO_TELEPHONY_INTERFACE);
+ return -1;
+ }
+
+ DBG("Registered interface %s", AUDIO_TELEPHONY_INTERFACE);
+
+ return 0;
+}
+
+void telephony_adapter_exit(struct btd_adapter *adapter)
+{
+ struct telephony_agent *agent;
+
+ DBG("adapter: %p", adapter);
+
+ g_dbus_unregister_interface(connection, adapter_get_path(adapter),
+ AUDIO_TELEPHONY_INTERFACE);
+
+ while ((agent = find_agent(adapter, NULL, NULL, NULL)) != NULL) {
+ agents = g_slist_remove(agents, agent);
+ free_agent(agent);
+ }
+}
+
+int telephony_init(void)
+{
+ DBG("");
+
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+ return 0;
+}
+
+void telephony_exit(void)
+{
+ DBG("");
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/audio/telephony.h b/audio/telephony.h
index 73b390c..f835202 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -141,29 +141,18 @@ struct indicator {
gboolean ignore_redundant;
};
-/* Notify telephony-*.c of connected/disconnected devices. Implemented by
- * telephony-*.c
- */
-void telephony_device_connected(void *telephony_device);
-void telephony_device_disconnected(void *telephony_device);
+struct telephony_device;
-/* HF requests (sent by the handsfree device). These are implemented by
- * telephony-*.c
- */
-void telephony_event_reporting_req(void *telephony_device, int ind);
-void telephony_response_and_hold_req(void *telephony_device, int rh);
-void telephony_last_dialed_number_req(void *telephony_device);
-void telephony_terminate_call_req(void *telephony_device);
-void telephony_answer_call_req(void *telephony_device);
-void telephony_dial_number_req(void *telephony_device, const char *number);
-void telephony_transmit_dtmf_req(void *telephony_device, char tone);
-void telephony_subscriber_number_req(void *telephony_device);
-void telephony_list_current_calls_req(void *telephony_device);
-void telephony_operator_selection_req(void *telephony_device);
-void telephony_call_hold_req(void *telephony_device, const char *cmd);
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
-void telephony_voice_dial_req(void *telephony_device, gboolean enable);
-void telephony_key_press_req(void *telephony_device, const char *keys);
+struct telephony_device *telephony_device_connecting(GIOChannel *io,
+ struct btd_device *btd_dev,
+ struct audio_device *au_dev,
+ const char *uuid);
+void telephony_device_disconnect(struct telephony_device *device);
+
+gboolean telephony_is_ready(struct btd_adapter *adapter);
+uint32_t telephony_get_ag_features(void);
+gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
+ const char *uuid);
/* AG responses to HF requests. These are implemented by headset.c */
int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
@@ -240,5 +229,7 @@ static inline int telephony_get_indicator(const struct indicator *indicators,
return -ENOENT;
}
+int telephony_adapter_init(struct btd_adapter *adapter);
+void telephony_adapter_exit(struct btd_adapter *adapter);
int telephony_init(void);
void telephony_exit(void);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v16 03/14] audio: Simplify org.bluez.Headset
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1343812131-19395-1-git-send-email-frederic.danis@linux.intel.com>
Simplify org.bluez.Headset interface by removing methods, signal and
properties which should be managed by external telephony program.
In audio/headset.[ch], remove functions no more used by telephony
drivers.
Move SpeakerGain and MicrophoneGain properties to Media Transport.
---
Makefile.am | 4 +-
audio/audio.conf | 7 -
audio/headset.c | 939 +----------------------------------------------------
audio/headset.h | 5 -
audio/manager.c | 19 --
audio/manager.h | 4 -
audio/telephony.h | 171 ----------
audio/transport.c | 90 +++--
doc/audio-api.txt | 167 ++--------
doc/media-api.txt | 19 +-
10 files changed, 106 insertions(+), 1319 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 2a8b903..b18450c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -315,9 +315,7 @@ endif
EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \
src/main.conf profiles/network/network.conf \
profiles/input/input.conf profiles/proximity/proximity.conf \
- audio/audio.conf audio/telephony-dummy.c \
- audio/telephony-maemo5.c audio/telephony-ofono.c \
- audio/telephony-maemo6.c profiles/sap/sap-dummy.c \
+ audio/audio.conf profiles/sap/sap-dummy.c \
profiles/sap/sap-u8500.c
if AUDIOPLUGIN
diff --git a/audio/audio.conf b/audio/audio.conf
index 662647c..9e9e664 100644
--- a/audio/audio.conf
+++ b/audio/audio.conf
@@ -31,10 +31,3 @@ HFP=true
# Maximum number of connected HSP/HFP devices per adapter. Defaults to 1
MaxConnected=1
-
-# Set to true to enable use of fast connectable mode (faster page scanning)
-# for HFP when incoming call starts. Default settings are restored after
-# call is answered or rejected. Page scan interval is much shorter and page
-# scan type changed to interlaced. Such allows faster connection initiated
-# by a headset.
-FastConnectable=false
diff --git a/audio/headset.c b/audio/headset.c
index 668e9f1..0070953 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -63,35 +63,7 @@
#define DC_TIMEOUT 3
-#define RING_INTERVAL 3
-
-#define BUF_SIZE 1024
-
-#define HEADSET_GAIN_SPEAKER 'S'
-#define HEADSET_GAIN_MICROPHONE 'M'
-
-static struct {
- const struct indicator *indicators; /* Available HFP indicators */
- int er_mode; /* Event reporting mode */
- int er_ind; /* Event reporting for indicators */
- int rh; /* Response and Hold state */
- char *number; /* Incoming phone number */
- int number_type; /* Incoming number type */
- guint ring_timer; /* For incoming call indication */
- const char *chld; /* Response to AT+CHLD=? */
-} ag = {
- .er_mode = 3,
- .er_ind = 0,
- .rh = BTRH_NOT_SUPPORTED,
- .number = NULL,
- .number_type = 0,
- .ring_timer = 0,
-};
-
static gboolean sco_hci = TRUE;
-static gboolean fast_connectable = FALSE;
-
-static GSList *active_devices = NULL;
static char *str_state[] = {
"HEADSET_STATE_DISCONNECTED",
@@ -129,30 +101,12 @@ struct pending_connect {
uint16_t svclass;
};
-struct headset_slc {
- struct telephony_device *tel_dev;
-
- gboolean cli_active;
- gboolean cme_enabled;
- gboolean cwa_enabled;
- gboolean pending_ring;
- gboolean inband_ring;
- gboolean nrec;
- gboolean nrec_req;
-
- int sp_gain;
- int mic_gain;
-
- unsigned int hf_features;
-};
-
struct headset {
uint32_t hsp_handle;
uint32_t hfp_handle;
int rfcomm_ch;
- GIOChannel *rfcomm;
GIOChannel *tmp_rfcomm;
const char *connecting_uuid;
GIOChannel *sco;
@@ -170,15 +124,10 @@ struct headset {
struct pending_connect *pending;
headset_lock_t lock;
- struct headset_slc *slc;
+ struct telephony_device *tel_dev;
GSList *nrec_cbs;
};
-struct event {
- const char *cmd;
- int (*callback) (struct audio_device *device, const char *buf);
-};
-
static GSList *headset_callbacks = NULL;
static void error_connect_failed(DBusConnection *conn, DBusMessage *msg,
@@ -194,44 +143,6 @@ static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
static int get_records(struct audio_device *device, headset_stream_cb_t cb,
void *user_data, unsigned int *cb_id);
-static void print_ag_features(uint32_t features)
-{
- GString *gstr;
- char *str;
-
- if (features == 0) {
- DBG("HFP AG features: (none)");
- return;
- }
-
- gstr = g_string_new("HFP AG features: ");
-
- if (features & AG_FEATURE_THREE_WAY_CALLING)
- g_string_append(gstr, "\"Three-way calling\" ");
- if (features & AG_FEATURE_EC_ANDOR_NR)
- g_string_append(gstr, "\"EC and/or NR function\" ");
- if (features & AG_FEATURE_VOICE_RECOGNITION)
- g_string_append(gstr, "\"Voice recognition function\" ");
- if (features & AG_FEATURE_INBAND_RINGTONE)
- g_string_append(gstr, "\"In-band ring tone capability\" ");
- if (features & AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG)
- g_string_append(gstr, "\"Attach a number to a voice tag\" ");
- if (features & AG_FEATURE_REJECT_A_CALL)
- g_string_append(gstr, "\"Ability to reject a call\" ");
- if (features & AG_FEATURE_ENHANCED_CALL_STATUS)
- g_string_append(gstr, "\"Enhanced call status\" ");
- if (features & AG_FEATURE_ENHANCED_CALL_CONTROL)
- g_string_append(gstr, "\"Enhanced call control\" ");
- if (features & AG_FEATURE_EXTENDED_ERROR_RESULT_CODES)
- g_string_append(gstr, "\"Extended Error Result Codes\" ");
-
- str = g_string_free(gstr, FALSE);
-
- DBG("%s", str);
-
- g_free(str);
-}
-
static const char *state2str(headset_state_t state)
{
switch (state) {
@@ -249,52 +160,6 @@ static const char *state2str(headset_state_t state)
return NULL;
}
-static int headset_send_valist(struct headset *hs, char *format, va_list ap)
-{
- char rsp[BUF_SIZE];
- ssize_t total_written, count;
- int fd;
-
- count = vsnprintf(rsp, sizeof(rsp), format, ap);
-
- if (count < 0)
- return -EINVAL;
-
- if (!hs->rfcomm) {
- error("headset_send: the headset is not connected");
- return -EIO;
- }
-
- total_written = 0;
- fd = g_io_channel_unix_get_fd(hs->rfcomm);
-
- while (total_written < count) {
- ssize_t written;
-
- written = write(fd, rsp + total_written,
- count - total_written);
- if (written < 0)
- return -errno;
-
- total_written += written;
- }
-
- return 0;
-}
-
-static int __attribute__((format(printf, 2, 3)))
- headset_send(struct headset *hs, char *format, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, format);
- ret = headset_send_valist(hs, format, ap);
- va_end(ap);
-
- return ret;
-}
-
static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -375,64 +240,11 @@ static unsigned int connect_cb_new(struct headset *hs,
return cb->id;
}
-static void __attribute__((format(printf, 3, 4)))
- send_foreach_headset(GSList *devices,
- int (*cmp) (struct headset *hs),
- char *format, ...)
-{
- GSList *l;
- va_list ap;
-
- for (l = devices; l != NULL; l = l->next) {
- struct audio_device *device = l->data;
- struct headset *hs = device->headset;
- int ret;
-
- assert(hs != NULL);
-
- if (cmp && cmp(hs) != 0)
- continue;
-
- va_start(ap, format);
- ret = headset_send_valist(hs, format, ap);
- if (ret < 0)
- error("Failed to send to headset: %s (%d)",
- strerror(-ret), -ret);
- va_end(ap);
- }
-}
-
-static int cli_cmp(struct headset *hs)
-{
- struct headset_slc *slc = hs->slc;
-
- if (!hs->hfp_active)
- return -1;
-
- if (slc->cli_active)
- return 0;
- else
- return -1;
-}
-
-static gboolean ring_timer_cb(gpointer data)
-{
- send_foreach_headset(active_devices, NULL, "\r\nRING\r\n");
-
- if (ag.number)
- send_foreach_headset(active_devices, cli_cmp,
- "\r\n+CLIP: \"%s\",%d\r\n",
- ag.number, ag.number_type);
-
- return TRUE;
-}
-
static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
int sk;
struct audio_device *dev = user_data;
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
struct pending_connect *p = hs->pending;
if (err) {
@@ -445,7 +257,7 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
pending_connect_finalize(dev);
}
- if (hs->rfcomm)
+ if (hs->tel_dev)
headset_set_state(dev, HEADSET_STATE_CONNECTED);
else
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
@@ -473,14 +285,6 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
fcntl(sk, F_SETFL, 0);
headset_set_state(dev, HEADSET_STATE_PLAYING);
-
- if (slc->pending_ring) {
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
- ring_timer_cb,
- NULL);
- slc->pending_ring = FALSE;
- }
}
static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
@@ -519,14 +323,6 @@ static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
return 0;
}
-static int hfp_cmp(struct headset *hs)
-{
- if (hs->hfp_active)
- return 0;
- else
- return -1;
-}
-
void headset_profile_connection_complete(struct audio_device *dev)
{
struct headset *hs = dev->headset;
@@ -556,202 +352,6 @@ void headset_profile_connection_complete(struct audio_device *dev)
}
}
-static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if ((err != CME_ERROR_NONE) && slc->cme_enabled)
- return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
-
- switch (err) {
- case CME_ERROR_NONE:
- return headset_send(hs, "\r\nOK\r\n");
- case CME_ERROR_NO_NETWORK_SERVICE:
- return headset_send(hs, "\r\nNO CARRIER\r\n");
- default:
- return headset_send(hs, "\r\nERROR\r\n");
- }
-}
-
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- uint32_t ag_features;
- int ret;
-
- if (err != CME_ERROR_NONE)
- return telephony_generic_rsp(telephony_device, err);
-
- ret = headset_send(hs, "\r\nOK\r\n");
- if (ret < 0)
- return ret;
-
- if (hs->state != HEADSET_STATE_CONNECTING)
- return 0;
-
- ag_features = telephony_get_ag_features();
- if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
- ag_features & AG_FEATURE_THREE_WAY_CALLING)
- return 0;
-
- headset_profile_connection_complete(device);
-
- return 0;
-}
-
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_terminate_call_rsp(void *telephony_device,
- cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
-
- if (err != CME_ERROR_NONE)
- return telephony_generic_rsp(telephony_device, err);
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, "CallTerminated",
- DBUS_TYPE_INVALID);
-
- return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
-{
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- const char *name, *property;
-
- if (gain > 15) {
- error("Invalid gain value: %u", gain);
- return -EINVAL;
- }
-
- switch (type) {
- case HEADSET_GAIN_SPEAKER:
- if (slc->sp_gain == gain) {
- DBG("Ignoring no-change in speaker gain");
- return -EALREADY;
- }
- name = "SpeakerGainChanged";
- property = "SpeakerGain";
- slc->sp_gain = gain;
- break;
- case HEADSET_GAIN_MICROPHONE:
- if (slc->mic_gain == gain) {
- DBG("Ignoring no-change in microphone gain");
- return -EALREADY;
- }
- name = "MicrophoneGainChanged";
- property = "MicrophoneGain";
- slc->mic_gain = gain;
- break;
- default:
- error("Unknown gain setting");
- return -EINVAL;
- }
-
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, name,
- DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- emit_property_changed(device->conn, device->path,
- AUDIO_HEADSET_INTERFACE, property,
- DBUS_TYPE_UINT16, &gain);
-
- return 0;
-}
-
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err)
-{
- struct audio_device *device = telephony_device;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
-
- if (err == CME_ERROR_NONE) {
- GSList *l;
-
- for (l = hs->nrec_cbs; l; l = l->next) {
- struct headset_nrec_callback *nrec_cb = l->data;
-
- nrec_cb->cb(device, slc->nrec_req, nrec_cb->user_data);
- }
-
- slc->nrec = hs->slc->nrec_req;
- }
-
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err)
-{
- return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_ind(int mode, const char *oper)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+COPS: %d,0,\"%s\"\r\n",
- mode, oper);
- return 0;
-}
-
static void close_sco(struct audio_device *device)
{
struct headset *hs = device->headset;
@@ -792,7 +392,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
struct btd_adapter *adapter;
struct pending_connect *p = hs->pending;
char hs_address[18];
- struct telephony_device *tel_dev;
if (err) {
error("%s", err->message);
@@ -808,14 +407,14 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
goto failed;
}
- tel_dev = telephony_device_connecting(chan, btd_dev, dev,
+ hs->tel_dev = telephony_device_connecting(chan, btd_dev, dev,
hs->connecting_uuid);
- if (tel_dev == NULL)
+ if (hs->tel_dev == NULL)
goto failed;
hs->connecting_uuid = NULL;
- hs->rfcomm = hs->tmp_rfcomm;
+ g_io_channel_unref(hs->tmp_rfcomm);
hs->tmp_rfcomm = NULL;
ba2str(&dev->dst, hs_address);
@@ -827,12 +426,6 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
DBG("%s: Connected to %s", dev->path, hs_address);
- hs->slc = g_new0(struct headset_slc, 1);
- hs->slc->tel_dev = tel_dev;
- hs->slc->sp_gain = 15;
- hs->slc->mic_gain = 15;
- hs->slc->nrec = TRUE;
-
return;
failed:
@@ -840,10 +433,7 @@ failed:
error_connect_failed(dev->conn, p->msg, p->err);
pending_connect_finalize(dev);
- if (hs->rfcomm)
- headset_set_state(dev, HEADSET_STATE_CONNECTED);
- else
- headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
}
static int headset_set_channel(struct headset *headset,
@@ -1105,26 +695,6 @@ static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
}
-static DBusMessage *hs_is_connected(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- DBusMessage *reply;
- dbus_bool_t connected;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
-
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1156,95 +726,6 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
-static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply = NULL;
- int err;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (ag.ring_timer) {
- DBG("IndicateCall received when already indicating");
- return reply;
- }
-
- err = headset_send(hs, "\r\nRING\r\n");
- if (err < 0) {
- dbus_message_unref(reply);
- return btd_error_failed(msg, strerror(-err));
- }
-
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
- NULL);
-
- return reply;
-}
-
-static DBusMessage *hs_cancel_call(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply = NULL;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- } else
- DBG("Got CancelCall method call but no call is active");
-
- return reply;
-}
-
-static DBusMessage *hs_set_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data, uint16_t gain,
- char type)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply;
- int err;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_connected(msg);
-
- err = headset_set_gain(device, gain, type);
- if (err < 0)
- return btd_error_invalid_args(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (hs->state == HEADSET_STATE_PLAYING) {
- err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
- if (err < 0) {
- dbus_message_unref(reply);
- return btd_error_failed(msg, strerror(-err));
- }
- }
-
- return reply;
-}
-
static DBusMessage *hs_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1280,94 +761,22 @@ static DBusMessage *hs_get_properties(DBusConnection *conn,
value = (device->headset->state >= HEADSET_STATE_CONNECTED);
dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
- if (!value)
- goto done;
-
- /* SpeakerGain */
- dict_append_entry(&dict, "SpeakerGain",
- DBUS_TYPE_UINT16,
- &device->headset->slc->sp_gain);
-
- /* MicrophoneGain */
- dict_append_entry(&dict, "MicrophoneGain",
- DBUS_TYPE_UINT16,
- &device->headset->slc->mic_gain);
-
-done:
dbus_message_iter_close_container(&iter, &dict);
return reply;
}
-static DBusMessage *hs_set_property(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *property;
- DBusMessageIter iter;
- DBusMessageIter sub;
- uint16_t gain;
-
- if (!dbus_message_iter_init(msg, &iter))
- return btd_error_invalid_args(msg);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&iter, &property);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return btd_error_invalid_args(msg);
- dbus_message_iter_recurse(&iter, &sub);
-
- if (g_str_equal("SpeakerGain", property)) {
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &gain);
- return hs_set_gain(conn, msg, data, gain,
- HEADSET_GAIN_SPEAKER);
- } else if (g_str_equal("MicrophoneGain", property)) {
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &gain);
- return hs_set_gain(conn, msg, data, gain,
- HEADSET_GAIN_MICROPHONE);
- }
-
- return btd_error_invalid_args(msg);
-}
-
static const GDBusMethodTable headset_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, hs_connect) },
{ GDBUS_METHOD("Disconnect", NULL, NULL, hs_disconnect) },
- { GDBUS_METHOD("IsConnected",
- NULL, GDBUS_ARGS({ "connected", "b" }),
- hs_is_connected) },
- { GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
- { GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
{ GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
hs_get_properties) },
- { GDBUS_METHOD("SetProperty",
- GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
- hs_set_property) },
{ }
};
static const GDBusSignalTable headset_signals[] = {
- { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) },
- { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) },
- { GDBUS_SIGNAL("AnswerRequested", NULL) },
- { GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) },
- { GDBUS_DEPRECATED_SIGNAL("Playing", NULL) },
- { GDBUS_DEPRECATED_SIGNAL("SpeakerGainChanged",
- GDBUS_ARGS({ "gain", "q" })) },
- { GDBUS_DEPRECATED_SIGNAL("MicrophoneGainChanged",
- GDBUS_ARGS({ "gain", "q" })) },
- { GDBUS_SIGNAL("CallTerminated", NULL) },
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ }
@@ -1418,13 +827,11 @@ void headset_update(struct audio_device *dev, uint16_t svc,
static int headset_close_rfcomm(struct audio_device *dev)
{
struct headset *hs = dev->headset;
- GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;
- if (rfcomm) {
- g_io_channel_shutdown(rfcomm, TRUE, NULL);
- g_io_channel_unref(rfcomm);
+ if (hs->tmp_rfcomm) {
+ g_io_channel_shutdown(hs->tmp_rfcomm, TRUE, NULL);
+ g_io_channel_unref(hs->tmp_rfcomm);
hs->tmp_rfcomm = NULL;
- hs->rfcomm = NULL;
}
return 0;
@@ -1539,19 +946,6 @@ uint32_t headset_config_init(GKeyFile *config)
g_free(str);
}
- /* Init fast connectable option */
- str = g_key_file_get_string(config, "Headset", "FastConnectable",
- &err);
- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- fast_connectable = strcmp(str, "true") == 0;
- if (fast_connectable)
- manager_set_fast_connectable(FALSE);
- g_free(str);
- }
-
return telephony_get_ag_features();
}
@@ -1590,7 +984,7 @@ gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id)
return TRUE;
if (hs->auto_dc) {
- if (hs->rfcomm)
+ if (hs->tel_dev)
hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,
(GSourceFunc) hs_dc_timeout,
dev);
@@ -1629,7 +1023,7 @@ unsigned int headset_request_stream(struct audio_device *dev,
hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)
return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
- if (hs->rfcomm == NULL) {
+ if (hs->tel_dev == NULL) {
if (rfcomm_connect(dev, cb, user_data, &id) < 0)
return 0;
hs->auto_dc = TRUE;
@@ -1658,7 +1052,7 @@ unsigned int headset_config_stream(struct audio_device *dev,
return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,
user_data);
- if (hs->rfcomm)
+ if (hs->tel_dev)
goto done;
if (rfcomm_connect(dev, cb, user_data, &id) < 0)
@@ -1766,29 +1160,18 @@ int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
{
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
if (hs->sco)
return -EISCONN;
hs->sco = g_io_channel_ref(io);
- if (slc->pending_ring) {
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
- ring_timer_cb,
- NULL);
- slc->pending_ring = FALSE;
- }
-
return 0;
}
void headset_set_state(struct audio_device *dev, headset_state_t state)
{
struct headset *hs = dev->headset;
- struct headset_slc *slc = hs->slc;
- gboolean value;
const char *state_str;
headset_state_t old_state = hs->state;
GSList *l;
@@ -1800,12 +1183,11 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
switch (state) {
case HEADSET_STATE_DISCONNECTED:
- value = FALSE;
close_sco(dev);
- if (dev->headset->slc) {
- telephony_device_disconnect(slc->tel_dev);
- slc->tel_dev = NULL;
+ if (dev->headset->tel_dev) {
+ telephony_device_disconnect(dev->headset->tel_dev);
+ dev->headset->tel_dev = NULL;
}
dev->headset->connecting_uuid = NULL;
@@ -1814,16 +1196,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Disconnected",
- DBUS_TYPE_INVALID);
- if (hs->state > HEADSET_STATE_CONNECTING) {
- emit_property_changed(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE, "Connected",
- DBUS_TYPE_BOOLEAN, &value);
- }
- active_devices = g_slist_remove(active_devices, dev);
break;
case HEADSET_STATE_CONNECTING:
emit_property_changed(dev->conn, dev->path,
@@ -1836,38 +1208,10 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
- if (hs->state < state) {
- if (telephony_get_ag_features() &
- AG_FEATURE_INBAND_RINGTONE)
- slc->inband_ring = TRUE;
- else
- slc->inband_ring = FALSE;
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Connected",
- DBUS_TYPE_INVALID);
- value = TRUE;
- emit_property_changed(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Connected",
- DBUS_TYPE_BOOLEAN, &value);
- active_devices = g_slist_append(active_devices, dev);
- } else if (hs->state == HEADSET_STATE_PLAYING) {
- value = FALSE;
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Stopped",
- DBUS_TYPE_INVALID);
- emit_property_changed(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE,
- "Playing",
- DBUS_TYPE_BOOLEAN, &value);
- }
break;
case HEADSET_STATE_PLAY_IN_PROGRESS:
break;
case HEADSET_STATE_PLAYING:
- value = TRUE;
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
@@ -1877,18 +1221,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state)
hs->sco_id = g_io_add_watch(hs->sco,
G_IO_ERR | G_IO_NVAL,
(GIOFunc) sco_cb, dev);
-
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE, "Playing",
- DBUS_TYPE_INVALID);
- emit_property_changed(dev->conn, dev->path,
- AUDIO_HEADSET_INTERFACE, "Playing",
- DBUS_TYPE_BOOLEAN, &value);
-
- if (slc->sp_gain >= 0)
- headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain);
- if (slc->mic_gain >= 0)
- headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain);
break;
}
@@ -1993,60 +1325,6 @@ int headset_get_sco_fd(struct audio_device *dev)
return g_io_channel_unix_get_fd(hs->sco);
}
-gboolean headset_get_nrec(struct audio_device *dev)
-{
- struct headset *hs = dev->headset;
-
- if (!hs->slc)
- return TRUE;
-
- return hs->slc->nrec;
-}
-
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
- headset_nrec_cb cb, void *user_data)
-{
- struct headset *hs = dev->headset;
- struct headset_nrec_callback *nrec_cb;
- static unsigned int id = 0;
-
- nrec_cb = g_new(struct headset_nrec_callback, 1);
- nrec_cb->cb = cb;
- nrec_cb->user_data = user_data;
- nrec_cb->id = ++id;
-
- hs->nrec_cbs = g_slist_prepend(hs->nrec_cbs, nrec_cb);
-
- return nrec_cb->id;
-}
-
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id)
-{
- struct headset *hs = dev->headset;
- GSList *l;
-
- for (l = hs->nrec_cbs; l != NULL; l = l->next) {
- struct headset_nrec_callback *cb = l->data;
- if (cb && cb->id == id) {
- hs->nrec_cbs = g_slist_remove(hs->nrec_cbs, cb);
- g_free(cb);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-gboolean headset_get_inband(struct audio_device *dev)
-{
- struct headset *hs = dev->headset;
-
- if (!hs->slc)
- return TRUE;
-
- return hs->slc->inband_ring;
-}
-
gboolean headset_get_sco_hci(struct audio_device *dev)
{
return sco_hci;
@@ -2063,193 +1341,6 @@ void headset_shutdown(struct audio_device *dev)
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
}
-int telephony_event_ind(int index)
-{
- if (!active_devices)
- return -ENODEV;
-
- if (!ag.er_ind) {
- DBG("telephony_report_event called but events are disabled");
- return -EINVAL;
- }
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CIEV: %d,%d\r\n", index + 1,
- ag.indicators[index].val);
-
- return 0;
-}
-
-int telephony_response_and_hold_ind(int rh)
-{
- if (!active_devices)
- return -ENODEV;
-
- ag.rh = rh;
-
- /* If we aren't in any response and hold state don't send anything */
- if (ag.rh < 0)
- return 0;
-
- send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n",
- ag.rh);
-
- return 0;
-}
-
-int telephony_incoming_call_ind(const char *number, int type)
-{
- struct audio_device *dev;
- struct headset *hs;
- struct headset_slc *slc;
-
- if (fast_connectable)
- manager_set_fast_connectable(TRUE);
-
- if (!active_devices)
- return -ENODEV;
-
- /* Get the latest connected device */
- dev = active_devices->data;
- hs = dev->headset;
- slc = hs->slc;
-
- if (ag.ring_timer) {
- DBG("telephony_incoming_call_ind: already calling");
- return -EBUSY;
- }
-
- /* With HSP 1.2 the RING messages should *not* be sent if inband
- * ringtone is being used */
- if (!hs->hfp_active && slc->inband_ring)
- return 0;
-
- g_free(ag.number);
- ag.number = g_strdup(number);
- ag.number_type = type;
-
- if (slc->inband_ring && hs->hfp_active &&
- hs->state != HEADSET_STATE_PLAYING) {
- slc->pending_ring = TRUE;
- return 0;
- }
-
- ring_timer_cb(NULL);
- ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
- NULL);
-
- return 0;
-}
-
-int telephony_calling_stopped_ind(void)
-{
- struct audio_device *dev;
-
- if (fast_connectable)
- manager_set_fast_connectable(FALSE);
-
- if (ag.ring_timer) {
- g_source_remove(ag.ring_timer);
- ag.ring_timer = 0;
- }
-
- if (!active_devices)
- return 0;
-
- /* In case SCO isn't fully up yet */
- dev = active_devices->data;
-
- if (!dev->headset->slc->pending_ring && !ag.ring_timer)
- return -EINVAL;
-
- dev->headset->slc->pending_ring = FALSE;
-
- return 0;
-}
-
-int telephony_ready_ind(uint32_t features,
- const struct indicator *indicators, int rh,
- const char *chld)
-{
- ag.indicators = indicators;
- ag.rh = rh;
- ag.chld = chld;
-
- DBG("Telephony plugin initialized");
-
- print_ag_features(telephony_get_ag_features());
-
- return 0;
-}
-
-int telephony_deinit(void)
-{
- g_free(ag.number);
-
- memset(&ag, 0, sizeof(ag));
-
- ag.er_mode = 3;
- ag.rh = BTRH_NOT_SUPPORTED;
-
- DBG("Telephony deinitialized");
-
- return 0;
-}
-
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
- int mprty, const char *number,
- int type)
-{
- if (!active_devices)
- return -ENODEV;
-
- if (number && strlen(number) > 0)
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
- idx, dir, status, mode, mprty, number, type);
- else
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CLCC: %d,%d,%d,%d,%d\r\n",
- idx, dir, status, mode, mprty);
-
- return 0;
-}
-
-int telephony_subscriber_number_ind(const char *number, int type, int service)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, hfp_cmp,
- "\r\n+CNUM: ,%s,%d,,%d\r\n",
- number, type, service);
-
- return 0;
-}
-
-static int cwa_cmp(struct headset *hs)
-{
- if (!hs->hfp_active)
- return -1;
-
- if (hs->slc->cwa_enabled)
- return 0;
- else
- return -1;
-}
-
-int telephony_call_waiting_ind(const char *number, int type)
-{
- if (!active_devices)
- return -ENODEV;
-
- send_foreach_headset(active_devices, cwa_cmp,
- "\r\n+CCWA: \"%s\",%d\r\n",
- number, type);
-
- return 0;
-}
-
unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data)
{
struct headset_state_callback *state_cb;
diff --git a/audio/headset.h b/audio/headset.h
index d877eef..61e63c8 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -95,11 +95,6 @@ void headset_set_state(struct audio_device *dev, headset_state_t state);
int headset_get_channel(struct audio_device *dev);
int headset_get_sco_fd(struct audio_device *dev);
-gboolean headset_get_nrec(struct audio_device *dev);
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
- headset_nrec_cb cb, void *user_data);
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id);
-gboolean headset_get_inband(struct audio_device *dev);
gboolean headset_get_sco_hci(struct audio_device *dev);
gboolean headset_is_active(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 67193da..2b125a0 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -1425,22 +1425,3 @@ gboolean manager_allow_headset_connection(struct audio_device *device)
return TRUE;
}
-
-void manager_set_fast_connectable(gboolean enable)
-{
- GSList *l;
-
- if (enable && !manager_allow_headset_connection(NULL)) {
- DBG("Refusing enabling fast connectable");
- return;
- }
-
- for (l = adapters; l != NULL; l = l->next) {
- struct audio_adapter *adapter = l->data;
-
- if (btd_adapter_set_fast_connectable(adapter->btd_adapter,
- enable))
- error("Changing fast connectable for hci%d failed",
- adapter_get_dev_id(adapter->btd_adapter));
- }
-}
diff --git a/audio/manager.h b/audio/manager.h
index f1d3021..85e5065 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -57,7 +57,3 @@ struct audio_device *manager_get_device(const bdaddr_t *src,
gboolean create);
gboolean manager_allow_headset_connection(struct audio_device *device);
-
-/* TRUE to enable fast connectable and FALSE to disable fast connectable for all
- * audio adapters. */
-void manager_set_fast_connectable(gboolean enable);
diff --git a/audio/telephony.h b/audio/telephony.h
index f835202..1a4ab06 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -26,13 +26,6 @@
#include <errno.h>
#include <glib.h>
-/* Response and hold values */
-#define BTRH_NOT_SUPPORTED -2
-#define BTRH_NONE -1
-#define BTRH_HOLD 0
-#define BTRH_ACCEPT 1
-#define BTRH_REJECT 2
-
/* HFP feature bits */
#define AG_FEATURE_THREE_WAY_CALLING 0x0001
#define AG_FEATURE_EC_ANDOR_NR 0x0002
@@ -52,95 +45,6 @@
#define HF_FEATURE_ENHANCED_CALL_STATUS 0x0020
#define HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040
-/* Indicator event values */
-#define EV_SERVICE_NONE 0
-#define EV_SERVICE_PRESENT 1
-
-#define EV_CALL_INACTIVE 0
-#define EV_CALL_ACTIVE 1
-
-#define EV_CALLSETUP_INACTIVE 0
-#define EV_CALLSETUP_INCOMING 1
-#define EV_CALLSETUP_OUTGOING 2
-#define EV_CALLSETUP_ALERTING 3
-
-#define EV_CALLHELD_NONE 0
-#define EV_CALLHELD_MULTIPLE 1
-#define EV_CALLHELD_ON_HOLD 2
-
-#define EV_ROAM_INACTIVE 0
-#define EV_ROAM_ACTIVE 1
-
-/* Call parameters */
-#define CALL_DIR_OUTGOING 0
-#define CALL_DIR_INCOMING 1
-
-#define CALL_STATUS_ACTIVE 0
-#define CALL_STATUS_HELD 1
-#define CALL_STATUS_DIALING 2
-#define CALL_STATUS_ALERTING 3
-#define CALL_STATUS_INCOMING 4
-#define CALL_STATUS_WAITING 5
-
-#define CALL_MODE_VOICE 0
-#define CALL_MODE_DATA 1
-#define CALL_MODE_FAX 2
-
-#define CALL_MULTIPARTY_NO 0
-#define CALL_MULTIPARTY_YES 1
-
-/* Subscriber number parameters */
-#define SUBSCRIBER_SERVICE_VOICE 4
-#define SUBSCRIBER_SERVICE_FAX 5
-
-/* Operator selection mode values */
-#define OPERATOR_MODE_AUTO 0
-#define OPERATOR_MODE_MANUAL 1
-#define OPERATOR_MODE_DEREGISTER 2
-#define OPERATOR_MODE_MANUAL_AUTO 4
-
-/* Some common number types */
-#define NUMBER_TYPE_UNKNOWN 128
-#define NUMBER_TYPE_TELEPHONY 129
-#define NUMBER_TYPE_INTERNATIONAL 145
-#define NUMBER_TYPE_NATIONAL 161
-#define NUMBER_TYPE_VOIP 255
-
-/* Extended Audio Gateway Error Result Codes */
-typedef enum {
- CME_ERROR_NONE = -1,
- CME_ERROR_AG_FAILURE = 0,
- CME_ERROR_NO_PHONE_CONNECTION = 1,
- CME_ERROR_NOT_ALLOWED = 3,
- CME_ERROR_NOT_SUPPORTED = 4,
- CME_ERROR_PH_SIM_PIN_REQUIRED = 5,
- CME_ERROR_SIM_NOT_INSERTED = 10,
- CME_ERROR_SIM_PIN_REQUIRED = 11,
- CME_ERROR_SIM_PUK_REQUIRED = 12,
- CME_ERROR_SIM_FAILURE = 13,
- CME_ERROR_SIM_BUSY = 14,
- CME_ERROR_INCORRECT_PASSWORD = 16,
- CME_ERROR_SIM_PIN2_REQUIRED = 17,
- CME_ERROR_SIM_PUK2_REQUIRED = 18,
- CME_ERROR_MEMORY_FULL = 20,
- CME_ERROR_INVALID_INDEX = 21,
- CME_ERROR_MEMORY_FAILURE = 23,
- CME_ERROR_TEXT_STRING_TOO_LONG = 24,
- CME_ERROR_INVALID_TEXT_STRING = 25,
- CME_ERROR_DIAL_STRING_TOO_LONG = 26,
- CME_ERROR_INVALID_DIAL_STRING = 27,
- CME_ERROR_NO_NETWORK_SERVICE = 30,
- CME_ERROR_NETWORK_TIMEOUT = 31,
- CME_ERROR_NETWORK_NOT_ALLOWED = 32,
-} cme_error_t;
-
-struct indicator {
- const char *desc;
- const char *range;
- int val;
- gboolean ignore_redundant;
-};
-
struct telephony_device;
struct telephony_device *telephony_device_connecting(GIOChannel *io,
@@ -154,81 +58,6 @@ uint32_t telephony_get_ag_features(void);
gboolean telephony_is_uuid_supported(struct btd_adapter *adapter,
const char *uuid);
-/* AG responses to HF requests. These are implemented by headset.c */
-int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err);
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err);
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err);
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err);
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err);
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err);
-
-/* Event indications by AG. These are implemented by headset.c */
-int telephony_event_ind(int index);
-int telephony_response_and_hold_ind(int rh);
-int telephony_incoming_call_ind(const char *number, int type);
-int telephony_calling_stopped_ind(void);
-int telephony_ready_ind(uint32_t features, const struct indicator *indicators,
- int rh, const char *chld);
-int telephony_deinit(void);
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
- int mprty, const char *number,
- int type);
-int telephony_subscriber_number_ind(const char *number, int type,
- int service);
-int telephony_call_waiting_ind(const char *number, int type);
-int telephony_operator_selection_ind(int mode, const char *oper);
-
-/* Helper function for quick indicator updates */
-static inline int telephony_update_indicator(struct indicator *indicators,
- const char *desc,
- int new_val)
-{
- int i;
- struct indicator *ind = NULL;
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (g_str_equal(indicators[i].desc, desc)) {
- ind = &indicators[i];
- break;
- }
- }
-
- if (!ind)
- return -ENOENT;
-
- DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
-
- if (ind->ignore_redundant && ind->val == new_val) {
- DBG("Ignoring no-change indication");
- return 0;
- }
-
- ind->val = new_val;
-
- return telephony_event_ind(i);
-}
-
-static inline int telephony_get_indicator(const struct indicator *indicators,
- const char *desc)
-{
- int i;
-
- for (i = 0; indicators[i].desc != NULL; i++) {
- if (g_str_equal(indicators[i].desc, desc))
- return indicators[i].val;
- }
-
- return -ENOENT;
-}
-
int telephony_adapter_init(struct btd_adapter *adapter);
void telephony_adapter_exit(struct btd_adapter *adapter);
int telephony_init(void);
diff --git a/audio/transport.c b/audio/transport.c
index 832ad2a..6d4ad55 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -70,7 +70,10 @@ struct a2dp_transport {
struct headset_transport {
struct audio_device *device;
- unsigned int nrec_id;
+ gboolean nrec;
+ gboolean inband;
+ uint16_t output_gain;
+ uint16_t input_gain;
};
struct media_transport {
@@ -788,26 +791,62 @@ static int set_property_headset(struct media_transport *transport,
const char *property,
DBusMessageIter *value)
{
- if (g_strcmp0(property, "NREC") == 0) {
- gboolean nrec;
+ struct headset_transport *headset = transport->data;
+ if (g_strcmp0(property, "NREC") == 0) {
if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
return -EINVAL;
- dbus_message_iter_get_basic(value, &nrec);
+ dbus_message_iter_get_basic(value, &headset->nrec);
- /* FIXME: set new nrec */
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE, "NREC",
+ DBUS_TYPE_BOOLEAN, &headset->nrec);
return 0;
} else if (g_strcmp0(property, "InbandRingtone") == 0) {
- gboolean inband;
-
if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
return -EINVAL;
- dbus_message_iter_get_basic(value, &inband);
+ dbus_message_iter_get_basic(value, &headset->inband);
+
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "InbandRingtone",
+ DBUS_TYPE_BOOLEAN, &headset->inband);
+ return 0;
+ } else if (g_strcmp0(property, "OutputGain") == 0) {
+ uint16_t gain;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(value, &gain);
+
+ if (gain > 15)
+ goto failed;
+
+ headset->output_gain = gain;
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "OutputGain", DBUS_TYPE_UINT16,
+ &headset->output_gain);
+ return 0;
+ } else if (g_strcmp0(property, "InputGain") == 0) {
+ uint16_t gain;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(value, &gain);
+
+ if (gain > 15)
+ goto failed;
- /* FIXME: set new inband */
+ headset->input_gain = gain;
+ emit_property_changed(transport->conn, transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "InputGain", DBUS_TYPE_UINT16,
+ &headset->input_gain);
return 0;
}
+failed:
return -EINVAL;
}
@@ -879,14 +918,16 @@ static void get_properties_a2dp(struct media_transport *transport,
static void get_properties_headset(struct media_transport *transport,
DBusMessageIter *dict)
{
- gboolean nrec, inband;
+ struct headset_transport *headset = transport->data;
const char *routing;
- nrec = headset_get_nrec(transport->device);
- dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec);
-
- inband = headset_get_inband(transport->device);
- dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband);
+ dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &headset->nrec);
+ dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN,
+ &headset->inband);
+ dict_append_entry(dict, "OutputGain", DBUS_TYPE_UINT16,
+ &headset->output_gain);
+ dict_append_entry(dict, "InputGain", DBUS_TYPE_UINT16,
+ &headset->input_gain);
routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM";
dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing);
@@ -985,9 +1026,6 @@ static void destroy_headset(void *data)
{
struct headset_transport *headset = data;
- if (headset->nrec_id > 0)
- headset_remove_nrec_cb(headset->device, headset->nrec_id);
-
g_free(headset);
}
@@ -1015,18 +1053,6 @@ static void media_transport_free(void *data)
g_free(transport);
}
-static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
- void *user_data)
-{
- struct media_transport *transport = user_data;
-
- DBG("");
-
- emit_property_changed(transport->conn, transport->path,
- MEDIA_TRANSPORT_INTERFACE, "NREC",
- DBUS_TYPE_BOOLEAN, &nrec);
-}
-
struct media_transport *media_transport_create(DBusConnection *conn,
struct media_endpoint *endpoint,
struct audio_device *device,
@@ -1068,9 +1094,7 @@ struct media_transport *media_transport_create(DBusConnection *conn,
headset = g_new0(struct headset_transport, 1);
headset->device = device;
- headset->nrec_id = headset_add_nrec_cb(device,
- headset_nrec_changed,
- transport);
+ headset->nrec = TRUE;
transport->resume = resume_headset;
transport->suspend = suspend_headset;
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index c620a7d..e8bb210 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -66,20 +66,6 @@ Methods void Connect()
Disconnect from the HSP/HFP service on the remote
device.
- void IndicateCall()
-
- Indicate an incoming call on the headset
- connected to the stream. Will continue to
- ring the headset about every 3 seconds.
-
- void CancelCall()
-
- Cancel the incoming call indication.
-
- void Play() {deprecated}
-
- Open the audio connection to the headset.
-
void Stop()
Close the audio connection.
@@ -91,44 +77,7 @@ Methods void Connect()
Possible Errors: org.bluez.Error.InvalidArguments
- void SetProperty(string name, variant value)
-
- Changes the value of the specified property. Only
- properties that are listed as read-write are changeable.
- On success this will emit a PropertyChanged signal.
-
- Possible Errors: org.bluez.Error.DoesNotExist
- org.bluez.Error.InvalidArguments
-
-Signals void AnswerRequested()
-
- Sent when the answer button is pressed on the headset
-
- void Connected() {deprecated}
-
- Sent when the device has been connected to.
-
- void Disconnected() {deprecated}
-
- Sent when the device has been disconnected from.
-
- void Stopped() {deprecated}
-
- Sent when the audio connection is closed
-
- void Playing() {deprecated}
-
- Sent when the audio connection is opened
-
- void SpeakerGainChanged(uint16 gain) {deprecated}
-
- The speaker gain changed.
-
- void MicrophoneGainChanged(uint16 gain) {deprecated}
-
- The microphone gain changed.
-
- PropertyChanged(string name, variant value)
+Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
property.
@@ -158,24 +107,6 @@ properties string State [readonly]
"playing" -> "disconnected"
Disconnected from the remote device
- boolean Connected [readonly]
-
- Indicates if there is a active connection to the
- HSP/HFP connection on the remote device.
-
- boolean Playing [readonly]
-
- Indicates if an audio connection to the headset
- is active.
-
- uint16 SpeakerGain [readwrite]
-
- The speaker gain when available.
-
- uint16 MicrophoneGain [readwrite]
-
- The speaker gain when available.
-
AudioSink hierarchy
===================
@@ -329,100 +260,40 @@ Methods void Connect()
Disconnect from the AG service on the remote device
- void AnswerCall()
-
- It has to called only after Ring signal received.
-
- void TerminateCall()
-
- Terminate call which is running or reject an incoming
- call. This has nothing with any 3-way situation incl.
- RaH. Just plain old PDH.
-
- void Call(string number)
-
- Dial a number 'number'. No number processing is done
- thus if AG would reject to dial it don't blame me :)
-
- string GetOperatorName()
-
- Find out the name of the currently selected network
- operator by AG.
-
- void SendDTMF(string digits)
-
- Will send each digit in the 'digits' sequentially. Would
- send nothing if there is non-dtmf digit.
-
- string GetSubscriberNumber()
-
- Get the voicecall subscriber number of AG
-
dict GetProperties()
Returns all properties for the interface. See the
properties section for available properties.
-Signals void Ring(string number)
-
- Someone's calling from 'number'.
- Caller number is provided as received from AG.
-
- void CallTerminated()
-
- Call failed to set up. It means that we tried to call
- someone or someone tried to call us but call was not
- accepted.
-
- void CallStarted()
-
- Call set up successfully.
-
- void CallEnded()
-
- Call was started and now ended. In contrast with
- CallTerminated where call didn't started
-
- PropertyChanged(string name, variant value)
+Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
property.
-properties boolean Connected [readonly]
-
- Indicates if there is an active connection to the
- AG service on the remote device.
-
- uint16 RegistrationStatus [readonly]
-
- Service availability indicator of AG, where:
- 0 implies no service. No Home/Roam network available.
- 1 implies presence of service. Home/Roam network
- available.
-
- uint16 SignalStrength [readonly]
-
- Signal strength indicator of AG, the value ranges from
- 0 to 5.
-
- uint16 RoamingStatus [readonly]
+properties string State [readonly]
- Roaming status indicator of AG, where:
- 0 means roaming is not active
- 1 means a roaming is active
+ Possible values: "disconnected", "connecting",
+ "connected", "playing"
- uint16 BatteryCharge [readonly]
+ "disconnected" -> "connecting"
+ Either an incoming or outgoing connection
+ attempt ongoing.
- Battery Charge indicator of AG, the value ranges from
- 0 to 5.
+ "connecting" -> "disconnected"
+ Connection attempt failed
- uint16 SpeakerGain [readonly]
+ "connecting" -> "connected"
+ Successfully connected
- The speaker gain when available.
+ "connected" -> "playing"
+ SCO audio connection successfully opened
- uint16 MicrophoneGain [readonly]
+ "playing" -> "connected"
+ SCO audio connection closed
- The speaker gain when available.
+ "connected" -> "disconnected"
+ "playing" -> "disconnected"
+ Disconnected from the remote device
Telephony hierarchy
diff --git a/doc/media-api.txt b/doc/media-api.txt
index e5eeaa0..4a3afd2 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -326,15 +326,12 @@ Properties object Device [readonly]
boolean NREC [readwrite]
Optional. Indicates if echo cancelling and noise
- reduction functions are active in the transport, this
- property is only writeable when the transport was
- acquired by the sender.
+ reduction functions are active in the transport.
boolean InbandRingtone [readwrite]
Optional. Indicates if the transport support sending
- ringtones, this property is only writeable when the
- transport was acquired by the sender.
+ ringtones.
string Routing [readonly]
@@ -349,3 +346,15 @@ Properties object Device [readonly]
acquired by the sender.
Possible Values: 0-127
+
+ uint16 OutputGain [readwrite]
+
+ Optional. The speaker gain when available.
+
+ Possible values: 0-15
+
+ uint16 InputGain [readwrite]
+
+ Optional. The microphone gain when available.
+
+ Possible values: 0-15
--
1.7.9.5
^ permalink raw reply related
* [PATCH v16 04/14] audio: Remove dummy telephony driver
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1343812131-19395-1-git-send-email-frederic.danis@linux.intel.com>
Remove dummy telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
audio/telephony-dummy.c | 447 -----------------------------------------------
1 file changed, 447 deletions(-)
delete mode 100644 audio/telephony-dummy.c
diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
deleted file mode 100644
index 2f89139..0000000
--- a/audio/telephony-dummy.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2006-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-#define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
-#define TELEPHONY_DUMMY_PATH "/org/bluez/test"
-
-static DBusConnection *connection = NULL;
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-static char *active_call_number = NULL;
-static int active_call_status = 0;
-static int active_call_dir = 0;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator dummy_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 5, TRUE },
- { "service", "0,1", 1, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-void telephony_device_connected(void *telephony_device)
-{
- DBG("telephony-dummy: device %p connected", telephony_device);
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-dummy: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
-
- /* Notify outgoing call set-up successfully initiated */
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- g_free(active_call_number);
- active_call_number = NULL;
-
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-
- if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- else
- telephony_update_indicator(dummy_indicators, "call",
- EV_CALL_INACTIVE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-
- telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
-
- active_call_status = CALL_STATUS_ACTIVE;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- DBG("telephony-dummy: dial request to %s", active_call_number);
-
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
- /* Notify outgoing call set-up successfully initiated */
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- DBG("telephony-dummy: transmit dtmf: %c", tone);
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-dummy: subscriber number request");
- if (subscriber_number)
- telephony_subscriber_number_ind(subscriber_number,
- NUMBER_TYPE_TELEPHONY,
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- DBG("telephony-dummy: list current calls request");
- if (active_call_number)
- telephony_list_current_call_ind(1, active_call_dir,
- active_call_status,
- CALL_MODE_VOICE,
- CALL_MULTIPARTY_NO,
- active_call_number,
- NUMBER_TYPE_TELEPHONY);
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- DBG("telephony-dymmy: got call hold request %s", cmd);
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-dummy: got %s NR and EC request",
- enable ? "enable" : "disable");
-
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-dummy: got %s voice dial request",
- enable ? "enable" : "disable");
-
- g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE, "VoiceDial",
- DBUS_TYPE_INVALID);
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- DBG("telephony-dummy: got key press request for %s", keys);
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-/* D-Bus method handlers */
-static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- DBG("telephony-dummy: outgoing call to %s", number);
-
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
-
- active_call_status = CALL_STATUS_ALERTING;
- active_call_dir = CALL_DIR_OUTGOING;
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- DBG("telephony-dummy: incoming call to %s", number);
-
- g_free(active_call_number);
- active_call_number = g_strdup(number);
-
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
-
- active_call_status = CALL_STATUS_INCOMING;
- active_call_dir = CALL_DIR_INCOMING;
-
- telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- DBG("telephony-dummy: cancel call");
-
- g_free(active_call_number);
- active_call_number = NULL;
-
- if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
- telephony_update_indicator(dummy_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- telephony_calling_stopped_ind();
- }
-
- if (telephony_get_indicator(dummy_indicators, "call") > 0)
- telephony_update_indicator(dummy_indicators, "call",
- EV_CALL_INACTIVE);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_uint32_t strength;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- if (strength > 5)
- return btd_error_invalid_args(msg);
-
- telephony_update_indicator(dummy_indicators, "signal", strength);
-
- DBG("telephony-dummy: signal strength set to %u", strength);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_uint32_t level;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- if (level > 5)
- return btd_error_invalid_args(msg);
-
- telephony_update_indicator(dummy_indicators, "battchg", level);
-
- DBG("telephony-dummy: battery level set to %u", level);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_bool_t roaming;
- int val;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
-
- telephony_update_indicator(dummy_indicators, "roam", val);
-
- DBG("telephony-dummy: roaming status set to %d", val);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- dbus_bool_t registration;
- int val;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, ®istration,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
-
- telephony_update_indicator(dummy_indicators, "service", val);
-
- DBG("telephony-dummy: registration status set to %d", val);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_subscriber_number(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- const char *number;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- g_free(subscriber_number);
- subscriber_number = g_strdup(number);
-
- DBG("telephony-dummy: subscriber number set to %s", number);
-
- return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable dummy_methods[] = {
- { GDBUS_METHOD("OutgoingCall",
- GDBUS_ARGS({ "number", "s" }), NULL,
- outgoing_call) },
- { GDBUS_METHOD("IncomingCall",
- GDBUS_ARGS({ "number", "s" }), NULL,
- incoming_call) },
- { GDBUS_METHOD("CancelCall", NULL, NULL, cancel_call) },
- { GDBUS_METHOD("SignalStrength",
- GDBUS_ARGS({ "strength", "u" }), NULL,
- signal_strength) },
- { GDBUS_METHOD("BatteryLevel",
- GDBUS_ARGS({ "level", "u" }), NULL,
- battery_level) },
- { GDBUS_METHOD("RoamingStatus",
- GDBUS_ARGS({ "roaming", "b" }), NULL,
- roaming_status) },
- { GDBUS_METHOD("RegistrationStatus",
- GDBUS_ARGS({ "registration", "b" }), NULL,
- registration_status) },
- { GDBUS_METHOD("SetSubscriberNumber",
- GDBUS_ARGS({ "number", "s" }), NULL,
- set_subscriber_number) },
- { }
-};
-
-static const GDBusSignalTable dummy_signals[] = {
- { GDBUS_SIGNAL("VoiceDial", NULL) },
- { }
-};
-
-int telephony_init(void)
-{
- uint32_t features = AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
-
- DBG("");
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE,
- dummy_methods, dummy_signals,
- NULL, NULL, NULL) == FALSE) {
- error("telephony-dummy interface %s init failed on path %s",
- TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
- return -1;
- }
-
- telephony_ready_ind(features, dummy_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
-
- return 0;
-}
-
-void telephony_exit(void)
-{
- DBG("");
-
- g_dbus_unregister_interface(connection, TELEPHONY_DUMMY_PATH,
- TELEPHONY_DUMMY_IFACE);
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v16 05/14] audio: Remove maemo5 telephony driver
From: Frédéric Danis @ 2012-08-01 9:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1343812131-19395-1-git-send-email-frederic.danis@linux.intel.com>
Remove Maemo 5 telephony driver which has been deprecated by
org.bluez.Telephony interface.
---
audio/telephony-maemo5.c | 2105 ----------------------------------------------
1 file changed, 2105 deletions(-)
delete mode 100644 audio/telephony-maemo5.c
diff --git a/audio/telephony-maemo5.c b/audio/telephony-maemo5.c
deleted file mode 100644
index 8a00296..0000000
--- a/audio/telephony-maemo5.c
+++ /dev/null
@@ -1,2105 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define NETWORK_BUS_NAME "com.nokia.phone.net"
-#define NETWORK_INTERFACE "Phone.Net"
-#define NETWORK_PATH "/com/nokia/phone/net"
-
-/* Mask bits for supported services */
-#define NETWORK_MASK_GPRS_SUPPORT 0x01
-#define NETWORK_MASK_CS_SERVICES 0x02
-#define NETWORK_MASK_EGPRS_SUPPORT 0x04
-#define NETWORK_MASK_HSDPA_AVAIL 0x08
-#define NETWORK_MASK_HSUPA_AVAIL 0x10
-
-/* network get cell info: cell type */
-#define NETWORK_UNKNOWN_CELL 0
-#define NETWORK_GSM_CELL 1
-#define NETWORK_WCDMA_CELL 2
-
-enum net_registration_status {
- NETWORK_REG_STATUS_HOME = 0x00,
- NETWORK_REG_STATUS_ROAM,
- NETWORK_REG_STATUS_ROAM_BLINK,
- NETWORK_REG_STATUS_NOSERV,
- NETWORK_REG_STATUS_NOSERV_SEARCHING,
- NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
- NETWORK_REG_STATUS_NOSERV_NOSIM,
- NETWORK_REG_STATUS_POWER_OFF = 0x08,
- NETWORK_REG_STATUS_NSPS,
- NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
- NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
-};
-
-enum network_types {
- NETWORK_GSM_HOME_PLMN = 0,
- NETWORK_GSM_PREFERRED_PLMN,
- NETWORK_GSM_FORBIDDEN_PLMN,
- NETWORK_GSM_OTHER_PLMN,
- NETWORK_GSM_NO_PLMN_AVAIL
-};
-
-enum network_alpha_tag_name_type {
- NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
- NETWORK_HARDCODED_USC2_OPER_NAME,
- NETWORK_NITZ_SHORT_OPER_NAME,
- NETWORK_NITZ_FULL_OPER_NAME,
-};
-
-#define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony"
-#define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony"
-
-#define CALLERID_BASE "/var/lib/bluetooth/maemo-callerid-"
-#define ALLOWED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-allowed"
-#define RESTRICTED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-restricted"
-#define NONE_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-none"
-
-static uint32_t callerid = 0;
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE "com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH "/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE 0
-#define CSD_CALL_STATUS_CREATE 1
-#define CSD_CALL_STATUS_COMING 2
-#define CSD_CALL_STATUS_PROCEEDING 3
-#define CSD_CALL_STATUS_MO_ALERTING 4
-#define CSD_CALL_STATUS_MT_ALERTING 5
-#define CSD_CALL_STATUS_WAITING 6
-#define CSD_CALL_STATUS_ANSWERED 7
-#define CSD_CALL_STATUS_ACTIVE 8
-#define CSD_CALL_STATUS_MO_RELEASE 9
-#define CSD_CALL_STATUS_MT_RELEASE 10
-#define CSD_CALL_STATUS_HOLD_INITIATED 11
-#define CSD_CALL_STATUS_HOLD 12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
-#define CSD_CALL_STATUS_RECONNECT_PENDING 14
-#define CSD_CALL_STATUS_TERMINATED 15
-#define CSD_CALL_STATUS_SWAP_INITIATED 16
-
-#define CALL_FLAG_NONE 0
-#define CALL_FLAG_PRESENTATION_ALLOWED 0x01
-#define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
-
-/* SIM Phonebook D-Bus definitions */
-#define SIM_PHONEBOOK_BUS_NAME "com.nokia.phone.SIM"
-#define SIM_PHONEBOOK_INTERFACE "Phone.Sim.Phonebook"
-#define SIM_PHONEBOOK_PATH "/com/nokia/phone/SIM/phonebook"
-
-#define PHONEBOOK_INDEX_FIRST_ENTRY 0xFFFF
-#define PHONEBOOK_INDEX_NEXT_FREE_LOCATION 0xFFFE
-
-enum sim_phonebook_type {
- SIM_PHONEBOOK_TYPE_ADN = 0x0,
- SIM_PHONEBOOK_TYPE_SDN,
- SIM_PHONEBOOK_TYPE_FDN,
- SIM_PHONEBOOK_TYPE_VMBX,
- SIM_PHONEBOOK_TYPE_MBDN,
- SIM_PHONEBOOK_TYPE_EN,
- SIM_PHONEBOOK_TYPE_MSISDN
-};
-
-enum sim_phonebook_location_type {
- SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
- SIM_PHONEBOOK_LOCATION_NEXT
-};
-
-struct csd_call {
- char *object_path;
- int status;
- gboolean originating;
- gboolean emergency;
- gboolean on_hold;
- gboolean conference;
- char *number;
- gboolean setup;
-};
-
-static struct {
- uint8_t status;
- uint16_t lac;
- uint32_t cell_id;
- uint32_t operator_code;
- uint32_t country_code;
- uint8_t network_type;
- uint8_t supported_services;
- uint16_t signals_bar;
- char *operator_name;
-} net = {
- .status = NETWORK_REG_STATUS_NOSERV,
- .lac = 0,
- .cell_id = 0,
- .operator_code = 0,
- .country_code = 0,
- .network_type = NETWORK_GSM_NO_PLMN_AVAIL,
- .supported_services = 0,
- .signals_bar = 0,
- .operator_name = NULL,
-};
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-static char *msisdn = NULL; /* Subscriber number */
-static char *vmbx = NULL; /* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1; /* "battery.charge_level.current" */
-static int battchg_last = -1; /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-static char *last_dialed_number = NULL;
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
- { "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 0, TRUE },
- { "service", "0,1", 0, TRUE },
- { "call", "0,1", 0, TRUE },
- { "callsetup", "0-3", 0, TRUE },
- { "callheld", "0-2", 0, FALSE },
- { "roam", "0,1", 0, TRUE },
- { NULL }
-};
-
-static char *call_status_str[] = {
- "IDLE",
- "CREATE",
- "COMING",
- "PROCEEDING",
- "MO_ALERTING",
- "MT_ALERTING",
- "WAITING",
- "ANSWERED",
- "ACTIVE",
- "MO_RELEASE",
- "MT_RELEASE",
- "HOLD_INITIATED",
- "HOLD",
- "RETRIEVE_INITIATED",
- "RECONNECT_PENDING",
- "TERMINATED",
- "SWAP_INITIATED",
- "???"
-};
-
-static struct csd_call *find_call(const char *path)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (g_str_equal(call->object_path, path))
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == CSD_CALL_STATUS_IDLE)
- continue;
-
- if (call->status != CSD_CALL_STATUS_HOLD)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status != CSD_CALL_STATUS_IDLE)
- return call;
- }
-
- return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- return call;
- }
-
- return NULL;
-}
-
-static int release_conference(void)
-{
- DBusMessage *msg;
-
- DBG("telephony-maemo: releasing conference call");
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- CSD_CALL_CONFERENCE_PATH,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Release");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Answer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
- call->object_path,
- CSD_CALL_INSTANCE,
- "Split");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Unhold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Hold");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int swap_calls(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Swap");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int create_conference(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Conference");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int call_transfer(void)
-{
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE,
- "Transfer");
- if (!msg) {
- error("Unable to allocate new D-Bus message");
- return -ENOMEM;
- }
-
- g_dbus_send_message(connection, msg);
-
- return 0;
-}
-
-static int number_type(const char *number)
-{
- if (number == NULL)
- return NUMBER_TYPE_TELEPHONY;
-
- if (number[0] == '+' || strncmp(number, "00", 2) == 0)
- return NUMBER_TYPE_INTERNATIONAL;
-
- return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
- struct csd_call *coming;
-
- DBG("telephony-maemo: device %p connected", telephony_device);
-
- coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (coming) {
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(coming->number,
- number_type(coming->number));
- else
- telephony_incoming_call_ind(coming->number,
- number_type(coming->number));
- }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
- DBG("telephony-maemo: device %p disconnected", telephony_device);
- events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
- events_enabled = ind == 1 ? TRUE : FALSE;
-
- telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
- telephony_response_and_hold_rsp(telephony_device,
- CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
- DBG("telephony-maemo: last dialed number request");
-
- if (last_dialed_number)
- telephony_dial_number_req(telephony_device,
- last_dialed_number);
- else
- telephony_last_dialed_number_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
- struct csd_call *call;
- int err;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- if (!call)
- call = find_non_idle_call();
-
- if (!call) {
- error("No active call");
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- if (call->conference)
- err = release_conference();
- else
- err = release_call(call);
-
- if (err < 0)
- telephony_terminate_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
- struct csd_call *call;
-
- call = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- if (!call)
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (!call) {
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_NOT_ALLOWED);
- return;
- }
-
- if (answer_call(call) < 0)
- telephony_answer_call_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int send_method_call(const char *dest, const char *path,
- const char *interface, const char *method,
- DBusPendingCallNotifyFunction cb,
- void *user_data, int type, ...)
-{
- DBusMessage *msg;
- DBusPendingCall *call;
- va_list args;
-
- msg = dbus_message_new_method_call(dest, path, interface, method);
- if (!msg) {
- error("Unable to allocate new D-Bus %s message", method);
- return -ENOMEM;
- }
-
- va_start(args, type);
-
- if (!dbus_message_append_args_valist(msg, type, args)) {
- dbus_message_unref(msg);
- va_end(args);
- return -EIO;
- }
-
- va_end(args);
-
- if (!cb) {
- g_dbus_send_message(connection, msg);
- return 0;
- }
-
- if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
- error("Sending %s failed", method);
- dbus_message_unref(msg);
- return -EIO;
- }
-
- dbus_pending_call_set_notify(call, cb, user_data, NULL);
- dbus_pending_call_unref(call);
- dbus_message_unref(msg);
-
- return 0;
-}
-
-static const char *memory_dial_lookup(int location)
-{
- if (location == 1)
- return vmbx;
- else
- return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
- uint32_t flags = callerid;
- int ret;
-
- DBG("telephony-maemo: dial request to %s", number);
-
- if (strncmp(number, "*31#", 4) == 0) {
- number += 4;
- flags = CALL_FLAG_PRESENTATION_ALLOWED;
- } else if (strncmp(number, "#31#", 4) == 0) {
- number += 4;
- flags = CALL_FLAG_PRESENTATION_RESTRICTED;
- } else if (number[0] == '>') {
- const char *location = &number[1];
-
- number = memory_dial_lookup(strtol(&number[1], NULL, 0));
- if (!number) {
- error("No number at memory location %s", location);
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_INVALID_INDEX);
- return;
- }
- }
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "CreateWith",
- NULL, NULL,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- telephony_dial_number_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
- int ret;
- char buf[2] = { tone, '\0' }, *buf_ptr = buf;
-
- DBG("telephony-maemo: transmit dtmf: %s", buf);
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "SendDTMF",
- NULL, NULL,
- DBUS_TYPE_STRING, &buf_ptr,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- telephony_transmit_dtmf_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- return;
- }
-
- telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
- DBG("telephony-maemo: subscriber number request");
- if (msisdn)
- telephony_subscriber_number_ind(msisdn,
- number_type(msisdn),
- SUBSCRIBER_SERVICE_VOICE);
- telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
- switch (call->status) {
- case CSD_CALL_STATUS_IDLE:
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- case CSD_CALL_STATUS_TERMINATED:
- return -1;
- case CSD_CALL_STATUS_CREATE:
- return CALL_STATUS_DIALING;
- case CSD_CALL_STATUS_WAITING:
- return CALL_STATUS_WAITING;
- case CSD_CALL_STATUS_PROCEEDING:
- /* PROCEEDING can happen in outgoing/incoming */
- if (call->originating)
- return CALL_STATUS_DIALING;
- else
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_COMING:
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_MO_ALERTING:
- return CALL_STATUS_ALERTING;
- case CSD_CALL_STATUS_MT_ALERTING:
- return CALL_STATUS_INCOMING;
- case CSD_CALL_STATUS_ANSWERED:
- case CSD_CALL_STATUS_ACTIVE:
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- case CSD_CALL_STATUS_SWAP_INITIATED:
- case CSD_CALL_STATUS_HOLD_INITIATED:
- return CALL_STATUS_ACTIVE;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- case CSD_CALL_STATUS_HOLD:
- return CALL_STATUS_HELD;
- default:
- return -1;
- }
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
- GSList *l;
- int i;
-
- DBG("telephony-maemo: list current calls request");
-
- for (l = calls, i = 1; l != NULL; l = l->next, i++) {
- struct csd_call *call = l->data;
- int status, direction, multiparty;
-
- status = csd_status_to_hfp(call);
- if (status < 0)
- continue;
-
- direction = call->originating ?
- CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
- multiparty = call->conference ?
- CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
- telephony_list_current_call_ind(i, direction, status,
- CALL_MODE_VOICE, multiparty,
- call->number,
- number_type(call->number));
- }
-
- telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
- telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
- net.operator_name ? net.operator_name : "");
- telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_call_with_status(int status,
- int (*func)(struct csd_call *call))
-{
- GSList *l;
-
- for (l = calls; l != NULL; l = l->next) {
- struct csd_call *call = l->data;
-
- if (call->status == status)
- func(call);
- }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
- const char *idx;
- struct csd_call *call;
- int err = 0;
-
- DBG("telephony-maemo: got call hold request %s", cmd);
-
- if (strlen(cmd) > 1)
- idx = &cmd[1];
- else
- idx = NULL;
-
- if (idx)
- call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
- else
- call = NULL;
-
- switch (cmd[0]) {
- case '0':
- foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call);
- foreach_call_with_status(CSD_CALL_STATUS_WAITING,
- release_call);
- break;
- case '1':
- if (idx) {
- if (call)
- err = release_call(call);
- break;
- }
- foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
- call = find_call_with_status(CSD_CALL_STATUS_WAITING);
- if (call)
- err = answer_call(call);
- break;
- case '2':
- if (idx) {
- if (call)
- err = split_call(call);
- } else {
- struct csd_call *held, *wait;
-
- call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
- held = find_call_with_status(CSD_CALL_STATUS_HOLD);
- wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
- if (wait)
- err = answer_call(wait);
- else if (call && held)
- err = swap_calls();
- else {
- if (call)
- err = hold_call(call);
- if (held)
- err = unhold_call(held);
- }
- }
- break;
- case '3':
- if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
- find_call_with_status(CSD_CALL_STATUS_WAITING))
- err = create_conference();
- break;
- case '4':
- err = call_transfer();
- break;
- default:
- DBG("Unknown call hold request");
- break;
- }
-
- if (err)
- telephony_call_hold_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo: got %s NR and EC request",
- enable ? "enable" : "disable");
- telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
- struct csd_call *active, *waiting;
- int err;
-
- DBG("telephony-maemo: got key press request for %s", keys);
-
- waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
- if (!waiting)
- waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
- active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
- if (waiting)
- err = answer_call(waiting);
- else if (active)
- err = release_call(active);
- else
- err = 0;
-
- if (err < 0)
- telephony_key_press_rsp(telephony_device,
- CME_ERROR_AG_FAILURE);
- else
- telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
- DBG("telephony-maemo: got %s voice dial request",
- enable ? "enable" : "disable");
-
- telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Coming() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Incoming call to %s from number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INCOMING);
-
- if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
- telephony_call_waiting_ind(call->number,
- number_type(call->number));
- else
- telephony_incoming_call_ind(call->number,
- number_type(call->number));
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
- const char *number, *call_path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &call_path,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Call.Created() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- DBG("Outgoing call from %s to number %s", call_path, number);
-
- g_free(call->number);
- call->number = g_strdup(number);
-
- g_free(last_dialed_number);
- last_dialed_number = g_strdup(number);
-
- if (create_request_timer) {
- g_source_remove(create_request_timer);
- create_request_timer = 0;
- }
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_INACTIVE);
- create_request_timer = 0;
- return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
- DBG("Call.CreateRequested()");
-
- if (create_request_timer)
- g_source_remove(create_request_timer);
-
- create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_OUTGOING);
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
- struct csd_call *call;
- dbus_uint32_t status, cause_type, cause;
- int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_UINT32, &cause_type,
- DBUS_TYPE_UINT32, &cause,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Instance.CallStatus() signal");
- return;
- }
-
- call = find_call(call_path);
- if (!call) {
- error("Didn't find any matching call object for %s",
- call_path);
- return;
- }
-
- if (status > 16) {
- error("Invalid call status %u", status);
- return;
- }
-
- DBG("Call %s changed from %s to %s", call_path,
- call_status_str[call->status], call_status_str[status]);
-
- if (call->status == (int) status) {
- DBG("Ignoring CSD Call state change to existing state");
- return;
- }
-
- call->status = (int) status;
-
- switch (status) {
- case CSD_CALL_STATUS_IDLE:
- if (call->setup) {
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- }
-
- g_free(call->number);
- call->number = NULL;
- call->originating = FALSE;
- call->emergency = FALSE;
- call->on_hold = FALSE;
- call->conference = FALSE;
- call->setup = FALSE;
- break;
- case CSD_CALL_STATUS_CREATE:
- call->originating = TRUE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_COMING:
- call->originating = FALSE;
- call->setup = TRUE;
- break;
- case CSD_CALL_STATUS_PROCEEDING:
- break;
- case CSD_CALL_STATUS_MO_ALERTING:
- telephony_update_indicator(maemo_indicators, "callsetup",
- EV_CALLSETUP_ALERTING);
- break;
- case CSD_CALL_STATUS_MT_ALERTING:
- break;
- case CSD_CALL_STATUS_WAITING:
- break;
- case CSD_CALL_STATUS_ANSWERED:
- break;
- case CSD_CALL_STATUS_ACTIVE:
- if (call->on_hold) {
- call->on_hold = FALSE;
- if (find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- } else {
- if (!g_slist_find(active_calls, call))
- active_calls = g_slist_prepend(active_calls, call);
- if (g_slist_length(active_calls) == 1)
- telephony_update_indicator(maemo_indicators,
- "call",
- EV_CALL_ACTIVE);
- /* Upgrade callheld status if necessary */
- if (callheld == EV_CALLHELD_ON_HOLD)
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- telephony_update_indicator(maemo_indicators,
- "callsetup",
- EV_CALLSETUP_INACTIVE);
- if (!call->originating)
- telephony_calling_stopped_ind();
- call->setup = FALSE;
- }
- break;
- case CSD_CALL_STATUS_MO_RELEASE:
- case CSD_CALL_STATUS_MT_RELEASE:
- active_calls = g_slist_remove(active_calls, call);
- if (g_slist_length(active_calls) == 0)
- telephony_update_indicator(maemo_indicators, "call",
- EV_CALL_INACTIVE);
- break;
- case CSD_CALL_STATUS_HOLD_INITIATED:
- break;
- case CSD_CALL_STATUS_HOLD:
- call->on_hold = TRUE;
- if (find_non_held_call())
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_MULTIPLE);
- else
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_RETRIEVE_INITIATED:
- break;
- case CSD_CALL_STATUS_RECONNECT_PENDING:
- break;
- case CSD_CALL_STATUS_TERMINATED:
- if (call->on_hold &&
- !find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_NONE);
- else if (callheld == EV_CALLHELD_MULTIPLE &&
- find_call_with_status(CSD_CALL_STATUS_HOLD))
- telephony_update_indicator(maemo_indicators,
- "callheld",
- EV_CALLHELD_ON_HOLD);
- break;
- case CSD_CALL_STATUS_SWAP_INITIATED:
- break;
- default:
- error("Unknown call status %u", status);
- break;
- }
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
- const char *path;
- struct csd_call *call;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in Conference.%s",
- dbus_message_get_member(msg));
- return;
- }
-
- call = find_call(path);
- if (!call) {
- error("Conference signal for unknown call %s", path);
- return;
- }
-
- DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
- call->conference = joined;
-}
-
-static void get_operator_name_reply(DBusPendingCall *pending_call,
- void *user_data)
-{
- DBusMessage *reply;
- DBusError err;
- const char *name;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(pending_call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("get_operator_name failed: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unexpected get_operator_name reply parameters: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- if (net_err != 0) {
- error("get_operator_name failed with code %d", net_err);
- goto done;
- }
-
- if (strlen(name) == 0)
- goto done;
-
- g_free(net.operator_name);
- net.operator_name = g_strdup(name);
-
- DBG("telephony-maemo: operator name updated: %s", name);
-
-done:
- dbus_message_unref(reply);
-}
-
-static void resolve_operator_name(uint32_t operator, uint32_t country)
-{
- uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
-
- send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_operator_name",
- get_operator_name_reply, NULL,
- DBUS_TYPE_BYTE, &name_type,
- DBUS_TYPE_UINT32, &operator,
- DBUS_TYPE_UINT32, &country,
- DBUS_TYPE_INVALID);
-}
-
-static void update_registration_status(uint8_t status, uint16_t lac,
- uint32_t cell_id,
- uint32_t operator_code,
- uint32_t country_code,
- uint8_t network_type,
- uint8_t supported_services)
-{
- if (net.status != status) {
- switch (status) {
- case NETWORK_REG_STATUS_HOME:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_INACTIVE);
- if (net.status >= NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_ROAM:
- case NETWORK_REG_STATUS_ROAM_BLINK:
- telephony_update_indicator(maemo_indicators, "roam",
- EV_ROAM_ACTIVE);
- if (net.status >= NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_PRESENT);
- break;
- case NETWORK_REG_STATUS_NOSERV:
- case NETWORK_REG_STATUS_NOSERV_SEARCHING:
- case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
- case NETWORK_REG_STATUS_NOSERV_NOSIM:
- case NETWORK_REG_STATUS_POWER_OFF:
- case NETWORK_REG_STATUS_NSPS:
- case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
- case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
- if (net.status < NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
- "service",
- EV_SERVICE_NONE);
- break;
- }
-
- net.status = status;
- }
-
- net.lac = lac;
- net.cell_id = cell_id;
-
- if (net.operator_code != operator_code ||
- net.country_code != country_code) {
- g_free(net.operator_name);
- net.operator_name = NULL;
- resolve_operator_name(operator_code, country_code);
- net.operator_code = operator_code;
- net.country_code = country_code;
- }
-
- net.network_type = network_type;
- net.supported_services = supported_services;
-}
-
-static void handle_registration_status_change(DBusMessage *msg)
-{
- uint8_t status;
- dbus_uint16_t lac, network_type, supported_services;
- dbus_uint32_t cell_id, operator_code, country_code;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_BYTE, &status,
- DBUS_TYPE_UINT16, &lac,
- DBUS_TYPE_UINT32, &cell_id,
- DBUS_TYPE_UINT32, &operator_code,
- DBUS_TYPE_UINT32, &country_code,
- DBUS_TYPE_BYTE, &network_type,
- DBUS_TYPE_BYTE, &supported_services,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in registration_status_change");
- return;
- }
-
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
-}
-
-static void update_signal_strength(uint8_t signals_bar)
-{
- int signal;
-
- if (signals_bar > 100) {
- DBG("signals_bar greater than expected: %u", signals_bar);
- signals_bar = 100;
- }
-
- if (net.signals_bar == signals_bar)
- return;
-
- /* A simple conversion from 0-100 to 0-5 (used by HFP) */
- signal = (signals_bar + 20) / 21;
-
- telephony_update_indicator(maemo_indicators, "signal", signal);
-
- net.signals_bar = signals_bar;
-
- DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
-}
-
-static void handle_signal_strength_change(DBusMessage *msg)
-{
- uint8_t signals_bar, rssi_in_dbm;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_BYTE, &signals_bar,
- DBUS_TYPE_BYTE, &rssi_in_dbm,
- DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in signal_strength_change");
- return;
- }
-
- update_signal_strength(signals_bar);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
- int first_arg_type, ...)
-{
- int type;
- va_list ap;
-
- va_start(ap, first_arg_type);
-
- for (type = first_arg_type; type != DBUS_TYPE_INVALID;
- type = va_arg(ap, int)) {
- void *value = va_arg(ap, void *);
- int real_type = dbus_message_iter_get_arg_type(iter);
-
- if (real_type != type) {
- error("iter_get_basic_args: expected %c but got %c",
- (char) type, (char) real_type);
- break;
- }
-
- dbus_message_iter_get_basic(iter, value);
- dbus_message_iter_next(iter);
- }
-
- va_end(ap);
-
- return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- dbus_int32_t level;
- int *value = user_data;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (dbus_message_get_args(reply, &err,
- DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse GetPropertyInteger reply: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- *value = (int) level;
-
- if (value == &battchg_last)
- DBG("telephony-maemo: battery.charge_level.last_full is %d",
- *value);
- else if (value == &battchg_design)
- DBG("telephony-maemo: battery.charge_level.design is %d",
- *value);
- else
- DBG("telephony-maemo: battery.charge_level.current is %d",
- *value);
-
- if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
- int new, max;
-
- if (battchg_last > 0)
- max = battchg_last;
- else
- max = battchg_design;
-
- new = battchg_cur * 5 / max;
-
- telephony_update_indicator(maemo_indicators, "battchg", new);
- }
-done:
- dbus_message_unref(reply);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
- send_method_call("org.freedesktop.Hal", path,
- "org.freedesktop.Hal.Device",
- "GetPropertyInteger",
- hal_battery_level_reply, user_data,
- DBUS_TYPE_STRING, &key,
- DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
- DBusMessageIter iter, array;
- dbus_int32_t num_changes;
- const char *path;
-
- path = dbus_message_get_path(msg);
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_get_basic(&iter, &num_changes);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in hal PropertyModified signal");
- return;
- }
-
- dbus_message_iter_recurse(&iter, &array);
-
- while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
- DBusMessageIter prop;
- const char *name;
- dbus_bool_t added, removed;
-
- dbus_message_iter_recurse(&array, &prop);
-
- if (!iter_get_basic_args(&prop,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &added,
- DBUS_TYPE_BOOLEAN, &removed,
- DBUS_TYPE_INVALID)) {
- error("Invalid hal PropertyModified parameters");
- break;
- }
-
- if (g_str_equal(name, "battery.charge_level.last_full"))
- hal_get_integer(path, name, &battchg_last);
- else if (g_str_equal(name, "battery.charge_level.current"))
- hal_get_integer(path, name, &battchg_cur);
- else if (g_str_equal(name, "battery.charge_level.design"))
- hal_get_integer(path, name, &battchg_design);
-
- dbus_message_iter_next(&array);
- }
-}
-
-static void csd_call_free(struct csd_call *call)
-{
- if (!call)
- return;
-
- g_free(call->object_path);
- g_free(call->number);
-
- g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
- do {
- DBusMessageIter call_iter;
- struct csd_call *call;
- const char *object_path, *number;
- dbus_uint32_t status;
- dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
- error("Unexpected signature in GetCallInfoAll reply");
- break;
- }
-
- dbus_message_iter_recurse(iter, &call_iter);
-
- if (!iter_get_basic_args(&call_iter,
- DBUS_TYPE_OBJECT_PATH, &object_path,
- DBUS_TYPE_UINT32, &status,
- DBUS_TYPE_BOOLEAN, &originating,
- DBUS_TYPE_BOOLEAN, &terminating,
- DBUS_TYPE_BOOLEAN, &emerg,
- DBUS_TYPE_BOOLEAN, &on_hold,
- DBUS_TYPE_BOOLEAN, &conf,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID)) {
- error("Parsing call D-Bus parameters failed");
- break;
- }
-
- call = find_call(object_path);
- if (!call) {
- call = g_new0(struct csd_call, 1);
- call->object_path = g_strdup(object_path);
- call->status = (int) status;
- calls = g_slist_append(calls, call);
- DBG("telephony-maemo: new csd call instance at %s",
- object_path);
- }
-
- if (call->status == CSD_CALL_STATUS_IDLE)
- continue;
-
- /* CSD gives incorrect call_hold property sometimes */
- if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
- (call->status == CSD_CALL_STATUS_HOLD &&
- !on_hold)) {
- error("Conflicting call status and on_hold property!");
- on_hold = call->status == CSD_CALL_STATUS_HOLD;
- }
-
- call->originating = originating;
- call->on_hold = on_hold;
- call->conference = conf;
- g_free(call->number);
- call->number = g_strdup(number);
-
- } while (dbus_message_iter_next(iter));
-}
-
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- uint8_t signals_bar, rssi_in_dbm;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("Unable to get signal strength: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_BYTE, &signals_bar,
- DBUS_TYPE_BYTE, &rssi_in_dbm,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unable to parse signal_strength reply: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- if (net_err != 0) {
- error("get_signal_strength failed with code %d", net_err);
- goto done;
- }
-
- update_signal_strength(signals_bar);
-
-done:
- dbus_message_unref(reply);
-}
-
-static int get_signal_strength(void)
-{
- return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_signal_strength",
- signal_strength_reply, NULL,
- DBUS_TYPE_INVALID);
-}
-
-static void registration_status_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- uint8_t status;
- dbus_uint16_t lac, network_type, supported_services;
- dbus_uint32_t cell_id, operator_code, country_code;
- dbus_int32_t net_err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("Unable to get registration status: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_BYTE, &status,
- DBUS_TYPE_UINT16, &lac,
- DBUS_TYPE_UINT32, &cell_id,
- DBUS_TYPE_UINT32, &operator_code,
- DBUS_TYPE_UINT32, &country_code,
- DBUS_TYPE_BYTE, &network_type,
- DBUS_TYPE_BYTE, &supported_services,
- DBUS_TYPE_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unable to parse registration_status_change reply:"
- " %s, %s", err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- if (net_err != 0) {
- error("get_registration_status failed with code %d", net_err);
- goto done;
- }
-
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
-
- get_signal_strength();
-
-done:
- dbus_message_unref(reply);
-}
-
-static int get_registration_status(void)
-{
- return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_registration_status",
- registration_status_reply, NULL,
- DBUS_TYPE_INVALID);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
-
- get_calls_active = FALSE;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("csd replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in GetCallInfoAll return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- parse_call_list(&sub);
-
- get_registration_status();
-
-done:
- dbus_message_unref(reply);
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError err;
- DBusMessage *reply;
- DBusMessageIter iter, sub;
- const char *path;
- char match_string[256];
- int type;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("hald replied with an error: %s, %s",
- err.name, err.message);
- dbus_error_free(&err);
- goto done;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in FindDeviceByCapability return");
- goto done;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- type = dbus_message_iter_get_arg_type(&sub);
-
- if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
- error("No hal device with battery capability found");
- goto done;
- }
-
- dbus_message_iter_get_basic(&sub, &path);
-
- DBG("telephony-maemo: found battery device at %s", path);
-
- snprintf(match_string, sizeof(match_string),
- "type='signal',"
- "path='%s',"
- "interface='org.freedesktop.Hal.Device',"
- "member='PropertyModified'", path);
- dbus_bus_add_match(connection, match_string, NULL);
-
- hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
- hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
- hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
- dbus_message_unref(reply);
-}
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError derr;
- DBusMessage *reply;
- const char *name, *number;
- char **number_type = user_data;
- dbus_int32_t current_location, err;
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- error("SIM.Phonebook replied with an error: %s, %s",
- derr.name, derr.message);
- dbus_error_free(&derr);
- goto done;
- }
-
- dbus_error_init(&derr);
- if (dbus_message_get_args(reply, &derr,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INT32, ¤t_location,
- DBUS_TYPE_INT32, &err,
- DBUS_TYPE_INVALID) == FALSE) {
- error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
- derr.name, derr.message);
- dbus_error_free(&derr);
- goto done;
- }
-
- if (err != 0) {
- error("SIM.Phonebook.read failed with error %d", err);
- if (number_type == &vmbx)
- vmbx = g_strdup(getenv("VMBX_NUMBER"));
- goto done;
- }
-
- if (number_type == &msisdn) {
- g_free(msisdn);
- msisdn = g_strdup(number);
- DBG("Got MSISDN %s (%s)", number, name);
- } else {
- g_free(vmbx);
- vmbx = g_strdup(number);
- DBG("Got voice mailbox number %s (%s)", number, name);
- }
-
-done:
- dbus_message_unref(reply);
-}
-
-static void csd_init(void)
-{
- dbus_uint32_t location;
- uint8_t pb_type, location_type;
- int ret;
-
- ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
- CSD_CALL_INTERFACE, "GetCallInfoAll",
- call_info_reply, NULL, DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to sent GetCallInfoAll method call");
- return;
- }
-
- get_calls_active = TRUE;
-
- pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
- phonebook_read_reply, &msisdn,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return;
- }
-
- pb_type = SIM_PHONEBOOK_TYPE_MBDN;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
- phonebook_read_reply, &vmbx,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
- DBUS_TYPE_INVALID);
- if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return;
- }
-}
-
-static uint32_t get_callflag(const char *callerid_setting)
-{
- if (callerid_setting != NULL) {
- if (g_str_equal(callerid_setting, "allowed"))
- return CALL_FLAG_PRESENTATION_ALLOWED;
- else if (g_str_equal(callerid_setting, "restricted"))
- return CALL_FLAG_PRESENTATION_RESTRICTED;
- else
- return CALL_FLAG_NONE;
- } else
- return CALL_FLAG_NONE;
-}
-
-static void generate_flag_file(const char *filename)
-{
- int fd;
-
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
- g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
- g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- return;
-
- fd = open(filename, O_WRONLY | O_CREAT, 0);
- if (fd >= 0)
- close(fd);
-}
-
-static void save_callerid_to_file(const char *callerid_setting)
-{
- char callerid_file[FILENAME_MAX];
-
- snprintf(callerid_file, sizeof(callerid_file), "%s%s",
- CALLERID_BASE, callerid_setting);
-
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(ALLOWED_FLAG_FILE, callerid_file);
- else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(RESTRICTED_FLAG_FILE, callerid_file);
- else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- rename(NONE_FLAG_FILE, callerid_file);
- else
- generate_flag_file(callerid_file);
-}
-
-static uint32_t callerid_from_file(void)
-{
- if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_PRESENTATION_ALLOWED;
- else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_PRESENTATION_RESTRICTED;
- else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
- return CALL_FLAG_NONE;
- else
- return CALL_FLAG_NONE;
-}
-
-static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *callerid_setting;
-
- if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
- &callerid_setting,
- DBUS_TYPE_INVALID) == FALSE)
- return btd_error_invalid_args(msg);
-
- if (g_str_equal(callerid_setting, "allowed") ||
- g_str_equal(callerid_setting, "restricted") ||
- g_str_equal(callerid_setting, "none")) {
- save_callerid_to_file(callerid_setting);
- callerid = get_callflag(callerid_setting);
- DBG("telephony-maemo setting callerid flag: %s",
- callerid_setting);
- return dbus_message_new_method_return(msg);
- }
-
- error("telephony-maemo: invalid argument %s for method call"
- " SetCallerId", callerid_setting);
- return btd_error_invalid_args(msg);
-}
-
-static const GDBusMethodTable telephony_maemo_methods[] = {
- { GDBUS_ASYNC_METHOD("SetCallerId",
- GDBUS_ARGS({ "id", "s" }), NULL,
- set_callerid) },
- { }
-};
-
-static void handle_modem_state(DBusMessage *msg)
-{
- const char *state;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
- DBUS_TYPE_INVALID)) {
- error("Unexpected modem state parameters");
- return;
- }
-
- DBG("SSC modem state: %s", state);
-
- if (calls != NULL || get_calls_active)
- return;
-
- if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
- csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("get_modem_status: %s, %s", err.name, err.message);
- dbus_error_free(&err);
- } else
- handle_modem_state(reply);
-
- dbus_message_unref(reply);
-}
-
-static DBusHandlerResult signal_filter(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *path = dbus_message_get_path(msg);
-
- if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
- handle_incoming_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
- handle_outgoing_call(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
- "CreateRequested"))
- handle_create_requested(msg);
- else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
- handle_call_status(msg, path);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
- handle_conference(msg, TRUE);
- else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
- handle_conference(msg, FALSE);
- else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
- "registration_status_change"))
- handle_registration_status_change(msg);
- else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
- "signal_strength_change"))
- handle_signal_strength_change(msg);
- else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
- "PropertyModified"))
- handle_hal_property_modified(msg);
- else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
- "modem_state_changed_ind"))
- handle_modem_state(msg);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-int telephony_init(void)
-{
- const char *battery_cap = "battery";
- uint32_t features = AG_FEATURE_EC_ANDOR_NR |
- AG_FEATURE_INBAND_RINGTONE |
- AG_FEATURE_REJECT_A_CALL |
- AG_FEATURE_ENHANCED_CALL_STATUS |
- AG_FEATURE_ENHANCED_CALL_CONTROL |
- AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
- AG_FEATURE_THREE_WAY_CALLING;
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
- if (!dbus_connection_add_filter(connection, signal_filter,
- NULL, NULL))
- error("Can't add signal filter");
-
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_INTERFACE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_INSTANCE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" NETWORK_INTERFACE, NULL);
- dbus_bus_add_match(connection,
- "type=signal,interface=" SSC_DBUS_IFACE
- ",member=modem_state_changed_ind", NULL);
-
- if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
- "get_modem_state", modem_state_reply,
- NULL, DBUS_TYPE_INVALID) < 0)
- error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
- generate_flag_file(NONE_FLAG_FILE);
- callerid = callerid_from_file();
-
- if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
- TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
- NULL, NULL, NULL, NULL)) {
- error("telephony-maemo interface %s init failed on path %s",
- TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
- }
-
- DBG("telephony-maemo registering %s interface on path %s",
- TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-
- telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
- chld_str);
- if (send_method_call("org.freedesktop.Hal",
- "/org/freedesktop/Hal/Manager",
- "org.freedesktop.Hal.Manager",
- "FindDeviceByCapability",
- hal_find_device_reply, NULL,
- DBUS_TYPE_STRING, &battery_cap,
- DBUS_TYPE_INVALID) < 0)
- error("Unable to send HAL method call");
-
- return 0;
-}
-
-void telephony_exit(void)
-{
- g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
- g_slist_free(calls);
- calls = NULL;
-
- dbus_connection_remove_filter(connection, signal_filter, NULL);
-
- dbus_connection_unref(connection);
- connection = NULL;
-
- telephony_deinit();
-}
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox